This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Write firmware to flash

Other Parts Discussed in Thread: OMAP-L138, OMAPL138

HI

I want to perform an upgrade to my DSP firmware through UART . I used EVM6424 and it's connected to MSp430 via UART . we decide  to send firmware from PC to MSP and then to DSP via UART. I want to learn more about how to write this firmware to flash ( parse the file and write each section to it's flash location ) . I already perform firmware burning using flashburn utility ( from software design solution ) and perform erase/write/read of array of data to flash.   

  • Hi Abdalla Ali,

    What i understood from your query is .
    PC ----UART----> MSP430----UART---->EVM6424.
    [query]
    we decide to send firmware from PC to MSP and then to DSP via UART
    [/query]
    How you are sending firmware from PC to MSP ? Are you using any flash utility for that also. ?
  • Hi abdalla,

    As far I know, for C6424, flashburn utility is the only solution which I came across to flash the images.

    For MSP430, check out whether this helps:
    www.ti.com/.../MSP430-FLASHER

    --
  • Arvind Singh.
    1)
    [ PC ----UART----> MSP430----UART---->EVM6424. ] Yes this is the actual setup
    2)
    [ we decide to send firmware from PC to MSP and then to DSP via UART ]
    Yes because it's the only interface that will be available to communicate
  • Hi Arvind Singh.
    we deside to update the firmware of the System via one interface (UART ) from PC The MSP430 will updated first and then the DSP

    Regards
    Abdalla
  • Hi Shankari.
    for the first program yes but we want to do the job of the flashburn utility when we apply the update of the firmware ; because the only interface that we can use to update the firmware of the DSP is the UART which is connected to the MSP430
    here is my scenario ( please correct me and add your recommendations )
    1) Image will send via UART to the DSP and a specific module will store the chunks until the full image received by DSP
    2) Hex file will be in motorola format(S011000075626C446156696E63692E6865789A
    S3254200000001000000544950410D595358000003001500000000000000000000000D5953582F
    S32542000020010005 ....etc) and then we need to parse the contains of the received file and write each data in it's memory flash address.
    3) Before we write data we need to check the integrity of the received image
    4 ) perform the erase /write to flash

    Regards
    Abdalla.
  • I found flash drivers for NAND/NOR in OMAP-L138 flash and Boot utility  and it's generic (attached ) . I can use it directly , i think it's more comprehensive than the spectrum digital drivers for NAND/NOR ( attached)

    /*
     * nand.c
    */
    
    /*
     * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 
    */
    /* 
     *  Redistribution and use in source and binary forms, with or without 
     *  modification, are permitted provided that the following conditions 
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright 
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the 
     *    documentation and/or other materials provided with the   
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    /* --------------------------------------------------------------------------
      FILE      : nand.c                                                   
      PROJECT   : TI Booting and Flashing Utilities
      AUTHOR    : Daniel Allred
      DESC      : Generic NAND driver file for EMIFA peripheral
    -------------------------------------------------------------------------- */
    
    
    /************************************************************
    * Include Files                                             *
    ************************************************************/
    
    // General type include
    #include "tistdtypes.h"
    
    // Device specific CSL
    #include "device.h"
    
    #ifndef USE_IN_ROM
      // Util functions
      #include "util.h"
    
      // Debug functions for non-ROMed version
      #include "debug.h"
    #endif
    
    // This module's header file 
    #include "nand.h"
    
    // Device NAND specific stuff
    #include "device_nand.h"
    
    
    /************************************************************
    * Explicit External Declarations                            *
    ************************************************************/
    
    // The device specific table of supported NAND devices
    extern NAND_CHIP_InfoObj    DEVICE_NAND_CHIP_infoTable[];
    
    // The device specific ECC info struct
    extern NAND_ECC_InfoObj     DEVICE_NAND_ECC_info;
    
    // The device specific BB info struct
    extern NAND_BB_InfoObj      DEVICE_NAND_BB_info;
    
    // The device specific PAGE layout structure
    extern NAND_PAGE_LayoutObj  DEVICE_NAND_PAGE_layout;
    
    
    /************************************************************
    * Local Macro Declarations                                  *
    ************************************************************/
    
    
    /************************************************************
    * Local Function Declarations                               *
    ************************************************************/
    
    // Low-level NAND functions read, write, and command functions
    static VUint8 *LOCAL_flashMakeAddr (Uint32 baseAddr, Uint32 offset);
    static void LOCAL_flashWriteData(NAND_InfoHandle hNandInfo, Uint32 offset, Uint32 data);
    static Uint32 LOCAL_flashReadData(NAND_InfoHandle hNandInfo);
    
    // Address byte write functions
    static void LOCAL_flashWriteColAddrBytes(NAND_InfoHandle hNandInfo, Uint32 offset);
    static void LOCAL_flashWriteRowAddrBytes(NAND_InfoHandle hNandInfo, Uint32 page);
    
    
    #ifndef USE_IN_ROM
    // Array data writing functions
    static void LOCAL_flashWriteBytes (NAND_InfoHandle hNandInfo, void *pSrc, Uint32 numBytes);
    
    // Function to erase a block
    static Uint32 LOCAL_eraseBlock(NAND_InfoHandle hNandInfo, Uint32 block, Bool force);
    #endif
    
    // Array data reading functions
    static void LOCAL_flashReadBytes(NAND_InfoHandle hNandInfo, void *pDest, Uint32 numBytes);
    
    // Wait for ready signal seen at NANDFSCR
    static Uint32 LOCAL_flashWaitForRdy(NAND_InfoHandle hNandInfo, Uint32 timeout);
    
    // Wait for status result from device to read good
    static Uint32 LOCAL_flashWaitForStatus(NAND_InfoHandle hNandInfo, Uint32 timeout);
    
    // page Pointer set function
    static Uint32 LOCAL_setPagePtr(NAND_InfoHandle hNandInfo,NAND_RegionType regtionType, Uint32 opNum);
    
    // Get Chip details
    static Uint32 LOCAL_flashGetDetails(NAND_InfoHandle hNandInfo);
    
    // ONFI CRC check for Read Parameter Page command
    static Bool LOCAL_onfiParamPageCRCCheck(Uint8 *paramPageData);
    
    
    /************************************************************
    * Local Variable Definitions                                *
    ************************************************************/
    
    
    /************************************************************
    * Global Variable Definitions                               *
    ************************************************************/
    
    #ifdef USE_IN_ROM
    #pragma DATA_SECTION(gNandInfo,".NANDInfoStruct")
    NAND_InfoObj gNandInfo;
    #endif
    
    
    /************************************************************
    * Global Function Definitions                               *
    ************************************************************/
    
    // Initialze NAND interface and find the details of the NAND used
    NAND_InfoHandle NAND_open(Uint32 baseCSAddr,  Uint8 busWidth)
    {
      NAND_InfoHandle hNandInfo;
      
      // Set NandInfo handle
    #ifdef USE_IN_ROM
      hNandInfo = (NAND_InfoHandle) &gNandInfo;
    #else
      hNandInfo = (NAND_InfoHandle) UTIL_allocMem(sizeof(NAND_InfoObj));
    #endif
    
      // Open Async Memory peripheral
      hNandInfo->hAsyncMemInfo = ASYNC_MEM_Open
      (
        AYSNC_MEM_TYPE_NAND,
        baseCSAddr,
        busWidth
      );
      
      // Set NAND flash base address
      hNandInfo->flashBase = baseCSAddr;
      
      // Init the current block number and good flag
      hNandInfo->currBlock = -1;     
      hNandInfo->isBlockGood = FALSE;  
      
      // Use device specific page layout and ECC layout
      hNandInfo->hPageLayout  = &DEVICE_NAND_PAGE_layout;
      hNandInfo->hEccInfo     = &DEVICE_NAND_ECC_info;
      hNandInfo->hBbInfo      = &DEVICE_NAND_BB_info;
      hNandInfo->hChipInfo    = DEVICE_NAND_CHIP_infoTable;
        
      // Get the CSOffset ( can be 0 through (DEVICE_EMIF_NUMBER_CE_REGION -1) )
    #if (0)
      hNandInfo->CSOffset = 0
      while (hNandInfo->CSOffset < DEVICE_EMIF_NUMBER_CE_REGION)
      {
        if ( (hNandInfo->flashBase >= (DEVICE_EMIF_FIRST_CE_START_ADDR + (DEVICE_EMIF_INTER_CE_REGION_SIZE * (hNandInfo->CSOffset+0)))) &&
             (hNandInfo->flashBase <  (DEVICE_EMIF_FIRST_CE_START_ADDR + (DEVICE_EMIF_INTER_CE_REGION_SIZE * (hNandInfo->CSOffset+1)))) 
           )
        {
          break;
        }
        hNandInfo->CSOffset++;
      }
    
      if (hNandInfo->CSOffset == DEVICE_EMIF_NUMBER_CE_REGION)
      {
        return NULL;
      }
    #else
      hNandInfo->CSOffset = hNandInfo->hAsyncMemInfo->chipSelectNum;
    #endif
        
      // Set EMIF bus width
    #if (0)  
      hNandInfo->busWidth = busWidth;
    #else
      hNandInfo->busWidth = hNandInfo->hAsyncMemInfo->busWidth;
    #endif  
      
    #if (0)  
      // Setup  registers for NAND  
      AEMIF->NANDFCR |= (0x1 << (hNandInfo->CSOffset));        // NAND enable for CSx
      (*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
    #endif                           
      // Send reset command to NAND
      if ( NAND_reset(hNandInfo) != E_PASS )
        return NULL;
     
      // Get and set device details
    
      if ( LOCAL_flashGetDetails(hNandInfo) != E_PASS )
        return NULL;
     
      // Send reset command to NAND
      if ( NAND_reset(hNandInfo) != E_PASS )
        return NULL;
      
      return hNandInfo;
    }
    
    
    // Routine to check a particular block to see if it is good or bad
    Uint32 NAND_badBlockCheck(NAND_InfoHandle hNandInfo, Uint32 block)
    {
      Uint8 spareBytes[256];
    
      if (!hNandInfo->hBbInfo->BBCheckEnable)
      {
        return E_PASS;
      }
      else if (hNandInfo->currBlock != block)
      {
        hNandInfo->currBlock = block;
    
        // Read and check spare bytes of first page of block (ONFI and normal)
        NAND_readSpareBytesOfPage(hNandInfo, block, 0, spareBytes);
        
        if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
        {
          hNandInfo->isBlockGood = FALSE;
          return E_FAIL;
        }
    
        // Read and check spare bytes of second page of block (normal)
        NAND_readSpareBytesOfPage(hNandInfo, block, 1, spareBytes);
        if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
        {
          hNandInfo->isBlockGood = FALSE;
          return E_FAIL;
        }
    
        if (hNandInfo->isONFI)
        {
          // Read and check spare bytes of last page of block (for ONFI)
          NAND_readSpareBytesOfPage(hNandInfo, block, (hNandInfo->pagesPerBlock - 1), spareBytes);
          if ((*hNandInfo->hBbInfo->fxnBBCheck)(hNandInfo,spareBytes) != E_PASS)
          {
            hNandInfo->isBlockGood = FALSE;
            return E_FAIL;
          }
        }
    
        hNandInfo->isBlockGood = TRUE;
        return E_PASS;
      }
      else if (hNandInfo->isBlockGood == FALSE)
      {
        return E_FAIL;
      }
      else
      {
        return E_PASS;
      }  
    }
    
    
    // Routine to reset the NAND device
    Uint32 NAND_reset(NAND_InfoHandle hNandInfo)
    {
      // Send reset command to NAND
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_RESET );
      
      // FIXME: On slow devices we may miss the busy pulse, the timeout may be take a long time
      return LOCAL_flashWaitForRdy(hNandInfo, 512);
    }
    
    
    // Routine to read a page from NAND
    Uint32 NAND_readPage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *dest)
    {
      Uint32 i, currPagePtr, nextPagePtr;
      //FIXME: the size of this array should be determined by the calcECCByteCnt
      Uint8 readECC[16];
    
      // This is enough to support 8 Kbyte page devices
      Uint8 spareBytes[256];
    
      // Get spare bytes of page (includes all stored ECC data)
      NAND_readSpareBytesOfPage(hNandInfo,block,page,spareBytes);
      
      // Write read command
      LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_READ_PAGE);
    
      // Jump to first data region
      currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,0);
      LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
    
      // Additional confirm command for large page devices
      if(hNandInfo->isLargePage)
      {
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_READ_30H);
      }
    
      // Wait for data to be available
      if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Clear the ECC hardware before starting
      (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
     
      // Read data bytes with ECC enabled
      for (i=0; i < hNandInfo->numOpsPerPage; i++)
      {
        (*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
        LOCAL_flashReadBytes(hNandInfo, &dest[hNandInfo->dataBytesPerOp*i], hNandInfo->dataBytesPerOp);
        (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
        // Use ECC bytes to correct any errors
        (*hNandInfo->hEccInfo->fxnRead)(hNandInfo, spareBytes, i, readECC);
        if ((*hNandInfo->hEccInfo->fxnCorrect)(hNandInfo,&dest[hNandInfo->dataBytesPerOp*i],readECC) != E_PASS)
        {
          return E_FAIL;
        }
        
        // Go to next data region of page
        currPagePtr += hNandInfo->dataBytesPerOp;
        
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
            
            // Jump to next data section of page (random read command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_READ_PAGE);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_READ_E0H);
          }
        }
      }
    
      // Return status check result
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    
    // Function to just read the sparebytes region of a page
    Uint32 NAND_readSpareBytesOfPage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *dest)
    {
      Uint32 i, currPagePtr, nextPagePtr;
    
      // The large page device MUST support Random Read Command (0x05)
      if(hNandInfo->isLargePage)
      {
        // Write read command
        LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_READ_PAGE);
        
        // Jump to first spare bytes region
        currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,0);
        LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
        LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
        
        // Additional confirm command for large page devices
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_READ_30H);
    
        // Wait for data to be available
        if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
          return E_FAIL;    
        
        // Collect spare bytes regions from the page into end of pageBuffer
        for (i=0; i < hNandInfo->numOpsPerPage; i++)
        {
          // Read spare bytes
          LOCAL_flashReadBytes(hNandInfo, &dest[hNandInfo->spareBytesPerOp*i], hNandInfo->spareBytesPerOp);
          currPagePtr += hNandInfo->spareBytesPerOp;
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,i+1);
          if ( (i != (hNandInfo->numOpsPerPage-1)) && ( currPagePtr != nextPagePtr) )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
            
            // Jump back to start of page (random read command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_READ_PAGE);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_READ_E0H);
          }
        }
      }
      else
      {
        // Go to start of spare bytes region
        LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_EXTRA_PAGE);
        LOCAL_flashWriteColAddrBytes(hNandInfo, 0x0);
        LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);  
      
        // Wait for data to be available
        if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
          return E_FAIL;
          
        // Read spare bytes (includes ECC data) 
        LOCAL_flashReadBytes(hNandInfo, dest, hNandInfo->spareBytesPerOp);
      }
    
      // Return status check result
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    
    // Defining this macro for the build will cause write (flash) ability to be removed
    // This can be used for using this driver as read-only for ROM code
    #ifndef USE_IN_ROM
    
    // Check to see if device is write protected
    Bool   NAND_isWriteProtected(NAND_InfoHandle hNandInfo)
    {
      Uint32 status;
      
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET,NAND_STATUS);
      status = LOCAL_flashReadData(hNandInfo);
      
      return (status&NAND_STATUS_PROTECTED)?FALSE:TRUE;
    }
    
    // Function to mark a bad block
    Uint32 NAND_badBlockMark(NAND_InfoHandle hNandInfo, Uint32 block)
    {
      Uint8 spareBytes[256];
    
      // Check if marking enabled
      if (!hNandInfo->hBbInfo->BBMarkEnable)
      {
        return E_PASS;
      }
      
      // Check to see if this block is already known as bad
      if ((hNandInfo->currBlock == block) && (hNandInfo->isBlockGood == FALSE))
      {
        return E_PASS;
      }
    
      // Indicate that this block is bad
      hNandInfo->currBlock = block;
      hNandInfo->isBlockGood = FALSE;
    
      // Mark the spare bytes according to device specific function
      (*hNandInfo->hBbInfo->fxnBBMark)(hNandInfo,spareBytes);
    
      // Erase the block so that we can mark the pages
      if (LOCAL_eraseBlock(hNandInfo, block, TRUE) != E_PASS)
      {
        return E_FAIL;
      }
    
      // Write the marked spare bytes to the first page (ONFI and normal)
      if (NAND_writeOnlySpareBytesOfPage(hNandInfo,block,0,spareBytes) != E_PASS)
      {
        // Marking the first page didn't succeed, try a second
        if (hNandInfo->isONFI)
        {
          // Write the marked spare bytes to the last page (ONFI)
          return NAND_writeOnlySpareBytesOfPage(hNandInfo,block,(hNandInfo->pagesPerBlock - 1),spareBytes);
        }
        else
        {
          // Write the marked spare bytes to the second page (normal)
          return NAND_writeOnlySpareBytesOfPage(hNandInfo,block,1,spareBytes);
        }
      }
    
      return E_PASS;
    }
    
    
    // Function to write only the spare bytes region (page must be
    // erased and not written to prior to calling this)
    Uint32 NAND_writeOnlySpareBytesOfPage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8* spareBytes)
    {
      Uint32 i,currPagePtr, nextPagePtr;
    
      // For small page devices, set pointer
      if (!hNandInfo->isLargePage)
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_EXTRA_PAGE);
      
      // Write program command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_START);
    
      // Write address bytes
      currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,0);
      if (!hNandInfo->isLargePage)
        LOCAL_flashWriteColAddrBytes(hNandInfo, 0);
      else
        LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
    
      
      // Write spare bytes sections of page
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
    
        LOCAL_flashWriteBytes(hNandInfo, &spareBytes[hNandInfo->spareBytesPerOp*i], hNandInfo->spareBytesPerOp);
        
        currPagePtr += hNandInfo->spareBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next data section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write program end command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_END);
    
      // Wait for the device to be ready
      if (LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Return status check result  
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    
    // Generic routine to write a page of data to NAND
    Uint32 NAND_writePage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *src)
    {
      Uint32 i,currPagePtr, nextPagePtr;
      //FIXME: the size of this array should be determined by the calcECCByteCnt  
      Uint8 calcECC[16];
    
      // This is enough to support 8 Kbyte page devices
      Uint8 spareBytes[256];
    
      // Fill in the spare bytes region with 0xFF
      for (i=0; i<hNandInfo->spareBytesPerPage; i++)
      {
        spareBytes[i] = 0xFF;
      }
    
      // For small page devices, set pointer
      if (!hNandInfo->isLargePage)
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_LO_PAGE);
      
      // Write program command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_START);
    
      // Write address bytes
      currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,0);
      LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
    
      // Clear the ECC hardware before starting
      (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
      // Write data sections of page, getting ECC data
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
        (*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
        LOCAL_flashWriteBytes(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], hNandInfo->dataBytesPerOp);
        (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
        (*hNandInfo->hEccInfo->fxnCalculate)(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], calcECC);
        
        (*hNandInfo->hEccInfo->fxnStore)(hNandInfo, spareBytes, i, calcECC);
        
        currPagePtr += hNandInfo->dataBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next data section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
        else
        {
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,0);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to first spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write spare bytes sections of page
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
    
        LOCAL_flashWriteBytes(hNandInfo, &spareBytes[hNandInfo->spareBytesPerOp*i], hNandInfo->spareBytesPerOp);
        
        currPagePtr += hNandInfo->spareBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write program end command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_END);
    
      // Wait for the device to be ready
      if (LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Return status check result  
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    
    #ifdef DM35X_STANDARD
    // Generic routine to write a page of data to NAND
    //Note:  This is identical to the NAND_writePage routine except for some special
    //       handling required for the UBL header.  For the UBL header, the spare bytes
    //       region for the first 512 sector of the page has to be duplicated in two places.
    //       a)  In the normal spare bytes region
    //       b)  At an offset of 512 bytes from the start of the page.  This is necessary to be
    //           compatible with revision 1.1. silicon compatibility mode.
    
    Uint32 NAND_writePage_ubl_header(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *src)
    {
      Uint32 i,j,currPagePtr, nextPagePtr;
      //FIXME: the size of this array should be determined by the calcECCByteCnt  
      Uint8 calcECC[16];
    
      // This is enough to support 8 Kbyte page devices
      Uint8 spareBytes[256];
    
      // Fill in the spare bytes region with 0xFF
      for (i=0; i<hNandInfo->spareBytesPerPage; i++)
      {
        spareBytes[i] = 0xFF;
      }
    
      // For small page devices, set pointer
      if (!hNandInfo->isLargePage)
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_LO_PAGE);
      
      // Write program command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_START);
    
      // Write address bytes
      currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,0);
      LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
    
      // Clear the ECC hardware before starting
      (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
      // Write data sections of page, getting ECC data
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
        (*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
        LOCAL_flashWriteBytes(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], hNandInfo->dataBytesPerOp);
        (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
        (*hNandInfo->hEccInfo->fxnCalculate)(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], calcECC);
        
        (*hNandInfo->hEccInfo->fxnStore)(hNandInfo, spareBytes, i, calcECC);
        
        currPagePtr += hNandInfo->dataBytesPerOp;
    
    	//If we are doing the 1st 512 byte section, then copy the spare bytes information
    	//into the first part of the 2nd 512 byte section.  This is legal because we KNOW that
    	//this is a blank area for a header page.
    	if (i == 0)
    	{
    	  for (j=0; j<16; j++) 
    	  {
    	     src[(hNandInfo->dataBytesPerOp)+j] = spareBytes[j];
    	  }
    	}
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next data section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
        else
        {
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,0);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to first spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write spare bytes sections of page
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
    
        LOCAL_flashWriteBytes(hNandInfo, &spareBytes[hNandInfo->spareBytesPerOp*i], hNandInfo->spareBytesPerOp);
        
        currPagePtr += hNandInfo->spareBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write program end command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_END);
    
      // Wait for the device to be ready
      if (LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Return status check result  
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    #endif
    
    // Test routine to write a page of data to NAND without writing sparebytes or ECC data
    #if defined(NAND_ECC_TEST)
    Uint32 NAND_writePageWithSpareBytes(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8 *src, Uint8* spareBytes)
    {
      Uint32 i,currPagePtr, nextPagePtr;
      //FIXME: the size of this array should be determined by the calcECCByteCnt  
      Uint8 calcECC[16];
    
      // For small page devices, set pointer
      if (!hNandInfo->isLargePage)
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_LO_PAGE);
      
      // Write program command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_START);
    
      // Write address bytes
      currPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,0);
      LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, (block*hNandInfo->pagesPerBlock) + page);
    
      (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
      // Write data sections of page, getting ECC data
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
        (*hNandInfo->hEccInfo->fxnEnable)(hNandInfo);
        LOCAL_flashWriteBytes(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], hNandInfo->dataBytesPerOp);
        (*hNandInfo->hEccInfo->fxnDisable)(hNandInfo);
    
        (*hNandInfo->hEccInfo->fxnCalculate)(hNandInfo, &src[hNandInfo->dataBytesPerOp*i], calcECC);
        
        currPagePtr += hNandInfo->dataBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_DATA,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next data section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
        else
        {
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,0);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to first spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write spare bytes sections of page
      for (i=0; i<hNandInfo->numOpsPerPage; i++)
      {
        LOCAL_flashWriteBytes(hNandInfo, &spareBytes[hNandInfo->spareBytesPerOp*i], hNandInfo->spareBytesPerOp);
        
        currPagePtr += hNandInfo->spareBytesPerOp;
    
        if (i != (hNandInfo->numOpsPerPage-1))
        {  
          nextPagePtr = LOCAL_setPagePtr(hNandInfo,NAND_REGION_SPARE,i+1);
          if ( currPagePtr != nextPagePtr )
          { 
            // Adjust page pointer      
            currPagePtr = nextPagePtr;
          
            // Jump to next spare section of page (random program command)
            LOCAL_flashWriteData(hNandInfo,DEVICE_NAND_CLE_OFFSET,NAND_RANDOM_PGRM);
            LOCAL_flashWriteColAddrBytes(hNandInfo, currPagePtr);
          }
        }
      }
    
      // Write program end command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_PGRM_END);
    
      // Wait for the device to be ready
      if (LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Return status check result  
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    }
    #endif
    
    // Verify data written by reading and comparing byte for byte
    Uint32 NAND_verifyPage(NAND_InfoHandle hNandInfo, Uint32 block, Uint32 page, Uint8* src, Uint8* dest)
    {
      Uint32 i, errCnt;
    
      if (NAND_readPage(hNandInfo, block, page, dest) != E_PASS)
        return E_FAIL;
      
      errCnt = 0;
      for (i=0; i <(hNandInfo->dataBytesPerPage); i++)
      {
        // Check for data read errors
        if ( src[i] != dest[i] )
        {
          errCnt++;
    #if (0)      
          DEBUG_printString("Data verification failed! Byte # ");
          DEBUG_printHexInt(i);
          DEBUG_printString(" Expected Data: ");
          DEBUG_printHexInt( src[i]);
          DEBUG_printString(", Received Byte: ");
          DEBUG_printHexInt( dest[i]);
          DEBUG_printString("\r\n");
    #endif      
        }
      }
      
      if (errCnt != 0)
      {
        return E_FAIL;
      }
      else
      {
        return E_PASS;
      }
    }
    
    // Verify erase succeeded by reading and comparing byte for byte
    Uint32 NAND_verifyBlockErased(NAND_InfoHandle hNandInfo, Uint32 block, Uint8* dest)
    {
      Uint32 i,j;
      
      for (j=0; j<hNandInfo->pagesPerBlock; j++)
      {
        if (NAND_readPage(hNandInfo, block, j, dest) != E_PASS)
          return E_FAIL;
        
        for (i=0; i<(hNandInfo->dataBytesPerPage>>2); i++)
        {
          // Check for data read errors
          if (((Uint32 *)dest)[i] += 0xFFFFFFFF)
          {
    #if (0)      
            DEBUG_printString("Erase verification failed! Block: ");
            DEBUG_printHexInt(block);
            DEBUG_printString(" page: ");
            DEBUG_printHexInt(j);
            DEBUG_printString(". First Failing Byte: ");
            DEBUG_printHexInt(i);
            DEBUG_printString("\r\n");
    #endif        
            return E_FAIL;
          }
        }
      }
      return E_PASS;
    }
    
    // Global Erase NAND Flash
    Uint32 NAND_globalErase(NAND_InfoHandle hNandInfo)
    {
      // We don't erase block 0, and possibly some ending blocks reserved for BBT
    //  return NAND_eraseBlocks( hNandInfo, 0, (hNandInfo->numBlocks - 1 - NAND_NUM_BLOCKS_RESERVED_FOR_BBT) );
        return NAND_eraseBlocks_with_bb_check( hNandInfo, 0, (hNandInfo->numBlocks - 1 - NAND_NUM_BLOCKS_RESERVED_FOR_BBT) );
    //    return NAND_eraseBlocks( hNandInfo, 0, 9);
    }
    
    // GLobal Erase NAND flash with Bad Block checking and marking
    Uint32 NAND_globalErase_with_bb_check(NAND_InfoHandle hNandInfo)
    {
      // We don't erase block 0, and possibly some ending blocks reserved for BBT
      return NAND_eraseBlocks_with_bb_check( hNandInfo, 1, (hNandInfo->numBlocks - 1) );
    }
    
    // NAND Flash erase block function
    Uint32 NAND_eraseBlocks(NAND_InfoHandle hNandInfo, Uint32 startBlkNum, Uint32 blkCnt)
    {  
      Uint32 i;
      Uint32 endBlkNum = startBlkNum + blkCnt - 1;
    
      // Do bounds checking
      if ( endBlkNum >= hNandInfo->numBlocks )
        return E_FAIL;
      
      // Output info about what we are doing
    #if(0)  
      DEBUG_printString("Erasing block ");
      DEBUG_printHexInt(startBlkNum);
      DEBUG_printString(" through ");
      DEBUG_printHexInt(endBlkNum);
      DEBUG_printString(".\r\n");
    #endif
    
      for (i = startBlkNum; i <= endBlkNum; i++)
      {
        if (LOCAL_eraseBlock(hNandInfo,i,FALSE) != E_PASS)
    //	      return E_FAIL;
    		;
      }
      
      return E_PASS;
    }
    
    Uint32 NAND_eraseBlocks_with_bb_check(NAND_InfoHandle hNandInfo, Uint32 startBlkNum, Uint32 blkCnt)
    {  
      Uint32 i;
      Uint32 endBlkNum = startBlkNum + blkCnt - 1;
    
      // Do bounds checking
      if ( endBlkNum >= hNandInfo->numBlocks )
        return E_FAIL;
      
      // Output info about what we are doing
    #if(0)  
      DEBUG_printString("Erasing block ");
      DEBUG_printHexInt(startBlkNum);
      DEBUG_printString(" through ");
      DEBUG_printHexInt(endBlkNum);
      DEBUG_printString(".\r\n");
    #endif
    
      for (i = startBlkNum; i <= endBlkNum; i++)
      {
        if (LOCAL_eraseBlock(hNandInfo,i,FALSE) != E_PASS)
        {
    #if (1)    
          DEBUG_printString(" Bad block at block ");
          DEBUG_printHexInt(i);
          DEBUG_printString(". Erasing is skipped\n");
          NAND_badBlockMark(hNandInfo, i);
    #endif      
        }	
      }
     
      return E_PASS;
    }
    
    // NAND Flash unprotect command
    Uint32 NAND_unProtectBlocks(NAND_InfoHandle hNandInfo, Uint32 startBlkNum, Uint32 blkCnt)
    {
      Uint32 endBlkNum = startBlkNum + blkCnt - 1;
    
      // Do bounds checking
    //  if (endBlkNum >= hNandInfo->numBlocks)
    //    return E_FAIL;
    
      // Output info about what we are doing
    #if (0)  
      DEBUG_printString("Unprotecting blocks ");
      DEBUG_printHexInt(startBlkNum);
      DEBUG_printString(" through ");
      DEBUG_printHexInt(endBlkNum);
      DEBUG_printString(".\r\n");
    #endif  
    
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_UNLOCK_START);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, hNandInfo->pagesPerBlock * startBlkNum);
      
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_UNLOCK_END);
      LOCAL_flashWriteRowAddrBytes(hNandInfo, hNandInfo->pagesPerBlock * endBlkNum);
        
      return E_PASS;
    }
    
    // NAND Flash protect command
    void NAND_protectBlocks(NAND_InfoHandle hNandInfo)
    {
    #if (0)
      DEBUG_printString("Protecting the entire NAND flash.\n");
    #endif  
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_LOCK);
    }
    
    #endif // END of !defined(USE_IN_ROM) section
    
    
    /************************************************************
    * Local Function Definitions                                *
    ************************************************************/
    
    // Generic Low-level NAND access functions
    static VUint8 *LOCAL_flashMakeAddr (Uint32 baseAddr, Uint32 offset)
    {
      return ((VUint8 *) ( baseAddr + offset ));
    }
    
    static void LOCAL_flashWriteData(NAND_InfoHandle hNandInfo, Uint32 offset, Uint32 data)
    {
      volatile NAND_Ptr addr;
      NAND_Data dataword;
      dataword.l = data;
    
      addr.cp = LOCAL_flashMakeAddr (hNandInfo->flashBase, offset);
      switch (hNandInfo->busWidth)
      {
        case BUS_8BIT:
          *addr.cp = dataword.c;
          break;
        case BUS_16BIT:
          *addr.wp = dataword.w;
          break;
      }
    }
    
    static Uint32 LOCAL_flashReadData (NAND_InfoHandle hNandInfo)
    {
      volatile NAND_Ptr addr;
      NAND_Data cmdword;
      cmdword.l = 0x0;
    
      addr.cp = LOCAL_flashMakeAddr (hNandInfo->flashBase, NAND_DATA_OFFSET );
      switch (hNandInfo->busWidth)
      {
        case BUS_8BIT:
         cmdword.c = *addr.cp;
         break;
        case BUS_16BIT:
         cmdword.w = *addr.wp;
         break;
      }
      return cmdword.l;
    }
    
    static void LOCAL_flashWriteRowAddrBytes(NAND_InfoHandle hNandInfo, Uint32 page)
    {
      Uint32 i;
      for (i=0; i<hNandInfo->numRowAddrBytes; i++)
      {
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_ALE_OFFSET, ( (page >> (8*i) ) & 0xff) );
      }
    }
    
    static void LOCAL_flashWriteColAddrBytes(NAND_InfoHandle hNandInfo, Uint32 offset)
    {
      Uint32 i;
    
      // Adjust column address for 16-bit buswidth since we address words instead of bytes
      if (hNandInfo->busWidth == (Uint8) DEVICE_BUSWIDTH_16BIT)
        offset >>= 1;
    
      for (i=0; i<hNandInfo->numColAddrBytes; i++)
      {
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_ALE_OFFSET, ( (offset >> (8*i) ) & 0xff) );
      }
    }
    
    #ifndef USE_IN_ROM
    static void LOCAL_flashWriteBytes(NAND_InfoHandle hNandInfo, void* pSrc, Uint32 numBytes)
    {
      volatile NAND_Ptr destAddr, srcAddr;
      Uint32 i;
      
      srcAddr.cp = (VUint8*) pSrc;
      destAddr.cp = LOCAL_flashMakeAddr (hNandInfo->flashBase, NAND_DATA_OFFSET );
      switch (hNandInfo->busWidth)
      {
        case BUS_8BIT:
          for(i=0;i<( numBytes );i++)
            *destAddr.cp = *srcAddr.cp++;
          break;
        case BUS_16BIT:
          for(i=0;i<( numBytes >> 1);i++)
            *destAddr.wp = *srcAddr.wp++;
          break;
        }
    }
    
    static Uint32 LOCAL_eraseBlock(NAND_InfoHandle hNandInfo, Uint32 block, Bool force)
    {
      
      // Start erase command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_BERASEC1);
    
      // Write the row addr bytes only
      LOCAL_flashWriteRowAddrBytes(hNandInfo, hNandInfo->pagesPerBlock * block );
      
      // Confirm erase command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_BERASEC2);
    
      // Wait for the device to be ready
      if (LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Verify the op succeeded by reading status from flash
      return LOCAL_flashWaitForStatus(hNandInfo, NAND_TIMEOUT);
    } 
    #endif
    
    static void LOCAL_flashReadBytes(NAND_InfoHandle hNandInfo, void* pDest, Uint32 numBytes)
    {
      volatile NAND_Ptr destAddr, srcAddr;
      Uint32 i;
      
      destAddr.cp = (VUint8*) pDest;
      srcAddr.cp = LOCAL_flashMakeAddr (hNandInfo->flashBase, NAND_DATA_OFFSET );
      switch (hNandInfo->busWidth)
      {
        case BUS_8BIT:
            for(i=0;i<( numBytes );i++)
              *destAddr.cp++ = *srcAddr.cp;
            break;
        case BUS_16BIT:
            for(i=0;i<( numBytes >> 1);i++)
              *destAddr.wp++ = *srcAddr.wp;
            break;
        }
    }
    
    // Poll bit of NANDFSR to indicate ready
    static Uint32 LOCAL_flashWaitForRdy(NAND_InfoHandle hNandInfo, Uint32 timeout)
    {
      VUint32 cnt;
      Uint32 status;
      Bool status_reached_zero = FALSE;
    
      cnt = timeout;
    
      // Wait for the status to show busy, and then after that
      // point we start checking for it to be high.  If we
      // don't do this we might see the status as ready before
      // it has even transitioned to show itself as busy.
      do 
      {  
        //status = (AEMIF->NANDFSR & NAND_NANDFSR_READY);
        status = (*(hNandInfo->hAsyncMemInfo->hDeviceInfo->fxnNandIsReadyPin))(hNandInfo->hAsyncMemInfo);
        if (status == 0)
          status_reached_zero = TRUE;
      }
      while(((cnt--)>0) && (!status || (status_reached_zero == FALSE)));
    
      return E_PASS;
    }
    
    
    // Wait for the status to be ready in NAND register
    //      There were some problems reported in DM320 with Ready/Busy pin
    //      not working with all NANDs. So this check has also been added.
    static Uint32 LOCAL_flashWaitForStatus(NAND_InfoHandle hNandInfo, Uint32 timeout)
    {
      VUint32 cnt;
      Uint32 status;
      cnt = timeout;
    
      do
      {
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET,NAND_STATUS);
        status = LOCAL_flashReadData(hNandInfo);
        cnt--;
      }
      while((cnt>0) && !(status & NAND_STATUS_READY));
    
      if( (cnt == 0) || (status & NAND_STATUS_ERROR) )
      {
        return E_FAIL;
      }
    
      return E_PASS;
    }
    
    
    // Function to set page pointer to appropriate location
    static Uint32 LOCAL_setPagePtr(NAND_InfoHandle hNandInfo, NAND_RegionType regionType, Uint32 opNum)
    {
      Uint32 currPtr = 0;
      NAND_RegionHandle hRegion;
      hRegion = (regionType == NAND_REGION_DATA)? &(hNandInfo->hPageLayout->dataRegion): &(hNandInfo->hPageLayout->spareRegion);
      
      currPtr = (hRegion->offsetType == NAND_OFFSETS_RELTODATA)? 0 : hNandInfo->dataBytesPerPage;
      currPtr += hRegion->offsets[opNum];
      
      return currPtr;
    }
    
    
    // Get details of the NAND flash used from the id and the table of NAND devices
    static Uint32 LOCAL_flashGetDetails(NAND_InfoHandle hNandInfo)
    {
      Uint8 devID[4];
      Uint32 i,j;
      
      // Check if ONFI compatible device
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_RDID);
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_ALE_OFFSET, NAND_ONFIRDIDADD);
    
      // FIXME: Do we need this? Wait for data to be available
      if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
        
      // Read ID bytes (to check for ONFI signature)
      for (i=0; i<4; i++)
        devID[i] = LOCAL_flashReadData(hNandInfo) & 0xFF;
    
      // Set ONFI flag as appropriate  
      if ( *((Uint32 *)devID) == NANDONFI_STRING)
        hNandInfo->isONFI = TRUE;
      else
        hNandInfo->isONFI = FALSE;
        
      // Send reset command to NAND
      if ( NAND_reset(hNandInfo) != E_PASS )
        return E_FAIL;
        
      // Issue device read ID command
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NAND_RDID);
      LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_ALE_OFFSET, NAND_RDIDADD);
      
      // FIXME: Do we need this? Wait for data to be available
      if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
        return E_FAIL;
    
      // Read ID bytes (to get true device ID data)
      for (i=0; i<4; i++)
        devID[i] = LOCAL_flashReadData(hNandInfo) & 0xFF;
    
      if (hNandInfo->isONFI)
      {
        Uint8 paramPageData[256];
        
        // Issue read param page command
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_CLE_OFFSET, NANDONFI_RDPARAMPAGE);
        
        // Issue lo-page address
        LOCAL_flashWriteData(hNandInfo, DEVICE_NAND_ALE_OFFSET, NAND_READ_PAGE);
        
        // Wait for data to be available
        if(LOCAL_flashWaitForRdy(hNandInfo, NAND_TIMEOUT) != E_PASS)
          return E_FAIL;
          
        // Read 256 bytes of param page data
        j = 0;
        do 
        {
          for (i=0; i<256; i++)
            paramPageData[i] = LOCAL_flashReadData(hNandInfo) & 0xFF;
          j++;
        }
        while ((!LOCAL_onfiParamPageCRCCheck(paramPageData)) && (j<3));
    
        // We never got a good param page, so look in the NAND table
        if (j == 3) goto SEARCH_TABLE;
    
        // Use JEDEC manufacturer ID from Parameter Page
        hNandInfo->manfID = paramPageData[64];
        
        // Use Device ID from the standard READID command
        hNandInfo->devID = (Uint8) devID[1];
        
        // Use Parameter Page data to fill in NAND device info structure
        hNandInfo->dataBytesPerPage     = (Uint16) (*((Uint32 *) (paramPageData+80))) & 0xFFFF;
        hNandInfo->spareBytesPerPage    = (Uint16) (*((Uint16 *) (paramPageData+84)));
        hNandInfo->pagesPerBlock        = (Uint16) (*((Uint32 *) (paramPageData+92))) & 0xFFFF;
        hNandInfo->numBlocks            = (Uint32) (*((Uint32 *) (paramPageData+96))) * paramPageData[100];
        hNandInfo->numColAddrBytes      = (Uint8)  ((paramPageData[101] >> 4) & 0xF);
        hNandInfo->numRowAddrBytes      = (Uint8)  (paramPageData[101] & 0xF);
      }
      else
      {
    SEARCH_TABLE:
        i=0;
    
        hNandInfo->manfID = (Uint8) devID[0];
        hNandInfo->devID = (Uint8) devID[1]; 
    
        // Search for Device ID in table
        while (hNandInfo->hChipInfo[i].devID != 0x00)
        {
          if(devID[1] == hNandInfo->hChipInfo[i].devID)
          {
            hNandInfo->pagesPerBlock      = (Uint16) hNandInfo->hChipInfo[i].pagesPerBlock;
            hNandInfo->numBlocks          = (Uint32) hNandInfo->hChipInfo[i].numBlocks;
            hNandInfo->dataBytesPerPage   = (Uint16) NANDFLASH_PAGESIZE(hNandInfo->hChipInfo[i].bytesPerPage);
            hNandInfo->spareBytesPerPage  = (Uint16) (hNandInfo->hChipInfo[i].bytesPerPage - hNandInfo->dataBytesPerPage);
            break;
          }
          i++;
        }
        
        // If we didn't find the device in the device table OR
        // If we did find the device and it is reportedly greater than 1Gb in size, let's check and use the 4th ID byte
        // This will possibly allow support for 4K-page devices with same device ID as those in table, and bigger than 1 Gb (128 MB) in size    
        if ( 
             (hNandInfo->hChipInfo[i].devID == 0x00) ||
             ( 
               (hNandInfo->dataBytesPerPage > 512) && 
               (((hNandInfo->pagesPerBlock>>4) * hNandInfo->numBlocks * (hNandInfo->dataBytesPerPage>>8)) > (128*1024*1024 >> 12))
             ) 
           )
        {
          // Either 1K, 2K, 4K, or 8K
          hNandInfo->dataBytesPerPage = 0x1 << (10 +(devID[3] & 0x03));   
          
          // Calculates BlockSize/PageSize = pagesPerBlock
          hNandInfo->pagesPerBlock = 0x1 << ( 6 + ((devID[3]>>4) & 0x3) - (devID[3] & 0x3) ); 
          
          // Number of 512 byte blocks per page * spare bytes per 512 block
          j  = 0x1 << ( 3 + ((devID[3]>>2) & 0x1)); // Spare bytes per 512 bytes
          hNandInfo->spareBytesPerPage = (hNandInfo->dataBytesPerPage >> 9) * j;
    
          // If the device ID is not in the table then assume a value for the
          // total number of blocks. Make sure this matches with the actual NAND device
          hNandInfo->numBlocks = 8192;
    
          // Check busWidth to make sure it is valid and matches the device's set bus width
          if ((devID[3]>>6) & 0x1)  // Device says it is 16-bit
          {
            if (hNandInfo->busWidth != (Uint8) DEVICE_BUSWIDTH_16BIT)
            {
              return E_FAIL;
            }
          }
          else    // Device says it is 8-bit
          {
            if (hNandInfo->busWidth != (Uint8) DEVICE_BUSWIDTH_8BIT)
            {
              return E_FAIL;
            }
          }
        }
    
        // Setup row and column address byte-lengths
        hNandInfo->numColAddrBytes = (hNandInfo->dataBytesPerPage > 512)?2:1;
        
        j = 0;
        while( ((hNandInfo->numBlocks * hNandInfo->pagesPerBlock) >> j) > 1) j++;
        hNandInfo->numRowAddrBytes = j >> 3;
        if (j > (hNandInfo->numRowAddrBytes << 3) )
          hNandInfo->numRowAddrBytes++;
      }
    
      // Assign the number of operations per page value
      hNandInfo->numOpsPerPage = 0;
      while ( (hNandInfo->numOpsPerPage * DEVICE_NAND_MAX_BYTES_PER_OP) < hNandInfo->dataBytesPerPage )
        hNandInfo->numOpsPerPage++;
      
      // Assign the bytes per operation value
      if (hNandInfo->dataBytesPerPage < hNandInfo->hPageLayout->dataRegion.bytesPerOp)
      {
        hNandInfo->dataBytesPerOp = hNandInfo->dataBytesPerPage;
      }
      else
      {
        hNandInfo->dataBytesPerOp = hNandInfo->hPageLayout->dataRegion.bytesPerOp;
      }
      
      // Assign the spare bytes per operation value
      if (hNandInfo->spareBytesPerPage < hNandInfo->hPageLayout->spareRegion.bytesPerOp)
      {
        hNandInfo->spareBytesPerOp = hNandInfo->spareBytesPerPage;
      }
      else
      {
        hNandInfo->spareBytesPerOp = hNandInfo->hPageLayout->spareRegion.bytesPerOp;
      }
    
      // Check to make sure there are enough spare bytes to satisfy our needs
      if ((hNandInfo->numOpsPerPage * hNandInfo->spareBytesPerOp) > hNandInfo->spareBytesPerPage)
        return E_FAIL;
    
      // Check and make sure we have enough spare bytes per op
      if (hNandInfo->spareBytesPerOp < DEVICE_NAND_MIN_SPAREBYTES_PER_OP)
        return E_FAIL;
       
      // Assign the large page flag
      hNandInfo->isLargePage = (hNandInfo->dataBytesPerPage > 512)?TRUE:FALSE;
    
      return E_PASS;
    }
    
    static Bool LOCAL_onfiParamPageCRCCheck(Uint8 *paramPageData)
    {
      // Bit by bit algorithm without augmented zero bytes 
      const Uint16 polynom = 0x8005;  // Polynomial
      const Uint16 crcmask=0xFFFF, crchighbit=0x8000;
      Uint16 crc = 0x4F4E;    // Initialize the crc shift register with 0x4F4E
      Uint16 i, j, bit;
    
      for (i =0; i<254; i++) 
      {   
       for (j=0x80; j; j>>=1)
       {
         bit = crc & crchighbit;
         crc <<= 1;
         if (paramPageData[i] & j) 
           bit ^= crchighbit;
         if (bit) crc^= polynom;
       }   
       crc &= crcmask;
      }
      return  (crc == *((Uint16 *)&paramPageData[254]));
    }
    
    /***********************************************************
    * End file                                                 *
    ***********************************************************/
    
    
    
    /*
     * nor.c
    */
    
    /*
     * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ 
    */
    /* 
     *  Redistribution and use in source and binary forms, with or without 
     *  modification, are permitted provided that the following conditions 
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright 
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the 
     *    documentation and/or other materials provided with the   
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    /* --------------------------------------------------------------------------
      FILE      : nor.c 				                             	 	        
      PROJECT   : TI Boot and Flashing Utilities
      AUTHOR    : Daniel Allred
      DESC	    : Generic NOR driver file for EMIFA peripheral
    -------------------------------------------------------------------------- */
    
    // General type include
    #include "tistdtypes.h"
    
    // This module's header file  
    #include "nor.h"
    
    // Device specific CSL
    #include "device.h"
    
    // Misc. utility function include
    #include "util.h"
    
    // Project specific debug functionality
    #include "debug.h"
    
    
    /************************************************************
    * Explicit External Declarations                            *
    ************************************************************/
    
    
    /************************************************************
    * Local Macro Declarations                                  *
    ************************************************************/
    
    
    /************************************************************
    * Local Typedef Declarations                                *
    ************************************************************/
    
    
    /************************************************************
    * Local Function Declarations                               *
    ************************************************************/
    
    static VUint8 *LOCAL_flashMakeAddr (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset);
    static void LOCAL_flashMakeCmd (NOR_InfoHandle hNorInfo, Uint8 cmd, void *cmdbuf);
    static void LOCAL_flashWriteCmd (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 cmd);
    static void LOCAL_flashWriteData(NOR_InfoHandle hNorInfo, Uint32 address, Uint32 data);
    static Uint32 LOCAL_flashVerifyDataBuffer(NOR_InfoHandle hNorInfo, Uint32 address, void* data, Uint32 numBytes);
    static Uint32 LOCAL_flashReadData(NOR_InfoHandle hNorInfo, Uint32 address, Uint32 offset);
    static Bool LOCAL_flashIsSetAll (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 mask);
    static Bool LOCAL_flashIsSetSome (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 mask);
    static NOR_Data LOCAL_flashReadCFIBytes (NOR_InfoHandle hNorInfo, Uint32 offset, Uint8 numBytes);
    static Bool LOCAL_flashCFIIsEqual (NOR_InfoHandle hNorInfo, Uint32 offset, Uint8 val);
    // Flash Identification and discovery
    static Uint32   LOCAL_flashQueryCFI( NOR_InfoHandle hNorInfo );
    
    
    // Empty commands for when neither command set is used
    static Uint32   Unsupported_Erase(NOR_InfoHandle hNorInfo, Uint32 address);
    static Uint32   Unsupported_Write(NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data);
    static Uint32   Unsupported_BufferWrite(NOR_InfoHandle hNorInfo, Uint32, VUint8[], Uint32 );
    static Uint32   Unsupported_ID(NOR_InfoHandle hNorInfo);
    static void     Unsupported_SoftReset(NOR_InfoHandle hNorInfo);
    
    
    //Intel pointer-mapped commands
    static Uint32   Intel_Erase( NOR_InfoHandle hNorInfo, VUint32 blkAddr);
    static Uint32   Intel_Write( NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data );
    static Uint32   Intel_BufferWrite( NOR_InfoHandle hNorInfo, Uint32 address, VUint8 data[], Uint32 numBytes );
    static Uint32   Intel_ID( NOR_InfoHandle hNorInfo );
    static void     Intel_SoftReset(NOR_InfoHandle hNorInfo);
    // Misc. Intel commands
    static Uint32   LOCAL_IntelClearLock(NOR_InfoHandle hNorInfo, Uint32 blkAddr);
    static Uint32   LOCAL_IntelSetLock(NOR_InfoHandle hNorInfo, Uint32 blkAddr);
    static Uint32   LOCAL_IntelLockStatusCheck(NOR_InfoHandle hNorInfo);
    static void     LOCAL_IntelClearStatus(NOR_InfoHandle hNorInfo);
    static void     LOCAL_IntelWaitForStatusComplete(NOR_InfoHandle hNorInfo);
    
    
    //AMD pointer-mapped commands
    static Uint32   AMD_Erase(NOR_InfoHandle hNorInfo, Uint32 blkAddr);
    static Uint32   AMD_Write(NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data );
    static Uint32   AMD_BufferWrite(NOR_InfoHandle hNorInfo, Uint32 address, VUint8 data[], Uint32 numBytes );
    static Uint32   AMD_ID(NOR_InfoHandle hNorInfo);
    static void     AMD_SoftReset(NOR_InfoHandle hNorInfo);
    // Misc. AMD commands
    static void     LOCAL_AMDPrefixCommands(NOR_InfoHandle hNorInfo);
    static void     LOCAL_AMDWriteBufAbortReset(NOR_InfoHandle hNorInfo);
    
    
    /************************************************************
    * Local Variable Definitions                                *
    ************************************************************/
    
    
    /************************************************************
    * Global Variable Definitions                               *
    ************************************************************/
    
    const NOR_FxnsTable AMD_NOR_FxnsTable = 
    {
      &(AMD_Write),
      &(AMD_BufferWrite),
      &(AMD_Erase),
      &(AMD_ID),
      &(AMD_SoftReset)
    };
    
    const NOR_FxnsTable Intel_NOR_FxnsTable = 
    {
      &(Intel_Write),
      &(Intel_BufferWrite),
      &(Intel_Erase),
      &(Intel_ID),
      &(Intel_SoftReset)
    };
    
    const NOR_FxnsTable Unsupported_NOR_FxnsTable = 
    {
      &(Unsupported_Write),
      &(Unsupported_BufferWrite),
      &(Unsupported_Erase),
      &(Unsupported_ID),
      &(Unsupported_SoftReset)
    };
    
    #ifdef USE_IN_ROM
    NOR_InfoObj gNorInfo;
    #endif
    
    
    /************************************************************
    * Global Function Definitions                               *
    ************************************************************/
    
    NOR_InfoHandle NOR_open(Uint32 baseCSAddr, Uint8 busWidth)
    {
      NOR_InfoHandle hNorInfo;
      
    #ifdef USE_IN_ROM
      hNorInfo = (NOR_InfoHandle) &gNorInfo;
    #else
      hNorInfo = (NOR_InfoHandle) UTIL_callocMem(sizeof(NOR_InfoObj));
    #endif
    
      // Open Async Memory peripheral
      hNorInfo->hAsyncMemInfo = ASYNC_MEM_Open
      (
        AYSNC_MEM_TYPE_NOR,
        baseCSAddr,
        busWidth
      );
    
      // Set NOR flash base address
      hNorInfo->flashBase = baseCSAddr;
    
      // Set width to 8 or 16
      hNorInfo->busWidth = busWidth;
    
      // Try both Intel and AMD resets ( we don't know yet which we need)
      AMD_SoftReset(hNorInfo);
      Intel_SoftReset(hNorInfo);
    
      // Perform CFI Query
      DEBUG_printString("CFI Query...");
      if (LOCAL_flashQueryCFI(hNorInfo) != E_PASS)
      {
        DEBUG_printString("failed.\r\n");
        return NULL;
      }
        
      // Setup function pointers
      DEBUG_printString("passed.\r\nNOR Initialization:\r\n");
        
      DEBUG_printString("\tCommand Set: ");    
      switch (hNorInfo->commandSet)
      {
        case AMD_BASIC_CMDSET:
        case AMD_EXT_CMDSET:
          hNorInfo->hNorFxns   = (NOR_FxnsHandle) &AMD_NOR_FxnsTable;
          DEBUG_printString("AMD\r\n");
          break;
        case INTEL_BASIC_CMDSET:
        case INTEL_EXT_CMDSET:
          hNorInfo->hNorFxns   = (NOR_FxnsHandle) &Intel_NOR_FxnsTable;
          DEBUG_printString("Intel\r\n");
          break;
        default:
          hNorInfo->hNorFxns   = NULL;
          DEBUG_printString("Unknown\r\n");
          break;
      }
      
      if ((*(hNorInfo->hNorFxns->id))(hNorInfo) != E_PASS)
      {
        DEBUG_printString("NOR ID failed.\r\n");
        return NULL;
      }
            
      DEBUG_printString("\tManufacturer: ");
      switch(hNorInfo->manfID)
      {
        case AMD:
          DEBUG_printString("AMD");
          break;
        case FUJITSU:
          DEBUG_printString("FUJITSU");
          break;
        case INTEL:
          DEBUG_printString("INTEL");
          break;
        case MICRON:
          DEBUG_printString("MICRON");
          break;
        case SAMSUNG:
          DEBUG_printString("SAMSUNG");
          break;
        case SHARP:
          DEBUG_printString("SHARP");
          break;
        default:
          DEBUG_printString("Unknown");
          break;
      }
      DEBUG_printString("\r\n");
      DEBUG_printString("\tSize: ");
      DEBUG_printHexInt(hNorInfo->flashSize>>20);
      DEBUG_printString(" MB\r\n");
        
      return hNorInfo;    
    }
    
    // Get info on block address and sizes
    Uint32 NOR_getBlockInfo(NOR_InfoHandle hNorInfo, Uint32 address, Uint32* blockSize, Uint32* blockAddr)
    {
      Int32 i;
      Uint32 currRegionAddr, nextRegionAddr;
            
      currRegionAddr = (Uint32) hNorInfo->flashBase;
      if ((address < currRegionAddr) || (address >= (currRegionAddr+hNorInfo->flashSize)))
      {
        return E_FAIL;
      }
        
      for(i=0; i< (hNorInfo->numberRegions); i++)
      {
        nextRegionAddr = currRegionAddr + (hNorInfo->blockSize[i] * hNorInfo->numberBlocks[i]);
        if ( (currRegionAddr <= address) && (nextRegionAddr > address) )
        {
          *blockSize = hNorInfo->blockSize[i];
          *blockAddr = address & (~((*blockSize) - 1));
          break;
        }
        currRegionAddr = nextRegionAddr;
      }
      return E_PASS;
    }
    
    //Global Erase NOR Flash
    Uint32 NOR_globalErase(NOR_InfoHandle hNorInfo)
    {
      return NOR_erase( hNorInfo, (VUint32) hNorInfo->flashBase, (VUint32) hNorInfo->flashSize );
    }
    
    void NOR_reset(NOR_InfoHandle hNorInfo)
    {
      hNorInfo->hNorFxns->reset(hNorInfo);
    }
    
    // Erase Flash Block
    Uint32 NOR_erase(NOR_InfoHandle hNorInfo, VUint32 start_address, VUint32 size)
    {
      Uint32 i;
    	VUint32 addr  = start_address;
    	VUint32 range = start_address + size;
    //	VUint32 addr  = hNorInfo->flashBase;
    //	VUint32 range = start_address +  hNorInfo->flashSize;
    
    	Uint32 blockSize, blockAddr;
    	
    	DEBUG_printString("Erasing the NOR Flash\r\n");
    	
      while (addr < range)
      {
        if (NOR_getBlockInfo(hNorInfo, addr, &blockSize, &blockAddr) != E_PASS)
        {
          DEBUG_printString("Address out of range");
          return E_FAIL;
        }
    		
    		//Increment to the next block
        if ((*(hNorInfo->hNorFxns->erase))(hNorInfo, blockAddr) != E_PASS)
    //    if ( (*Flash_Erase)(hNorInfo, blockAddr) != E_PASS)
        {
          DEBUG_printString("Erase failure at block address ");
          DEBUG_printHexInt(blockAddr);
          DEBUG_printString("\r\n");
          return E_FAIL;
        }
        
        // Verify erase was correct
        NOR_reset(hNorInfo);  // Put NOR into read mode
        for (i=0; i< blockSize; i+=4)
        {
    		/*
            DEBUG_printString("Data at address ");
            DEBUG_printHexInt(( *((Uint32 *)(addr+i))));
            DEBUG_printString("\r\n");
    		*/
          if ( *((Uint32 *)(addr+i)) != 0xFFFFFFFF)
          {
            DEBUG_printString("Erase failure at address ");
            DEBUG_printHexInt((addr+i));
            DEBUG_printString(" Data:");
            DEBUG_printHexInt( *((Uint32 *)(addr+i)));
            DEBUG_printString(".\r\n");
            return E_FAIL;
          }
        }
        
        
        addr = blockAddr + blockSize;
    	    
        // Show status messages
    
        DEBUG_printString("Erased through ");
        DEBUG_printHexInt(addr);
        DEBUG_printString("\r\n");
    
      }
    
      DEBUG_printString("Erase Completed\r\n");
    
      return(E_PASS);
    }
    
    // NOR_WriteBytes
    Uint32 NOR_writeBytes( NOR_InfoHandle hNorInfo, Uint32 writeAddress, Uint32 numBytes, Uint32 readAddress)
    {
      Uint32  blockSize, blockAddr;
      Int32   i;
      Uint32  retval = E_PASS;
    
      DEBUG_printString("Writing the NOR Flash\r\n");
    
      // Make numBytes even if needed
      if (numBytes & 0x00000001)
      {
        numBytes++;
      }
    
      if (NOR_getBlockInfo(hNorInfo, writeAddress, &blockSize, &blockAddr) != E_PASS)
      {
        DEBUG_printString("Address out of range\r\n");
        return E_FAIL;
      }
    
      while (numBytes > 0)
      {
        if(  (hNorInfo->bufferSize == 1) || (numBytes < hNorInfo->bufferSize) || (writeAddress & (hNorInfo->bufferSize-1)) )
        {
          if ((*(hNorInfo->hNorFxns->write))(hNorInfo, writeAddress, LOCAL_flashReadData(hNorInfo,readAddress,0) ) != E_PASS)
    //      if ((*Flash_Write)(hNorInfo, writeAddress, LOCAL_flashReadData(hNorInfo,readAddress,0) ) != E_PASS)
          {
            DEBUG_printString("\r\nNormal write failed.\r\n");
            retval = E_FAIL;
          }
          else
          {
            numBytes     -= hNorInfo->busWidth;
            writeAddress += hNorInfo->busWidth;
            readAddress  += hNorInfo->busWidth;
          }
        }
        else
        {
          // Try to use buffered writes
          if((*(hNorInfo->hNorFxns->bufferWrite))(hNorInfo, writeAddress, (VUint8 *)readAddress, hNorInfo->bufferSize) == E_PASS)
    //      if((*Flash_BufferWrite)(hNorInfo, writeAddress, (VUint8 *)readAddress, hNorInfo->bufferSize) == E_PASS)
          {
            numBytes -= hNorInfo->bufferSize;
            writeAddress += hNorInfo->bufferSize;
            readAddress  += hNorInfo->bufferSize;
          }
          else
          {
            DEBUG_printString("\r\nBuffered write failed. Trying normal write\r\n");
            // Try normal writes as a backup
            for(i = 0; i<(hNorInfo->bufferSize>>1); i++)
            {
              if ((*(hNorInfo->hNorFxns->write))(hNorInfo, writeAddress, LOCAL_flashReadData(hNorInfo,readAddress,0) ) != E_PASS)
    //          if ((*Flash_Write)(hNorInfo, writeAddress, LOCAL_flashReadData(hNorInfo,readAddress,0) ) != E_PASS)
              {
                DEBUG_printString("\r\nNormal write also failed\r\n");
                retval = E_FAIL;
                break;
              }
              else
              {
                numBytes     -= hNorInfo->busWidth;
                writeAddress += hNorInfo->busWidth;
                readAddress  += hNorInfo->busWidth;
              }
            }
          }
        }
    
        // Output status info on the write operation
        if (retval == E_PASS)
        {    
          if  ( ((writeAddress & (~((blockSize>>2)-1))) == writeAddress) || (numBytes == 0) )
          {
            DEBUG_printString("NOR Write OK through ");
            DEBUG_printHexInt(writeAddress);
            DEBUG_printString(".\r\n");
    
            if (NOR_getBlockInfo(hNorInfo, writeAddress, &blockSize, &blockAddr) != E_PASS)
            {
              DEBUG_printString("Address out of range");
              return E_FAIL;
            }
          }
        }
        else
        {
          DEBUG_printString( "NOR Write Failed...Aborting!\r\n");
          return E_FAIL;
        }
      }
      return retval;
    }
    
    
    /************************************************************
    * Local Function Definitions                                *
    ************************************************************/
    
    static VUint8 *LOCAL_flashMakeAddr (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset)
    {
      return ((VUint8 *) ( blkAddr + (offset * hNorInfo->maxTotalWidth)));
    }
    
    static void LOCAL_flashMakeCmd (NOR_InfoHandle hNorInfo, Uint8 cmd, void *cmdbuf)
    {
      Int32 i;
      Uint8 *cp = (Uint8 *) cmdbuf;
    
      for (i = hNorInfo->busWidth; i > 0; i--)
        *cp++ = (i & (hNorInfo->chipOperatingWidth - 1)) ? 0x00 : cmd;
    }
    
    static void LOCAL_flashWriteCmd (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 cmd)
    {
      volatile NOR_Ptr addr;
      NOR_Data cmdword;
    
      addr.cp = LOCAL_flashMakeAddr (hNorInfo, blkAddr, offset);
      LOCAL_flashMakeCmd ( hNorInfo, cmd, &cmdword);
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          *addr.cp = cmdword.c;
          break;
        case BUS_16BIT:
          *addr.wp = cmdword.w;
          break;
      }
    }
    
    static void LOCAL_flashWriteData(NOR_InfoHandle hNorInfo, Uint32 address, Uint32 data)
    {
      volatile NOR_Ptr pAddr;
      NOR_Data dataword;
      dataword.l = data;
    
      pAddr.cp = (VUint8*) address;
    
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          *pAddr.cp = dataword.c;
          break;
        case BUS_16BIT:
          *pAddr.wp = dataword.w;
          break;
      }
    }
    
    /* Used only once */
    static Uint32 LOCAL_flashVerifyDataBuffer(NOR_InfoHandle hNorInfo, Uint32 address, void* data, Uint32 numBytes)
    {
      volatile NOR_Ptr pAddr, pData;
      VUint8* endAddress;
    		
      pData.cp = (VUint8*) data;
      pAddr.cp = (VUint8*) address;
      endAddress =(VUint8*)(address+numBytes);
      while (pAddr.cp < endAddress)
      {
        switch (hNorInfo->busWidth)
        {
          case BUS_8BIT:
            if ( (*pAddr.cp++) != (*pData.cp++) )
              return E_FAIL;
            break;
          case BUS_16BIT:
            if ( (*pAddr.wp++) != (*pData.wp++) )
              return E_FAIL;
            break;
        }
      }
      return E_PASS;
    }
    
    static Uint32 LOCAL_flashReadData(NOR_InfoHandle hNorInfo, Uint32 address, Uint32 offset)
    {
      volatile NOR_Ptr pAddr;
      NOR_Data dataword;
      dataword.l = 0x00000000;
    
      pAddr.cp = LOCAL_flashMakeAddr(hNorInfo, address, offset);
    	
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          dataword.c = *pAddr.cp;
          break;      
        case BUS_16BIT:
          dataword.w = *pAddr.wp;
          break;
    	}
    	return dataword.l;
    }
    
    static Bool LOCAL_flashIsSetAll (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 mask)
    {
      volatile NOR_Ptr addr;
    	NOR_Data maskword;
      Bool retval = TRUE;
      Uint32 temp;
    
      maskword.l = 0x00000000;
    
      addr.cp = LOCAL_flashMakeAddr (hNorInfo, blkAddr, offset);
      temp = *addr.wp;
      LOCAL_flashMakeCmd (hNorInfo, mask, &maskword);
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          temp = *addr.cp;
          retval = ((maskword.c & temp) == maskword.c);
          break;
        case BUS_16BIT:
          temp = *addr.wp;
          retval = ((maskword.w & temp) == maskword.w);
          break;
    	}
      return retval;
    }
    
    static Bool LOCAL_flashIsSetSome (NOR_InfoHandle hNorInfo, Uint32 blkAddr, Uint32 offset, Uint8 mask)
    {
      volatile NOR_Ptr addr;
      NOR_Data maskword;
    	
      Bool retval = TRUE;
    
      addr.cp = LOCAL_flashMakeAddr (hNorInfo, blkAddr, offset);
      LOCAL_flashMakeCmd (hNorInfo, mask, &maskword);
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          retval = (maskword.c & *addr.cp);
          break;
        case BUS_16BIT:
          retval = (maskword.w & *addr.wp);
          break;
      }
      return retval;
    }
    
    static NOR_Data LOCAL_flashReadCFIBytes (NOR_InfoHandle hNorInfo, Uint32 offset, Uint8 numBytes)
    {
      Int32 i;
      NOR_Data readword;
      Uint8* pReadword = &readword.c;
    	
      for (i = 0; i < numBytes; i++)
      {
        *pReadword++ = *(LOCAL_flashMakeAddr (hNorInfo, hNorInfo->flashBase, offset+i));
      }
    	
      return readword;
    }
    
    static Bool LOCAL_flashCFIIsEqual (NOR_InfoHandle hNorInfo, Uint32 offset, Uint8 val)
    {
      volatile NOR_Ptr addr;
      NOR_Data testword;
    	
      Bool retval = TRUE;
    
      addr.cp = LOCAL_flashMakeAddr (hNorInfo, hNorInfo->flashBase, offset);
      LOCAL_flashMakeCmd (hNorInfo, val, &testword);
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          retval = (testword.c == *addr.cp);
          break;
        case BUS_16BIT:
          retval = (testword.w == *addr.wp);
          break;
    	}
      return retval;
    }
    
    // Query the chip to check for CFI table and data
    static Uint32 LOCAL_flashQueryCFI( NOR_InfoHandle hNorInfo )
    {                
      Int32 i;
      Uint32 blkVal; 
        
      // Six possible NOR Flash Configurations
      //  1) Bus in x8 mode, x8 only device (chipOperatingWidth = 8-bit, busWidth = 8-bit, maxTotalWidth = 8-bit)
      //  2) Bus in x8 mode, single x8/x16 flash operating in x8 mode (chipOperatingWidth = 8-bit, busWidth = 8-bit, maxTotalWidth = 16-bit)
      //  3) Bus in x16 mode, single x8/x16 or x16-only flash operating in x16 mode (chipOperatingWidth = 16-bit, busWidth = 16-bit, maxTotalWidth = 16-bit)
      //  4) Bus in x16 mode, two x8 flash operating in parallel. (chipOperatingWidth = 8-bit, busWidth = 16-bit, maxTotalWidth = 16-bit)
      //  5) Bus in x16 mode, two x8/x16 flash, each in x8 mode, operating in parallel  (chipOperatingWidth = 8-bit, busWidth = 16-bit, maxTotalWidth = 32-bit)
      //  6) Bus in x16 mode, single x16/x32 flash operating in x16 mode (chipOperatingWidth = 16-bit, busWidth = 16-bit, maxTotalWidth = 32-bit)
      // hNorInfo->chipOperatingWidth is the actual data bus width of the NOR flash(es)
      // hNorInfo->busWidth is the operating width of the EMIF (8 or 16)
      // hNorInfo->maxTotalWidth is total possible data bus width that the NOR flash supports (or flashes combined support)
      for (hNorInfo->chipOperatingWidth = BUS_8BIT; hNorInfo->chipOperatingWidth <= hNorInfo->busWidth;  hNorInfo->chipOperatingWidth <<= 1)
      {
        for (hNorInfo->maxTotalWidth = hNorInfo->busWidth; hNorInfo->maxTotalWidth <= (hNorInfo->busWidth*2); hNorInfo->maxTotalWidth <<= 1)
        {
          // Specify number of devices
          hNorInfo->numberDevices = 0;
          while ( hNorInfo->numberDevices * hNorInfo->chipOperatingWidth < hNorInfo->busWidth)
            hNorInfo->numberDevices++;
                            
          // Enter the CFI Query mode
          LOCAL_flashWriteCmd (hNorInfo, hNorInfo->flashBase, 0, CFI_EXIT_CMD);
          LOCAL_flashWriteCmd (hNorInfo, hNorInfo->flashBase, CFI_QRY_CMD_ADDR, CFI_QRY_CMD);
    
          // Check for Query QRY values
          if ( LOCAL_flashCFIIsEqual ( hNorInfo, CFI_Q, 'Q') && 
          LOCAL_flashCFIIsEqual ( hNorInfo, CFI_R, 'R') && 
          LOCAL_flashCFIIsEqual ( hNorInfo, CFI_Y, 'Y') )
    			{               
            hNorInfo->commandSet = (NOR_CmdSet) (LOCAL_flashReadCFIBytes(hNorInfo,CFI_CMDSET,2).w);
            hNorInfo->flashSize = 0x1 << LOCAL_flashReadCFIBytes(hNorInfo,CFI_DEVICESIZE,1).c * hNorInfo->numberDevices;
            hNorInfo->numberRegions = LOCAL_flashReadCFIBytes(hNorInfo,CFI_NUMBLKREGIONS,1).c;
            hNorInfo->bufferSize = 0x1 << LOCAL_flashReadCFIBytes(hNorInfo,CFI_WRITESIZE,2).w * hNorInfo->numberDevices;
                    
            // Get info on sector sizes in each erase region of device
            for (i = 0;i < hNorInfo->numberRegions; i++)
            {    
              blkVal = LOCAL_flashReadCFIBytes(hNorInfo,(CFI_BLKREGIONS+i*CFI_BLKREGIONSIZE),4).l;
              hNorInfo->numberBlocks[i] = (blkVal&0x0000FFFF) + 1;
              hNorInfo->blockSize[i]    = ((blkVal&0xFFFF0000) ? ( ((blkVal>>16)&0xFFFF) * 256) : 128) * hNorInfo->numberDevices;
            }
                    
            // Exit CFI mode 
            LOCAL_flashWriteCmd (hNorInfo,hNorInfo->flashBase, 0, CFI_EXIT_CMD);
    			    
            return E_PASS;
          }
        }        
      }
        
      LOCAL_flashWriteCmd (hNorInfo,hNorInfo->flashBase, 0, CFI_EXIT_CMD);   
      return E_FAIL;
    }
    
    
    // ------------------------ Default empty commands ---------------------------
    
    static Uint32 Unsupported_Write( NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data)
    {
      return E_FAIL;
    }
    static Uint32 Unsupported_BufferWrite(NOR_InfoHandle hNorInfo, Uint32 address, VUint8 data[], Uint32 length )
    {
      return E_FAIL;
    }
    static Uint32 Unsupported_Erase(NOR_InfoHandle hNorInfo, Uint32 address)
    {
      return E_FAIL;
    }
    static Uint32 Unsupported_ID(NOR_InfoHandle hNorInfo)
    {
      return E_FAIL;
    }
    
    static void Unsupported_SoftReset(NOR_InfoHandle hNorInfo)
    {
    
    }
    
    
    // ------------------- Begin of Intel specific commands ----------------------
    //ID flash
    static Uint32 Intel_ID( NOR_InfoHandle hNorInfo )
    {
        // Intel Exit back to read array mode
        Intel_SoftReset(hNorInfo);
        
        // Write ID command
        LOCAL_flashWriteCmd(hNorInfo,hNorInfo->flashBase, 0, INTEL_ID_CMD);
            
        //Read Manufacturer's ID
        hNorInfo->manfID = (NOR_ManfID) LOCAL_flashReadData(hNorInfo, hNorInfo->flashBase, INTEL_MANFID_ADDR);
        
        // Read Device ID
        hNorInfo->devID1 = (Uint16) (NOR_ManfID) LOCAL_flashReadData(hNorInfo, hNorInfo->flashBase, INTEL_DEVID_ADDR);
        hNorInfo->devID2 = 0x0000;
            
        // Intel Exit back to read array mode
        Intel_SoftReset(hNorInfo); 
        
        return E_PASS;
    }
    
    // Reset back to Read array mode
    static void Intel_SoftReset(NOR_InfoHandle hNorInfo)
    {
        // Intel Exit back to read array mode
        LOCAL_flashWriteCmd(hNorInfo, hNorInfo->flashBase, 0, INTEL_RESET);
    }
    
    // Clear status register
    static void LOCAL_IntelClearStatus(NOR_InfoHandle hNorInfo)
    {
        // Intel clear status
        LOCAL_flashWriteCmd(hNorInfo, hNorInfo->flashBase,0,INTEL_CLEARSTATUS_CMD);
    }
    
    // Remove block write protection
    static Uint32 LOCAL_IntelClearLock(NOR_InfoHandle hNorInfo, Uint32 blkAddr)
    {
    
    	// Write the Clear Lock Command
        LOCAL_flashWriteCmd(hNorInfo, blkAddr,0,INTEL_LOCK_CMD0);
    
        LOCAL_flashWriteCmd(hNorInfo, blkAddr,0,INTEL_UNLOCK_BLOCK_CMD);
    
        // Check Status
    	return LOCAL_IntelLockStatusCheck(hNorInfo);
    }
    
    // Write-protect a block
    static Uint32 LOCAL_IntelSetLock(NOR_InfoHandle hNorInfo, Uint32 blkAddr)
    {
    	// Write the Set Lock Command	
      LOCAL_flashWriteCmd(hNorInfo, blkAddr,0,INTEL_LOCK_CMD0);            
    	
      LOCAL_flashWriteCmd(hNorInfo, blkAddr,0,INTEL_LOCK_BLOCK_CMD);
    
      // Check Status
      return LOCAL_IntelLockStatusCheck(hNorInfo);
    }
    
    static void LOCAL_IntelWaitForStatusComplete(NOR_InfoHandle hNorInfo)
    {
        while ( !LOCAL_flashIsSetAll(hNorInfo, hNorInfo->flashBase, 0, BIT7) );
    }
    
    static Uint32 LOCAL_IntelLockStatusCheck(NOR_InfoHandle hNorInfo)
    {
        Uint32 retval = E_PASS;
        //Uint8 status;
    
        LOCAL_IntelWaitForStatusComplete(hNorInfo);
    
        //status = flash_read_uint16((Uint32)hNorInfo->flashBase,0);
        //if ( status & BIT5 )
        if (LOCAL_flashIsSetSome(hNorInfo, hNorInfo->flashBase, 0, (BIT5 | BIT3)))
        {
            retval = E_FAIL;
    		/*if ( status & BIT4 )
            {
    			DEBUG_printString("Command Sequence Error\r\n");
    		}
    		else
    		{
    			DEBUG_printString("Clear Lock Error\r\n");
    		}*/
    	}
    	/*if ( status & BIT3 )
    	{
    		retval = E_FAIL;
    		//DEBUG_printString("Voltage Range Error\n");
        }*/
    	
    	// Clear status
    	LOCAL_IntelClearStatus(hNorInfo);
    	
    	// Put chip back into read array mode.
    	Intel_SoftReset(hNorInfo);
    	
    	// Set Timings back to Optimum for Read
    	return retval;
    }
    
    // Erase Block
    static Uint32 Intel_Erase(NOR_InfoHandle hNorInfo, VUint32 blkAddr)
    {
    	Uint32 retval = E_PASS;
    	
    	// Clear Lock Bits
    	retval |= LOCAL_IntelClearLock(hNorInfo,blkAddr);
    	
    	// Send Erase commands
    	LOCAL_flashWriteCmd(hNorInfo,blkAddr,0,INTEL_ERASE_CMD0);
    	LOCAL_flashWriteCmd(hNorInfo,blkAddr,0,INTEL_ERASE_CMD1);
    	
    	// Wait until Erase operation complete
    	LOCAL_IntelWaitForStatusComplete(hNorInfo);
        
      // Verify successful erase                       
      if ( LOCAL_flashIsSetSome(hNorInfo,hNorInfo->flashBase, 0, BIT5) )
        retval = E_FAIL;
        
    	// Put back into Read Array mode.
    	Intel_SoftReset(hNorInfo);
    	
    	return retval;
    }
    
    // Write data
    static Uint32 Intel_Write(NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data )
    {
      Uint32 retval = E_PASS;
    
      // Send Write command
      LOCAL_flashWriteCmd(hNorInfo,address,0,INTEL_WRITE_CMD);
      LOCAL_flashWriteData(hNorInfo,address, data);
    
      // Wait until Write operation complete
      LOCAL_IntelWaitForStatusComplete(hNorInfo);
    
      // Verify successful program
      if ( LOCAL_flashIsSetSome(hNorInfo, hNorInfo->flashBase, 0, (BIT4|BIT3)) )
      {
        //DEBUG_printString("Write Op Failed.\r\n", FALSE);
        retval = E_FAIL;
      }
    
      // Put back into Read Array mode.
    	Intel_SoftReset(hNorInfo);
                              
      return retval;
    }
    
    // Buffer write data
    static Uint32 Intel_BufferWrite(NOR_InfoHandle hNorInfo, Uint32 address, VUint8 data[], Uint32 numBytes )
    {
    	Uint32 retval = E_PASS;
    	Uint32 timeoutCnt = 0, shift;
    
    	// Send Write_Buff_Load command   
      do {
        LOCAL_flashWriteCmd(hNorInfo,address,0,INTEL_WRT_BUF_LOAD_CMD);
        timeoutCnt++;
      }while( (!LOCAL_flashIsSetAll(hNorInfo,hNorInfo->flashBase, 0, BIT7)) && (timeoutCnt < 0x00010000) );
    
      if (timeoutCnt >= 0x10000)
      {
        retval = E_TIMEOUT;
      }
      else
      {
        volatile NOR_Ptr pAddr, pData;
        VUint8* endAddress;
        
        //Establish correct shift value
        shift = 0;
        while ((hNorInfo->busWidth >> shift) > 1)
          shift++;
    
        // Write Length (either numBytes or numBytes/2)	    
        LOCAL_flashWriteCmd(hNorInfo, address, 0, (numBytes >> shift) - 1);
    
        // Write buffer data
        pData.cp = (VUint8*) data;
        pAddr.cp = (VUint8*) address;
        endAddress =(VUint8*)(pAddr.cp + numBytes);
        while (pAddr.cp < endAddress)
        {
          switch (hNorInfo->busWidth)
          {
            case BUS_8BIT:
              *pAddr.cp++ = *pData.cp++;
              break;
            case BUS_16BIT:
              *pAddr.wp++ = *pData.wp++;
              break;
          }
        }
    
        // Send write buffer confirm command
        LOCAL_flashWriteCmd(hNorInfo, address, 0,INTEL_WRT_BUF_CONF_CMD);
    
        // Check status
        LOCAL_IntelWaitForStatusComplete(hNorInfo);
        
        // Verify program was successful
        if ( LOCAL_flashIsSetSome(hNorInfo, hNorInfo->flashBase, 0, BIT4) )
        {
          retval = E_FAIL;
        }
    
        // Put back into Read Array mode.
        Intel_SoftReset(hNorInfo);
        if (retval == E_PASS)
        {
          retval = LOCAL_flashVerifyDataBuffer(hNorInfo, address, (void*)data, numBytes);
          if (retval != E_PASS)
            DEBUG_printString("Data verify failed.\r\n");
        }    
      }
    
      return retval;
    }
    // -------------------- End of Intel specific commands -----------------------
    
    
    
    // -------------------- Begin of AMD specific commands -----------------------
    
    // Identify the Manufacturer and Device ID 
    static Uint32 AMD_ID( NOR_InfoHandle hNorInfo )
    {
      // Exit back to read array mode
      AMD_SoftReset(hNorInfo);
    
      // Write ID commands
      LOCAL_AMDPrefixCommands(hNorInfo);
      LOCAL_flashWriteCmd(hNorInfo, hNorInfo->flashBase, AMD_CMD2_ADDR, AMD_ID_CMD);
    
      // Read manufacturer's ID
      hNorInfo->manfID = (NOR_ManfID) LOCAL_flashReadData(hNorInfo,hNorInfo->flashBase, AMD_MANFID_ADDR);
        
      // Read device ID
      hNorInfo->devID1 = (Uint16) LOCAL_flashReadData(hNorInfo,hNorInfo->flashBase, AMD_DEVID_ADDR0);
        
      // Read additional ID bytes if needed
      if ( (hNorInfo->devID1 & 0xFF ) == AMD_ID_MULTI )
        hNorInfo->devID2 = LOCAL_flashReadCFIBytes(hNorInfo, AMD_DEVID_ADDR1, 2).w;
      else
        hNorInfo->devID2 = 0x0000;
            
      // Exit back to read array mode
      AMD_SoftReset(hNorInfo);
        
      return E_PASS;
    }
    
    static void AMD_SoftReset(NOR_InfoHandle hNorInfo)
    {
    	// Reset Flash to be in Read Array Mode
    	LOCAL_flashWriteCmd(hNorInfo,hNorInfo->flashBase,AMD_CMD2_ADDR,AMD_RESET);
      UTIL_waitLoop(5000);
    }
    
    // AMD Prefix Commands
    static void LOCAL_AMDPrefixCommands(NOR_InfoHandle hNorInfo)
    {
      LOCAL_flashWriteCmd(hNorInfo, hNorInfo->flashBase, AMD_CMD0_ADDR, AMD_CMD0);
      LOCAL_flashWriteCmd(hNorInfo, hNorInfo->flashBase, AMD_CMD1_ADDR, AMD_CMD1);
    }
    
    // Erase Block
    static Uint32 AMD_Erase(NOR_InfoHandle hNorInfo, Uint32 blkAddr)
    {
      Uint32 retval = E_PASS;
      Uint32 cnt = 0;
    
      // Send commands
      LOCAL_AMDPrefixCommands(hNorInfo);
      LOCAL_flashWriteCmd(hNorInfo,hNorInfo->flashBase, AMD_CMD2_ADDR, AMD_BLK_ERASE_SETUP_CMD);
      LOCAL_AMDPrefixCommands(hNorInfo);
      LOCAL_flashWriteCmd(hNorInfo,blkAddr, 0x0, AMD_BLK_ERASE_CMD);
    	
      // Poll DQ7 and DQ15 for status
      while ( !LOCAL_flashIsSetAll(hNorInfo,blkAddr, 0, BIT7) )
      {
        cnt++;
      }
    
      UTIL_waitLoop(1000);
        
      // Check data
      if ( !LOCAL_flashIsSetAll(hNorInfo, blkAddr, 0, AMD_BLK_ERASE_DONE) )
        retval = E_FAIL;
    	
      // Flash Mode: Read Array
      AMD_SoftReset(hNorInfo);
        
      return retval;
    }
    
    // AMD Flash Write
    static Uint32 AMD_Write(NOR_InfoHandle hNorInfo, Uint32 address, VUint32 data )
    {
      Uint32 retval = E_PASS;
    	
      // Send Commands
      LOCAL_AMDPrefixCommands(hNorInfo);
      LOCAL_flashWriteCmd(hNorInfo,hNorInfo->flashBase, AMD_CMD2_ADDR, AMD_PROG_CMD);
      LOCAL_flashWriteData(hNorInfo,address, data);
    
      // Wait for ready.
      while(TRUE)
      {
        if ( (LOCAL_flashReadData(hNorInfo, address, 0 ) & (BIT7 | BIT15) ) == (data & (BIT7 | BIT15) ) )
        {
          break;
        }
        else
        {
          if(LOCAL_flashIsSetAll(hNorInfo, address, 0, BIT5))
          {
            if ( (LOCAL_flashReadData(hNorInfo, address, 0 ) & (BIT7 | BIT15) ) != (data & (BIT7 | BIT15) ) )
            {
              DEBUG_printString("Timeout ocurred.\r\n");
              retval = E_FAIL;
            }
            break;				
          }
        }
      }
    	
      // Return Read Mode
    	AMD_SoftReset(hNorInfo);
    	
    	// Verify the data.
      if ( (retval == E_PASS) && ( LOCAL_flashReadData(hNorInfo, address, 0) != data) )
        retval = E_FAIL;
    	
    	return retval;
    }
    
    // AMD flash buffered write
    static Uint32 AMD_BufferWrite(NOR_InfoHandle hNorInfo, Uint32 address, VUint8 data[], Uint32 numBytes )
    {
      Uint32 startAddress = address;
      Uint32 blkAddress, blkSize;
      Uint32 data_temp;
      Uint32 retval = E_PASS;
      Uint32 shift;
      volatile NOR_Ptr pAddr, pData;
      VUint8* endAddress;
    	
      // Get block base address and size
      NOR_getBlockInfo(hNorInfo, address, &blkSize, &blkAddress);
    			
      // Write the Write Buffer Load command
      LOCAL_AMDPrefixCommands(hNorInfo);
      LOCAL_flashWriteCmd(hNorInfo, blkAddress, 0, AMD_WRT_BUF_LOAD_CMD);
            
      //Establish correct shift value
      shift = 0;
      while ((hNorInfo->busWidth >> shift) > 1)
        shift++;
        
      // Write Length (either numBytes or numBytes/2)	    
      LOCAL_flashWriteCmd(hNorInfo, blkAddress, 0, (numBytes >> shift) - 1);
    	
    	// Write Data
      pData.cp = (VUint8*) data;
      pAddr.cp = (VUint8*) address;
      endAddress =(VUint8*)(pAddr.cp + numBytes);
      while (pAddr.cp < endAddress)
      {
        switch (hNorInfo->busWidth)
        {
          case BUS_8BIT:
            *pAddr.cp++ = *pData.cp++;
            break;
          case BUS_16BIT:
            *pAddr.wp++ = *pData.wp++;
            break;
        }
      }
    
      // Put last data written at start of data buffer - For AMD verification
      switch (hNorInfo->busWidth)
      {
        case BUS_8BIT:
          address = (Uint32)(endAddress-1);
          break;
        case BUS_16BIT:
          address = (Uint32)(endAddress-2);
          break;
      }  
      
    		
      // Program Buffer to Flash Confirm Write
      LOCAL_flashWriteCmd(hNorInfo, blkAddress, 0, AMD_WRT_BUF_CONF_CMD);                  
    
      UTIL_waitLoop(1000);
        
      // Read last data item                  
      data_temp = LOCAL_flashReadData(hNorInfo, (Uint32) (data + (address - startAddress)), 0);
            
    	while(TRUE)
    	{
        if( (LOCAL_flashReadData(hNorInfo, address, 0 ) & (BIT7 | BIT15)) == (data_temp & (BIT7 | BIT15) ) )
        {
          break;
        }
        else
        {
          // Timeout has occurred
          if(LOCAL_flashIsSetAll(hNorInfo,address, 0, BIT5))
          {
            if( (LOCAL_flashReadData(hNorInfo,address, 0 ) & (BIT7 | BIT15)) != (data_temp & (BIT7 | BIT15) ) )
            {
              DEBUG_printString("Timeout ocurred.\r\n");
              retval = E_FAIL;
            }
            break;
          }
          // Abort has occurred
          if(LOCAL_flashIsSetAll(hNorInfo, address, 0, BIT1))
          {
            if( (LOCAL_flashReadData(hNorInfo, address, 0 ) & (BIT7 | BIT15)) != (data_temp & (BIT7 | BIT15) ) )
            {
              DEBUG_printString("Abort ocurred.\r\n");
              retval = E_FAIL;
              LOCAL_AMDWriteBufAbortReset (hNorInfo);
            }
            break;
          }
        }
      }
    	
      // Put chip back into read array mode.
      AMD_SoftReset(hNorInfo);
      if (retval == E_PASS)
      {
        retval = LOCAL_flashVerifyDataBuffer(hNorInfo, startAddress,(void*)data, numBytes);
        if (retval != E_PASS)
          DEBUG_printString("Data verify failed.\r\n");
      }
      return retval;
    }
    
    // AMD Write Buf Abort Reset Flash
    static void LOCAL_AMDWriteBufAbortReset(NOR_InfoHandle hNorInfo)
    {
      // Reset Flash to be in Read Array Mode
      LOCAL_AMDPrefixCommands(hNorInfo);
      AMD_SoftReset(hNorInfo);
    }
    
    // --------------------- End of AMD specific commands ------------------------
    
    
    /***********************************************************
    * End file                                                 *
    ***********************************************************/
    
    /*
     *  Copyright 2007 by Spectrum Digital Incorporated.
     *  All rights reserved. Property of Spectrum Digital Incorporated.
     */
    
    /*
     *  Flash Setup
     *
     */
    
    #include "evm6424_flash.h"
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _FLASH_init( )                                                          *
     *      Setup Flash                                                         *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 EVM6424_FLASH_init( )
    {
        Uint32 acfg2;
        Uint32 mfg;
        Uint16 width;
    
        /* Setup PinMux & EMIF for 16-bit mode */
        _clrPinMux( ( 0x0F << 0 ), 0 );
        _setPinMux( ( 0x02 << 0 ), 0 );
        _setupEMIF( EMIF_CS2, AEMIF_MAX_TIMEOUT_16BIT, EMIF_NORMAL_MODE );
        width = 1;
    
        /* Get the Flash MFG info */
        mfg = _FLASH_getMfg( );
    
        #ifdef USE_SPANSION
            /* -------------------------------------------------------- *
             *                                                          *
             *  SPANSION Flash memory                                   *
             *      EMIF @ 99MHz/10.1ns                                 *
             *                                                          *
             * -------------------------------------------------------- */
            if ( mfg == MFG_SPANSION )
            {
                acfg2 = 0
                    | ( 0 << 31 )           // selectStrobe
                    | ( 0 << 30 )           // extWait
                    | ( 0 << 26 )           // writeSetup      //   0 ns
                    | ( 3 << 20 )           // writeStrobe     //  35 ns
                    | ( 0 << 17 )           // writeHold       //   0 ns
                    | ( 0 << 13 )           // readSetup       //   0 ns
                    | ( 12 << 7 )           // readStrobe      // 110 ns
                    | ( 0 << 4 )            // readHold        //   0 ns
                    | ( 1 << 2 )            // turnAround      //  10 ns
                    | ( width << 0 )        // asyncSize       // 8/16-bit bus
                    ;
    
                _setupEMIF( EMIF_CS2, acfg2, EMIF_NORMAL_MODE );
    
                FLASH_BASE_PTR8 = FLASH_RESET;
            }
        #endif
    
        #ifdef USE_INTEL_MICRON
            /* -------------------------------------------------------- *
             *                                                          *
             *  Intel / Micron Flash memory                             *
             *      EMIF @ 99MHz/10.1ns                                 *
             *                                                          *
             * -------------------------------------------------------- */
            if ( ( mfg == MFG_INTEL ) || ( mfg == MFG_MICRON ) )
            {
                acfg2 = 0
                    | ( 0 << 31 )           // selectStrobe
                    | ( 0 << 30 )           // extWait
                    | ( 0 << 26 )           // writeSetup      //   0 ns
                    | ( 4 << 20 )           // writeStrobe     //  35 ns
                    | ( 0 << 17 )           // writeHold       //   0 ns
                    | ( 4 << 13 )           // readSetup       //  30 ns
                    | ( 12 << 7 )           // readStrobe      // 120 ns
                    | ( 0 << 4 )            // readHold        //   0 ns
                    | ( 1 << 2 )            // turnAround      //  10 ns
                    | ( width << 0 )        // asyncSize       // 8/16-bit bus
                    ;
    
                _setupEMIF( EMIF_CS2, acfg2, EMIF_NORMAL_MODE );
    
                _FLASH_unlockBlocks( FLASH_BASE, FLASH_END_OR_RANGE );
    
                FLASH_BASE_PTR8 = FLASH_READ_ARRAY;
            }
        #endif
    
        EVM6424_FLASH_getTotalPages( 1 );
    
        return 0;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _FLASH_unlockBlocks( )                                                  *
     *                                                                          *
     *      Flash unlock blocks ( Intel/Micron Flash )                          *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_INTEL_MICRON
        Int16 _FLASH_unlockBlocks( Uint32 start, Uint32 length )
        {
            Uint32 end = start + length - 1;
            Uint32 addr;
            volatile Uint16 *pblock;
    
            if ( ( _FLASH_getMfg( ) == MFG_INTEL )
              || ( _FLASH_getMfg( ) == MFG_MICRON ) )
            {
                for ( addr = start ; addr <= end ; addr = _FLASH_nextPage( addr ) )
                {
                    #if ( 0 )
                        pblock = ( volatile Uint16* )addr;
                        *pblock = FLASH_CONFIG_BLOCK_LOCK_BITS;      // Lock Setup
                        *pblock = FLASH_CLEAR_LOCK_BITS;             // Unlock Confirm
                        *pblock = FLASH_READ_ARRAY;                  // Read Mode
                    #else
                        do /* Optional unlock + check */
                        {
                            pblock = ( volatile Uint16* )addr;
                            *pblock = FLASH_CONFIG_BLOCK_LOCK_BITS;  // Lock Setup
                            *pblock = FLASH_CLEAR_LOCK_BITS;         // Lock Confirm
                            *pblock = FLASH_READ_ID;                 // Read Device ID
                            pblock = ( volatile Uint16* )( addr + 2 );// Read Status
                        } while ( ( *pblock & 0x03 ) != 0 );
                        *pblock = FLASH_READ_ARRAY;                  // Read Mode
                        *pblock = FLASH_CLEAR_STATUS;                // Clear status reg
                    #endif
                }
            }
            return 0;
        }
    #endif
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _FLASH_waitWhileBusy( )                                                 *
     *                                                                          *
     *      Wait for the Busy bit ( Intel/Micron Flash )                        *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_INTEL_MICRON
        Int16 _FLASH_waitWhileBusy( Int32 timeout )
        {
            if ( ( _FLASH_getMfg( ) == MFG_INTEL )
              || ( _FLASH_getMfg( ) == MFG_MICRON ) )
            {
                /* Read Status Register */
                FLASH_BASE_PTR8 = FLASH_READ_STATUS;
    
                while ( timeout-- > 0 )
                {
                    /*
                     *  The most important bit in the status is the busy bit.
                     *  When asserted the operation is done.
                     */
                    if ( ( FLASH_BASE_PTR16 & 0x0080 )
                      || ( FLASH_BASE_PTR16 & 0x8000 ) )
                    {
                        /*
                         *  Check for any errors
                         */
                        if ( ( ( FLASH_BASE_PTR16 & 0x007F ) != 0 )
                          || ( ( FLASH_BASE_PTR16 & 0x7F00 ) != 0 ) )
                        {
                            /* Bad, operation finished w/ errors */
                            FLASH_BASE_PTR16 = FLASH_READ_ARRAY;
                            return -1;
                        }
                        else
                        {
                            /* Good, operation is finished w/o errors */
                            FLASH_BASE_PTR16 = FLASH_READ_ARRAY;
                            return 0;
                        }
                    }
                }
    
                /* Timeout occured */
                FLASH_BASE_PTR8 = FLASH_READ_ARRAY;
            }
            return 1;
        }
    #endif
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _FLASH_waitWhileErasing( )                                              *
     *                                                                          *
     *      Wait while erasing ( SPANSION Flash )                               *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_SPANSION
        Int16 _FLASH_waitWhileErasing( Uint32 addr, Int32 timeout )
        {
            Uint8* pdata = ( Uint8* )addr;
    
            if ( _FLASH_getMfg( ) == MFG_SPANSION )
            {
                while ( timeout-- > 0 )
                    if ( *pdata == 0xFF )
                        /* Good, erase completed */
                        return 0;
    
                /* Timeout occured */
                FLASH_BASE_PTR8 = FLASH_RESET;
                return 1;
            }
            return -1;
        }
    #endif
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _FLASH_waitWhileProgramming( )                                          *
     *                                                                          *
     *      Wait while programming ( SPANSION Flash )                           *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_SPANSION
        Int16 _FLASH_waitWhileProgramming( Uint32 addr, Uint16 data, Int32 timeout )
        {
            Uint16* pdata = ( Uint16* )addr;
    
            if ( _FLASH_getMfg( ) == MFG_SPANSION )
            {
                while ( timeout-- > 0 )
                    if ( *pdata == data )
                        /* Good, programming completed */
                        return 0;
    
                /* Timeout occured */
                FLASH_BASE_PTR8 = FLASH_RESET;
                return 1;
            }
            return -1;
        }
    #endif
    
    /*
     *  Copyright 2007 by Spectrum Digital Incorporated.
     *  All rights reserved. Property of Spectrum Digital Incorporated.
     */
    
    /*
     *  NAND Flash interface
     *
     */
    
    #include "evm6424_nandflash.h"
    
    /*
     *  Invalid Block & Page list
     */
    static Uint16 invalid_blk_count = 0;
    static Uint16 invalid_blks[80];
    
    static Uint16 invalid_pg_count = 0;
    static Uint16 invalid_pgs[80];
    
    /*
     *  NAND Flash timeout
     */
    static Uint32 nand_timeout = ( 0x00100000 );
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NAND_readECC( )                                                        *
     *                                                                          *
     *      Read ECC calcualtions                                               *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_ECC
        inline Uint32 _NAND_readECC( void )
        {
            return AEMIF_NANDECC2;
        }
    #endif
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NAND_startECC( )                                                       *
     *                                                                          *
     *      Start ECC calcualtions                                              *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    #ifdef USE_ECC
        inline void _NAND_startECC( void )
        {
            _NAND_readECC( );
            AEMIF_NANDFCR |= 0x0100;
        }
    #endif
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NAND_getBadPages( pages )                                              *
     *                                                                          *
     *      Get the last invaild pages                                          *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    void _NAND_getBadPages( Uint32* pages )
    {
        Int16 i;
        for ( i = 0 ; invalid_pg_count ; i++ )
            pages[i] = invalid_pgs[i];
    
        if ( invalid_pg_count == 0 )
            pages[0] = 0;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NAND_getBadBlocks( blocks )                                            *
     *                                                                          *
     *      Get the last invaild blocks                                         *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    void _NAND_getBadBlocks( Uint32* blocks )
    {
        Int16 i;
        for ( i = 0 ; invalid_blk_count ; i++ )
            blocks[i] = invalid_blks[i];
    
        if ( invalid_blk_count == 0 )
            blocks[0] = 0;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NAND_busywait( timeout )                                               *
     *                                                                          *
     *      Poll the external RDY/BSY pin                                       *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 _NAND_busywait( Int32 timeout )
    {
        /*
         *  Short delay to let the Ready/Busy signal go LOW
         */
        _wait( 200 );
    
        /*
         *  Wait while the device is busy
         */
        while( ( ! NAND_READ_RB ) && ( timeout-- > 0 ) );
    
        if ( timeout == 0 )
            return NAND_ERR_TIMEOUT;
        else
            return 0;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NANDFLASH_init( )                                                      *
     *      Initialize the NAND Flash                                           *
     *                                                                          *
     *  Note:                                                                   *
     *      The Write Protect on the NAND Flash is disabled.  This allows the   *
     *      erase & write NAND flash to work.                                   *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 EVM6424_NANDFLASH_init( )
    {
        /*------------------------------------------------------------------*
         *                                                                  *
         *  NAND Flash timing parameters                                    *
         *                                                                  *
         *      EMIF.CLK freq   = PLL1/6 = 594/6 = 99 MHz                   *
         *      EMIF.CLK period = 1/99 MHz = 10.1 ns                        *
         *                                                                  *
         *------------------------------------------------------------------*/
        Uint32 acfg2 = 0
                | ( 0 << 31 )           // selectStrobe
                | ( 0 << 30 )           // extWait
                | ( 0 << 26 )           // writeSetup      //   0 ns
                | ( 8 << 20 )           // writeStrobe     //  40 ns
                | ( 2 << 17 )           // writeHold       //  10 ns
                | ( 0 << 13 )           // readSetup       //   0 ns
                | ( 6 << 7 )            // readStrobe      //  25 ns
                | ( 2 << 4 )            // readHold        //  10 ns
                | ( 2 << 2 )            // turnAround      //  10 ns
                | ( 0 << 0 );           // asyncSize       //  8-bit bus
    
        _resetEMIF( EMIF_CS2 );
        _setupEMIF( EMIF_CS2, acfg2, EMIF_NAND_MODE );
    
        /* ---------------------------------------------------------------- *
         *                                                                  *
         *  Note: If NANDFLASH_CE_DO_CARE is defined, then CE will be low   *
         *        during read/write/erase operations.                       *
         *                                                                  *
         *        Else if NANDFLASH_CE_DO_NOT_CARE is defined, then CE will *
         *        only be low during accesses to the NAND Flash device.     *
         *                                                                  *
         * ---------------------------------------------------------------- */
    
      //NAND_ASSERT_CE( );                  // Assert CE ( for CE-care devices )
    
        NAND_CMD( CMD_RESET );              // Reset NAND Flash
    
        if ( _NAND_busywait( nand_timeout ) )// Wait while busy
            return NAND_ERR_TIMEOUT;
    
      //NAND_DEASSERT_CE( );                // Deassert CE ( for CE-care devices )
    
        return 0;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NANDFLASH_getTotalPages( )                                             *
     *                                                                          *
     *      Determine the total number of pages of NAND Flash                   *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Uint32 EVM6424_NANDFLASH_getTotalPages( )
    {
        Uint8 mfg_id;
        Uint8 dev_id;
        Uint32 pages = 0;
    
      //NAND_ASSERT_CE( );                  // Assert CE ( for CE-care devices )
    
        NAND_CMD( CMD_READID );             // Issue Read ID command
        NAND_ADDR_1( 0 );
    
        mfg_id = NAND_DATA;                 // Read MFG Id
        dev_id = NAND_DATA;                 // Read Device Id
    
        /*
         *  Compared MFG ID & Device ID to the supported devices
         */
        if ( mfg_id == MFG_SAMSUNG )
        {
            switch ( dev_id )
            {
                case DEV_K9F5608U0B:
                    pages = DEV_K9F5608U0B_PAGE_COUNT;
                    break;
    
                case DEV_K9F5608Q0B:
                    pages = DEV_K9F5608Q0B_PAGE_COUNT;
                    break;
    
                case DEV_K9F2808U0C:
                    pages = DEV_K9F2808U0C_PAGE_COUNT;
                    break;
    
                case DEV_K9K1208Q0C:
                    pages = DEV_K9K1208Q0C_PAGE_COUNT;
                    break;
            }
        }
        else if ( mfg_id == MFG_STI )
        {
            switch( dev_id )
            {
                case DEV_NAND512W3A:
                    pages = DEV_NAND512W3A_PAGE_COUNT;
                    break;
            }
        }
    
      //NAND_DEASSERT_CE( );                // Deassert CE ( for CE-care devices )
    
        return pages;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NANDFLASH_erase( start, block_count )                                  *
     *                                                                          *
     *      Erase the blocks of Flash memory                                    *
     *          start = destination address [ block address ]                   *
     *          block_count = # of blocks   [ 1 block = 16384 bytes ]           *
     *                                                                          *
     *      Returns:    0   pass                                                *
     *                  1+  failed - bad blocks                                 *
     *                 -1   timeout                                             *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 EVM6424_NANDFLASH_erase( Uint32 start, Uint32 block_count )
    {
        Uint32 i;
    
        invalid_blk_count = 0;
    
        for ( i = 0 ; i < block_count ; i++ )
        {
          //NAND_ASSERT_CE( );              // Assert CE ( for CE-care devices )
    
            NAND_CMD( CMD_ERASE );          // Erase block
            NAND_ADDR_3( start );
            NAND_CMD( CMD_ERASE_CONFIRM );  // Confirm Erase
    
            if ( _NAND_busywait( nand_timeout ) )
            {
              //NAND_DEASSERT_CE( );        // Deassert CE ( for CE-care devices )
                return NAND_ERR_TIMEOUT;    // Timeout Error
            }
    
            NAND_CMD( CMD_STATUS );         // Check Status
    
            if ( NAND_DATA & CMD_STATUS_ERROR )
                invalid_blks[invalid_blk_count++] = start;
    
          //NAND_DEASSERT_CE( );            // Deassert CE ( for CE-care devices )
    
            start += NAND_BLOCKSIZE;        // Increment address
        }
        return invalid_blk_count;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NANDFLASH_readPage( src, dst, page_count )                             *
     *                                                                          *
     *      Read data from NAND Flash by pages ( 512 bytes )                    *
     *                                                                          *
     *          src = source address      [ must be aligned to start of page ]  *
     *          dst = destination address [ any address ]                       *
     *          page_count = # of pages   [ a page is 512 bytes ]               *
     *                                                                          *
     *      Note does not return spare array data                               *
     *                                                                          *
     *      Returns:    0   pass                                                *
     *                  1+  failed - bad pages                                  *
     *                 -1   timeout                                             *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 EVM6424_NANDFLASH_readPage( Uint32 src, Uint32 dst, Uint32 page_count )
    {
        Uint32 i, j;
        volatile Uint8* dst8 = ( volatile Uint8* )dst;
        Uint8 spare[NAND_SPARESIZE];
    
        #ifdef USE_ECC
            Uint32 computed_ecc;
            Uint8  spare_ecc[4];
            Uint32 spare_ecc32;
        #endif
    
        invalid_pg_count = 0;
    
        for ( i = 0 ; i < page_count ; i++ )
        {
          //NAND_ASSERT_CE( );              // Assert CE ( for CE-care devices )
    
            NAND_CMD( CMD_READ );           // Read page
            NAND_ADDR_4( src );
    
            if ( _NAND_busywait( nand_timeout ) )
            {
              //NAND_DEASSERT_CE( );        // Deassert CE ( for CE-care devices )
                return NAND_ERR_TIMEOUT;    // Timeout Error
            }
    
            #ifdef USE_ECC
                _NAND_startECC( );          // Start ECC
            #endif
    
            j = NAND_PAGESIZE;
            while ( j-- )
                *dst8++ = NAND_DATA;        // Read MAIN array
    
            #ifdef USE_ECC
                computed_ecc = _NAND_readECC( ); // Read computed ECC
                computed_ecc &= 0x0FFF0FFF;
            #endif
    
            for ( j = 0 ; j < NAND_SPARESIZE ; j++ )
                spare[j] = NAND_DATA;       // Read SPARE leftovers
    
            #ifdef USE_ECC
                for ( j = 0 ; j < 4 ; j++ )
                    spare_ecc[j] = spare[j];// Read SPARE ECC
    
                spare_ecc32 = *( Uint32* )( &spare_ecc[0] );
                spare_ecc32 &= 0x0FFF0FFF;
    
                if ( spare_ecc32 != computed_ecc )// Compare ECCs
                    invalid_pgs[invalid_pg_count++] = src;
            #endif
    
          //NAND_DEASSERT_CE( );            // Deassert CE ( for CE-care devices )
    
            src += NAND_PAGESIZE;           // Increment address
        }
    
        return invalid_pg_count;
    }
    
    /* ------------------------------------------------------------------------ *
     *                                                                          *
     *  _NANDFLASH_writePage( src, dst, page_count )                            *
     *                                                                          *
     *      Program NAND Flash.                                                 *
     *          src = source address      [ any address ]                       *
     *          dst = destination address [ must be aligned to start of page ]  *
     *          page_count = # of pages   [ a page is 512 bytes ]               *
     *                                                                          *
     *      Note does not program SPARE arrays                                  *
     *                                                                          *
     *      Returns:    0   pass                                                *
     *                  1+  failed - bad pages                                  *
     *                 -1   timeout                                             *
     *                                                                          *
     * ------------------------------------------------------------------------ */
    Int16 EVM6424_NANDFLASH_writePage( Uint32 src, Uint32 dst, Uint32 page_count )
    {
        Uint32 i, j = 0;
        volatile Uint8* src8 = ( volatile Uint8* )src;
    
        #ifdef USE_ECC
            Uint32 computed_ecc;
        #endif
    
        invalid_pg_count = 0;
    
        for ( i = 0 ; i < page_count ; i++ )
        {
          //NAND_ASSERT_CE( );              // Assert CE ( for CE-care devices )
    
            NAND_CMD( CMD_PROGRAM );        // Program page
            NAND_ADDR_4( dst );
    
            #ifdef USE_ECC
                _NAND_startECC( );          // Start ECC calculation
            #endif
    
            j = NAND_PAGESIZE;
            while ( j-- )                   // Write main array
                NAND_DATA = *src8++;
    
            #ifdef USE_ECC
                computed_ecc = _NAND_readECC( ); // Read computed ECC
                computed_ecc &= 0x0FFF0FFF;
    
                NAND_DATA = ( computed_ecc >> 24 );
                NAND_DATA = ( computed_ecc >> 16 );
                NAND_DATA = ( computed_ecc >> 8 );
                NAND_DATA = ( computed_ecc );
            #endif
    
            j = NAND_SPARESIZE - 4;
            while ( j-- );                  // Write Spare array
                NAND_DATA = 0xFF;
    
            NAND_CMD( CMD_PROGRAM_CONFIRM );// Confirm Program
    
            if ( _NAND_busywait( nand_timeout ) )
            {
              //NAND_DEASSERT_CE( );        // Deassert CE ( for CE-care devices )
                return NAND_ERR_TIMEOUT;    // Timeout Error
            }
    
            NAND_CMD( CMD_STATUS );         // Check erase status
    
            if ( NAND_DATA & CMD_STATUS_ERROR )
                invalid_pgs[invalid_pg_count++] = dst;
    
          //NAND_DEASSERT_CE( );            // Deassert CE ( for CE-care devices )
    
            dst += NAND_PAGESIZE;           // Increment address
        }
    
        return invalid_pg_count;
    }
    

  • Hi Abdalla,
    Do you want to update the DSP boot firmware or need to upgrade ?
    If upgrade, then how did you flash initially to the DSP ?
    Can we connect emulator to the board ?
    BTW, which board are you using ?
    Custom or EVM ?
    I presume that you are using custom board since you said MSP uC is available on your board.
  • Hi Titus S.
    I want to upgrade the application that running in the DSP ( stored in the flash ).
    Initialy we planed to perform the first program by jtag and then the jtag burned. So the only interface available in our product is the UART which is connected to the MSP430 . Currently we use EVM6424 ( our final hardware not ready yet so we need to test all the software in the evm board before we shift to the real hardware ) .
  • Hi abdalla,

    From PC to MSP430, you can use

    To communicate between the MSP430 and the DSP, you have to write your own code.

    It is good to refer the NAND / NOR writer of OMAPL138, but it has C6748 as DSP core. But you use C6424 as DSP core.

    I.e. you can run C64x object code on the C64x+, C674x, and the C66x. You cannot go in the reverse direction, i.e, you can't run C674x object code on the C64x.

    To use the NAND / NOR writer of C6748 code for C424, you will have a porting effort like checking the memory map, reigister settings e.t.c. for C6424.

    ---

  • Thanks you Shankari

    We already implement our own communication protocol between the MSP430 and the EVM6424 and we transfer data/command properly.
    I want to know if there are any library or Ti open source code that can help me to perform parsing to the image ,check the integrity and write it to the NAND/NOR

    Regards
    Abdalla.
  • Hi all
    In testing i used flash burn tool from software design solution to burn the hex image into the board flash but after production i able to use the UART interface only so i need to do the flash burn job in my code ( write the hex file into board flash ). that is exactly what i ask about

    Regards
    Abdalla.