/** * @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); }
//----------------------------------------------------------------------------- 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; }