/**
  * @brief  This routine erase complete block from NAND FLASH
  * @param  Address: Any address into block to be erased
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  */
uint32_t NAND_EraseBlock(NAND_ADDRESS Address)
{
  *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE0;

  *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
  *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);
  *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_3rd_CYCLE(ROW_ADDRESS);

  *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE1; 

  return (NAND_GetStatus());
}
/**
  * @brief  This routine write the spare area information for the specified
  *         pages addresses.  
  * @param  pBuffer: pointer on the Buffer containing data to be written 
  * @param  Address: First page address
  * @param  NumSpareAreaTowrite: Number of Spare Area to write
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  *                And the new status of the increment address operation. It can be:
  *              - NAND_VALID_ADDRESS: When the new address is valid address
  *              - NAND_INVALID_ADDRESS: When the new address is invalid address
  */
uint32_t NAND_WriteSpareArea(uint8_t * pBuffer, NAND_ADDRESS Address,
			     uint32_t NumSpareAreaTowrite)
{
	uint32_t index = 0x00, numsparesreawritten = 0x00, addressstatus =
	    NAND_VALID_ADDRESS;
	uint32_t status = NAND_READY, size = 0x00;

	while ((NumSpareAreaTowrite != 0x00)
	       && (addressstatus == NAND_VALID_ADDRESS)
	       && (status == NAND_READY)) {
		/*!< Page write Spare area command and address */
		*(__IO uint8_t *) (Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_C;
		*(__IO uint8_t *) (Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;

		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) = 0x00;
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_1st_CYCLE(ROW_ADDRESS);
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_2nd_CYCLE(ROW_ADDRESS);
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_3rd_CYCLE(ROW_ADDRESS);

		/*!< Calculate the size */
		size =
		    NAND_SPARE_AREA_SIZE +
		    (NAND_SPARE_AREA_SIZE * numsparesreawritten);

		/*!< Write the data */
		for (; index < size; index++) {
			*(__IO uint8_t *) (Bank_NAND_ADDR | DATA_AREA) =
			    pBuffer[index];
		}

		*(__IO uint8_t *) (Bank_NAND_ADDR | CMD_AREA) =
		    NAND_CMD_WRITE_TRUE1;

		/*!< Check status for successful operation */
		status = NAND_GetStatus();

		if (status == NAND_READY) {
			numsparesreawritten++;

			NumSpareAreaTowrite--;

			/*!< Calculate Next page Address */
			addressstatus = NAND_AddressIncrement(&Address);
		}
	}

	return (status | addressstatus);
}
/**
  * @brief  This routine erase complete block from NAND FLASH
  * @param  Address: Any address into block to be erased
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  */
uint32_t NAND_EraseBlock(NAND_ADDRESS Address)
{
  *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE0;

  //*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
  *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
  *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);

  *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE1; 

  /* 读忙脚, 等待直到空闲 */
  while(NAND_FLASH_BUZY);
  
  return (NAND_GetStatus());
}
/**
  * @brief  This routine is for writing one or several 512 Bytes Page size.
  * @param  pBuffer: pointer on the Buffer containing data to be written 
  * @param  Address: First page address
  * @param  NumPageToWrite: Number of page to write  
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  *                And the new status of the increment address operation. It can be:
  *              - NAND_VALID_ADDRESS: When the new address is valid address
  *              - NAND_INVALID_ADDRESS: When the new address is invalid address  
  */
uint32_t NAND_WriteSmallPage(uint8_t *pBuffer, NAND_ADDRESS Address, uint32_t NumPageToWrite)
{
  uint32_t index = 0x00, numpagewritten = 0x00, addressstatus = NAND_VALID_ADDRESS;
  uint32_t status = NAND_READY, size = 0x00;

  while((NumPageToWrite != 0x00) && (addressstatus == NAND_VALID_ADDRESS) && (status == NAND_READY))
  {
    /*!< Page write command and address */
    //*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_A;
    *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;
   
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00; 
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00; 
	*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);

    /*!< Calculate the size */
    size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpagewritten);

    /* 读忙脚, 等待直到空闲 */
    while(NAND_FLASH_BUZY);

    /*!< Write data */
    for(; index < size; index++)
    {
      *(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA) = pBuffer[index];
    }
    
    *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE_TRUE1;

    /*!< Check status for successful operation */
    status = NAND_GetStatus();
    
    if(status == NAND_READY)
    {
      numpagewritten++;

      NumPageToWrite--;

      /*!< Calculate Next small page Address */
      addressstatus = NAND_AddressIncrement(&Address);
    }
  }
  
  return (status | addressstatus);
}
/**
  * @brief  This routine read the spare area information from the specified
  *         pages addresses.  
  * @param  pBuffer: pointer on the Buffer to fill 
  * @param  Address: First page address
  * @param  NumSpareAreaToRead: Number of Spare Area to read
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  *                And the new status of the increment address operation. It can be:
  *              - NAND_VALID_ADDRESS: When the new address is valid address
  *              - NAND_INVALID_ADDRESS: When the new address is invalid address
  */
