/** * \brief This function check if the Nandflash has an embedded ECC controller. * \return 0: ONFI not compliant or internal ECC not supported. 1: Internal ECC enabled. */ uint8_t NandEnableInternalEcc (void) { OnfiPageParam *pOnfiPageParameter; pOnfiPageParameter = NandGetCurrentOnfiInstance(); if (pOnfiPageParameter->onfiCompatiable == 1) { /* Check if the Nandflash has an embedded ECC controller Known memories with this feature : - Manufacturer ID = 2Ch (Micron) - Number of bits ECC = 04h (4-bit ECC means process 34nm) - device size = 1Gb or 2Gb or 4Gb (Number of data bytes per page * Number of pages per block * Number of blocks per unit) */ if ( ((pOnfiPageParameter->manufacturerId & NAND_MFR_MICRON) == NAND_MFR_MICRON) && (pOnfiPageParameter->onfiEccCorrectability == 0x4) && ((pOnfiPageParameter->onfiDeviceModel == '1') // 1G, || (pOnfiPageParameter->onfiDeviceModel == '2') // 2G || (pOnfiPageParameter->onfiDeviceModel == '4'))) { // or 4G bits /* then activate the internal ECC controller */ WRITE_NAND_COMMAND(NAND_CMD_SET_FEATURE, EBI_NF_ADDR); WRITE_NAND_ADDRESS(0x90, EBI_NF_ADDR); WRITE_NAND(0x08, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); WRITE_NAND(0x00, EBI_NF_ADDR); NandSwitchEcc(ECC_INTERNAL); return 1; } } return 0; }
//----------------------------------------------------------------------------- __inline void SectorAccess( NandDevice_t* pDevice, SECTOR_ADDR sector, UINT offset ) { // Offset is provided to this function in bytes; NAND device requires words offset = offset / 2; WRITE_NAND(pDevice->pNandAddress, (offset & 0xFF)); WRITE_NAND(pDevice->pNandAddress, ((offset >> 8) & 0xFF)); WRITE_NAND(pDevice->pNandAddress, (sector & 0xFF)); WRITE_NAND(pDevice->pNandAddress, ((sector >> 8) & 0xFF)); WRITE_NAND(pDevice->pNandAddress, ((sector >> 16) & 0xFF)); }
/*! \fn void ifx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) \ingroup IFX_NAND_DRV \brief write buffer to chip \param mtd MTD device structure \param buf data buffer \param len number of bytes to write \return none */ static void ifx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { int i; //struct nand_chip *chip = mtd->priv; for (i = 0; i < len; i++) WRITE_NAND(buf[i]); // writeb(buf[i], chip->IO_ADDR_W); }
//----------------------------------------------------------------------------- __inline void BlockAccess( NandDevice_t* pDevice, BLOCK_ID blockId ) { blockId *= pDevice->nandInfo.sectorsPerBlock; WRITE_NAND(pDevice->pNandAddress, (blockId & 0xFF)); WRITE_NAND(pDevice->pNandAddress, ((blockId >> 8) & 0xFF)); WRITE_NAND(pDevice->pNandAddress, ((blockId >> 16) & 0xFF)); }
static void upmnand_write_byte(struct mtd_info *mtdinfo, u_char byte) { struct nand_chip *this = mtdinfo->priv; ulong base = (ulong) (this->IO_ADDR_W + chipsel * CONFIG_SYS_NAND_CS_DIST); if (hwctl & 0x1) { WRITE_NAND_UPM(byte, base, CONFIG_SYS_NAND_UPM_WRITE_CMD_OFS); } else if (hwctl & 0x2) { WRITE_NAND_UPM(byte, base, CONFIG_SYS_NAND_UPM_WRITE_ADDR_OFS); } else { WRITE_NAND(byte, base); } }
bool onfi_embeddedecc(FAR const struct onfi_pgparam_s *onfi, uintptr_t cmdaddr, uintptr_t addraddr, uintptr_t dataaddr, bool enable) { /* Does the NAND supported the embedded ECC function? */ if (onfi_have_embeddedecc(onfi)) { /* Yes... enable or disable it */ /* Perform common setup */ WRITE_NAND_COMMAND(NAND_CMD_SET_FEATURE, cmdaddr); WRITE_NAND_ADDRESS(0x90, addraddr); if (enable) { /* Activate the internal ECC controller */ WRITE_NAND(0x08, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); setSmcOpEccType(SMC_ECC_INTERNAL); } else { /* De-activate the internal ECC controller */ WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); WRITE_NAND(0x00, dataaddr); } return true; } return false; }
//----------------------------------------------------------------------------- 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; }