uint32_t NAND_ReadSpareArea(uint8_t * pBuffer, NAND_ADDRESS Address,
			    uint32_t NumSpareAreaToRead)
{
	uint32_t numsparearearead = 0x00, index = 0x00, addressstatus =
	    NAND_VALID_ADDRESS;
	uint32_t status = NAND_READY, size = 0x00;

	while ((NumSpareAreaToRead != 0x0)
	       && (addressstatus == NAND_VALID_ADDRESS)) {
		/*!< Page Read command and page address */
		*(__IO uint8_t *) (Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_C;

		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) = 0x00;
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_1st_CYCLE(ROW_ADDRESS);
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_2nd_CYCLE(ROW_ADDRESS);
		*(__IO uint8_t *) (Bank_NAND_ADDR | ADDR_AREA) =
		    ADDR_3rd_CYCLE(ROW_ADDRESS);

		/*!< Data Read */
		size =
		    NAND_SPARE_AREA_SIZE +
		    (NAND_SPARE_AREA_SIZE * numsparearearead);

		/*!< Get Data into Buffer */
		for (; index < size; index++) {
			pBuffer[index] =
			    *(__IO uint8_t *) (Bank_NAND_ADDR | DATA_AREA);
		}

		numsparearearead++;

		NumSpareAreaToRead--;

		/*!< Calculate page address */
		addressstatus = NAND_AddressIncrement(&Address);
	}

	status = NAND_GetStatus();

	return (status | addressstatus);
}
/**
  * @brief  This routine is for sequential read from one or several 512 Bytes Page size.
  * @param  pBuffer: pointer on the Buffer to fill
  * @param  Address: First page address
  * @param  NumPageToRead: Number of page to read  
  * @retval New status of the NAND operation. This parameter can be:
  *              - NAND_TIMEOUT_ERROR: when the previous operation generate 
  *                a Timeout error
  *              - NAND_READY: when memory is ready for the next operation 
  *                And the new status of the increment address operation. It can be:
  *              - NAND_VALID_ADDRESS: When the new address is valid address
  *              - NAND_INVALID_ADDRESS: When the new address is invalid address
  */
uint32_t NAND_ReadSmallPage(uint8_t *pBuffer, NAND_ADDRESS Address, uint32_t NumPageToRead)
{
  uint32_t index = 0x00, numpageread = 0x00, addressstatus = NAND_VALID_ADDRESS;
  uint32_t status = NAND_READY, size = 0x00;

  while((NumPageToRead != 0x0) && (addressstatus == NAND_VALID_ADDRESS))
  {
    /*!< Page Read command and page address */
    *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_A;
   
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00; 
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00; 
	*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
    *(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);
    
    *(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_AREA_TRUE1;
	 
    /*!< Calculate the size */
    size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpageread);

    /* 读忙脚, 等待直到空闲 */
    while(NAND_FLASH_BUZY);
	   
    /*!< Get Data into Buffer */    
    for(; index < size; index++)
    {
      pBuffer[index]= *(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA);
    }

    numpageread++;
    
    NumPageToRead--;

    /*!< Calculate page address */
    addressstatus = NAND_AddressIncrement(&Address);
  }

  status = NAND_GetStatus();
  
  return (status | addressstatus);
}
Beispiel #7
0
//-----------------------------------------------------------------------------
HANDLE 
NAND_Initialize(
    LPCTSTR szContext,
    PCI_REG_INFO *pRegIn,
    PCI_REG_INFO *pRegOut
    )
{
    DWORD chipSelect = BSPGetNandCS();
    const NAND_INFO *  pBSPNandInfo;
    HANDLE hDevice = NULL;
    UINT ffPrefetchMode = 0;
    UINT8 manufacturer, device;
    NandDevice_t *pDevice = &s_Device;
#ifndef BOOT_MODE    
    DWORD dwKernelRet;
#endif

    UNREFERENCED_PARAMETER(pRegOut);
    UNREFERENCED_PARAMETER(szContext);
    // initialize structure
    memset(pDevice, 0, sizeof(NandDevice_t));

#ifdef BOOT_MODE    
    pDevice->pGpmcRegs = (OMAP_GPMC_REGS*)OALPAtoUA(SOCGetGPMCAddress(0));
    pDevice->pFifo = (NANDREG*)OALPAtoUA(pRegIn->MemBase.Reg[0]);

    /* Get ECC mode from BootCfg */
    pDevice->ECCtype = g_ecctype;
    if((pDevice->ECCtype > BCH8bit) || (pDevice->ECCtype < Hamming1bit))
    	{
            pDevice->ECCtype = Hamming1bit;
            RETAILMSG(TRUE, (L"Incorrect ECC type setting\r\n"));			
    	}
#else    
    if (szContext != NULL)
	{
        if (InitializePointers(szContext, pDevice) == FALSE) goto cleanUp;
	}
    else
	{
        PHYSICAL_ADDRESS pa;
        
        // if there's not context string then use global macros

        pa.QuadPart = pRegIn->MemBase.Reg[0];
        pDevice->memLen[0] = pRegIn->MemLen.Reg[0];
        pDevice->pGpmcRegs = MmMapIoSpace(pa, pDevice->memLen[0], FALSE);
        if (pDevice->pGpmcRegs == NULL) goto cleanUp;

        pa.QuadPart = pRegIn->MemBase.Reg[1];
        pDevice->memLen[1] = pRegIn->MemLen.Reg[1];
        pDevice->pFifo = MmMapIoSpace(pa, pDevice->memLen[1], FALSE);
        if (pDevice->pGpmcRegs == NULL) goto cleanUp;

	}

	if (!KernelIoControl(IOCTL_HAL_GET_ECC_TYPE, NULL, 0, &pDevice->ECCtype, sizeof(DWORD), &dwKernelRet))
	{
		RETAILMSG( TRUE,(TEXT("Failed to read Ecc type\r\n")));
		pDevice->ECCtype = Hamming1bit;
	}   
	
	RETAILMSG(TRUE, (L"ECC TYPE is %s\r\n", (pDevice->ECCtype==Hamming1bit)? L"Hamming 1 bit" :
									(pDevice->ECCtype==BCH4bit)? L"BCH 4 bit" : L"BCH 8 bit"));
	
#endif

    pDevice->pNandCmd = (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_COMMAND_0) + (0x30 * chipSelect));
    pDevice->pNandAddress= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_ADDRESS_0) + (0x30 * chipSelect));
    pDevice->pNandData= (NANDREG*)((UINT32)pDevice->pGpmcRegs + offset(OMAP_GPMC_REGS, GPMC_NAND_DATA_0) + (0x30 * chipSelect));
    // Enable GPMC wait-to-nowait edge detection mechanism on NAND R/B pin
    NAND_Enable(pDevice, TRUE);

    // Write RESET command
    // (a reset aborts any current READ, WRITE (PROGRAM) or ERASE operation)
    NAND_SendCommand(pDevice, NAND_CMD_RESET);

    // Wait for NAND
    while ((NAND_GetStatus(pDevice) & NAND_STATUS_READY) == 0);

    // Send Read ID Command
    NAND_SendCommand(pDevice, NAND_CMD_READID);

    // Send Address 00h
    WRITE_NAND(pDevice->pNandAddress, 0);

    // Read the manufacturer ID & device code
    manufacturer = (UINT8)READ_NAND(pDevice->pNandData);
    device = (UINT8)READ_NAND(pDevice->pNandData);

 
    if ((pBSPNandInfo = BSPGetNandInfo(manufacturer,device))==NULL)
    {                
        goto cleanUp;
    }
    if ((pBSPNandInfo->sectorSize != 2048) && (pBSPNandInfo->wordData != 2))
    {
        ERRORMSG(1,(TEXT("FMD driver supports only 16bits large page (2KB) devices\r\n")));
        goto cleanUp;
    }
    pDevice->nandInfo = *pBSPNandInfo;

    pDevice->IrqWait = BSPGetNandIrqWait();

    /* ECCCfg: 16bit bus width, cs0, 4 - 512 bytes blocks per page */
    pDevice->ECCCfg = (GPMC_ECC_CONFIG_16BIT | (chipSelect << 1) | (0x3<<4)); 
    pDevice->ECCsize = (pDevice->ECCtype == Hamming1bit ) ? ECC_BYTES_HAMMING : 
		                      (pDevice->ECCtype == BCH4bit ) ? ECC_BYTES_BCH4 : ECC_BYTES_BCH8; 
							  
    //  Enable and reset ECC engine (workaround for engine giving 0s first time)
    ECC_Init(pDevice->pGpmcRegs, pDevice->ECCCfg, pDevice->ECCtype, NAND_ECC_READ);
    ECC_Reset(pDevice->pGpmcRegs);

    //  Only enable during NAND read/write/erase operations
    NAND_Enable(pDevice, FALSE);

    // configure the prefetch engine
    pDevice->prefetchMode = kPrefetchOff;
    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONTROL, 0);

    // set prefetch mask
    ffPrefetchMode = GPMC_PREFETCH_CONFIG_SYNCHROMODE |
                     GPMC_PREFETCH_CONFIG_PFPWENROUNDROBIN |
                     GPMC_PREFETCH_CONFIG_ENABLEOPTIMIZEDACCESS |
                     GPMC_PREFETCH_CONFIG_WAITPINSELECTOR(chipSelect) |
                     GPMC_PREFETCH_CONFIG_FIFOTHRESHOLD(FIFO_THRESHOLD) |
                     GPMC_PREFETCH_CONFIG_ENGINECSSELECTOR(chipSelect);

    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, ffPrefetchMode);

    // configure prefetch engine
    OUTREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG2, 
        pBSPNandInfo->sectorSize
        );
        
    SETREG32(&pDevice->pGpmcRegs->GPMC_PREFETCH_CONFIG1, 
        GPMC_PREFETCH_CONFIG_ENABLEENGINE
        );

    // We are done
    hDevice = pDevice;

cleanUp:
    return hDevice;
}