/** * * This function returns the length including bad blocks from a given offset and * length. * * @param NandInstPtr is the pointer to the XNandPs instance. * @param Offset is the flash data address to read from. * @param Length is number of bytes to read. * * @return * - Return actual length including bad blocks. * * @note None. * ******************************************************************************/ static u32 XNandPs_CalculateLength(XNandPs *NandInstPtr, u64 Offset, u32 Length) { u32 BlockSize = NandInstPtr->Geometry.BlockSize; u32 CurBlockLen; u32 CurBlock; u32 Status; u32 TempLen = 0; u32 ActLen = 0; while (TempLen < Length) { CurBlockLen = BlockSize - (Offset & (BlockSize - 1)); CurBlock = (Offset & ~(BlockSize - 1))/BlockSize; /* * Check if the block is bad */ Status = XNandPs_IsBlockBad(NandInstPtr, CurBlock); if (Status != XST_SUCCESS) { /* Good Block */ TempLen += CurBlockLen; } ActLen += CurBlockLen; Offset += CurBlockLen; if (Offset >= NandInstPtr->Geometry.DeviceSize) { break; } } return ActLen; }
/** * * This function runs a test on the NAND flash device using the basic driver * functions. * The function does the following tasks: * - Initialize the driver. * - Erase the blocks. * - Write in to all the blocks. * - Read back the data from the blocks. * - Compare the data read against the data Written. * * @param NandDeviceId is is the XPAR_<NAND_instance>_DEVICE_ID value * from xparameters.h. * * @return * - XST_SUCCESS if successful. * - XST_FAILURE if failed. * * @note When bad blocks are encountered, they are not erased and * programmed. * ****************************************************************************/ int NandReadWriteExample(u32 NandDeviceId) { int Status; u32 Index; u32 BlockIndex; XNandPs_Config *ConfigPtr; u64 Offset; u32 Length; u32 StartBlock; u32 EndBlock; /* * Initialize the flash driver. */ ConfigPtr = XNandPs_LookupConfig(NandDeviceId); if (ConfigPtr == NULL) { return XST_FAILURE; } Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr, ConfigPtr->SmcBase,ConfigPtr->FlashBase); if (Status != XST_SUCCESS) { return XST_FAILURE; } StartBlock = NAND_TEST_START_BLOCK; EndBlock = NAND_TEST_START_BLOCK + NAND_TEST_NUM_BLOCKS; Length = NAND_TEST_BLOCK_SIZE; /* * Prepare the write buffer. Fill in the data need to be written into * Flash Device. */ for (Index = 0; Index < Length; Index++) { WriteBuffer[Index] = Index % 256; } /* * Erase the blocks in the flash */ for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { /* * Don't erase bad blocks. */ if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) { continue; } /* * Perform erase operation. */ Status = XNandPs_EraseBlock(NandInstPtr, BlockIndex); if (Status != XST_SUCCESS) { return Status; } } /* * Perform the read/write operation */ for (BlockIndex = StartBlock; BlockIndex < EndBlock; BlockIndex++) { /* * Don't program bad blocks. */ if (XNandPs_IsBlockBad(NandInstPtr, BlockIndex) == XST_SUCCESS) { continue; } Offset = BlockIndex * NandInstPtr->Geometry.BlockSize; /* * Perform the write operation. */ Status = XNandPs_Write(NandInstPtr, Offset, Length, WriteBuffer, NULL); if (Status != XST_SUCCESS) { return Status; } /* * Perform the read operation. */ Status = XNandPs_Read(NandInstPtr, Offset, Length, ReadBuffer, NULL); if (Status != XST_SUCCESS) { return Status; } /* * Compare the data read against the data Written. */ for (Index = 0; Index < Length; Index++) { if (ReadBuffer[Index] != WriteBuffer[Index]) { return XST_FAILURE; } } /* * Clear the Receive buffer for next iteration */ memset(ReadBuffer, 0, Length); } return XST_SUCCESS; }
/** * * This function provides the NAND FLASH interface for the Simplified header * functionality. This function handles bad blocks. * * The source address is the absolute good address, bad blocks are skipped * without incrementing the source address. * * @param SourceAddress is address in FLASH data space, absolute good address * @param DestinationAddress is address in OCM data space * * @return XST_SUCCESS if the transfer completes correctly * XST_FAILURE if the transfer fails to completes correctly * * @note none. * ****************************************************************************/ u32 NandAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) { u32 Status = XST_SUCCESS; u32 PageSizeMask; u32 PageSize; u32 BytesPerBlock; u32 TempSourceAddress; u32 ByteCount = 0; u32 TmpAddress = 0; int BlockCount = 0; int BadBlocks = 0; u32 LastBlockCount = 0; u32 Data; PageSize = NandInstance.Geometry.BytesPerPage; PageSizeMask = PageSize - 1; TempSourceAddress = SourceAddress; BytesPerBlock = (NandInstance.Geometry.PagesPerBlock * PageSize); Data = 0xFFFFFFFF; /* First get bad blocks before the source address */ while (TmpAddress < SourceAddress) { while (XNandPs_IsBlockBad(NandInstPtr, BlockCount) == XST_SUCCESS) { BlockCount ++; BadBlocks ++; } TmpAddress += BytesPerBlock; BlockCount ++; } /* Previous loop advanced BlockCount one more too much */ LastBlockCount = BlockCount - 1; /* Now transfer with bad block skipping */ while (ByteCount < LengthBytes) { int TmpBadBlocks = 0; int Length; TempSourceAddress = SourceAddress + ByteCount + BadBlocks * BytesPerBlock; BlockCount = TempSourceAddress / BytesPerBlock; /* If advance to the next block, needs to check bad block */ if (BlockCount > LastBlockCount) { LastBlockCount = BlockCount; while (XNandPs_IsBlockBad(NandInstPtr, BlockCount) == XST_SUCCESS) { BlockCount ++; TmpBadBlocks ++; fsbl_printf(DEBUG_INFO,"Found bad block %d: %d\r\n", BlockCount, TmpBadBlocks); } if (TmpBadBlocks) { BadBlocks += TmpBadBlocks; TempSourceAddress += TmpBadBlocks * BytesPerBlock; LastBlockCount += TmpBadBlocks; } } if (LengthBytes == 4) { Status = ReadNand(TempSourceAddress,&Data); *((u32 *)DestinationAddress) = Data; return Status; } /* NAND transfer is page-wise */ Length = PageSize - (TempSourceAddress & PageSizeMask); if ((Length + ByteCount) > LengthBytes) { Length = LengthBytes - ByteCount; } Status = XNandPs_Read(NandInstPtr, (u64)TempSourceAddress, Length, (u32 *)(DestinationAddress + ByteCount), NULL); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"NandAccess Failed: source %x, " "count %d, destinationaddr %x, " "Status = 0x%.8x\r\n", (u64)TempSourceAddress, Length, DestinationAddress + ByteCount, Status); return Status; } ByteCount += Length; } /* End of while ByteCount < LengthBytes */ return Status; } /* End of NandAccess */
/** * * This function provides the NAND FLASH interface for the Simplified header * functionality. This function handles bad blocks. * * The source address is the absolute good address, bad blocks are skipped * without incrementing the source address. * * @param SourceAddress is address in FLASH data space, absolute good address * @param DestinationAddress is address in OCM data space * * @return XST_SUCCESS if the transfer completes correctly * XST_FAILURE if the transfer fails to completes correctly * * @note none. * ****************************************************************************/ u32 NandAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes) { u32 ActLen; u32 BlockOffset; u32 Block; u32 Status; u32 BytesLeft = LengthBytes; u32 BlockSize = NandInstPtr->Geometry.BlockSize; u8 *BufPtr = (u8 *)DestinationAddress; u32 ReadLen; u32 BlockReadLen; u32 Offset; u32 TmpAddress = 0 ; u32 BlockCount = 0; u32 BadBlocks = 0; /* * First get bad blocks before the source address */ while (TmpAddress < SourceAddress) { while (XNandPs_IsBlockBad(NandInstPtr, BlockCount) == XST_SUCCESS) { BlockCount ++; BadBlocks ++; } TmpAddress += BlockSize; BlockCount ++; } Offset = SourceAddress + BadBlocks * BlockSize; /* * Calculate the actual length including bad blocks */ ActLen = XNandPs_CalculateLength(NandInstPtr, Offset, LengthBytes); /* * Check if the actual length cross flash size */ if (Offset + ActLen > NandInstPtr->Geometry.DeviceSize) { return XST_FAILURE; } while (BytesLeft > 0) { BlockOffset = Offset & (BlockSize - 1); Block = (Offset & ~(BlockSize - 1))/BlockSize; BlockReadLen = BlockSize - BlockOffset; Status = XNandPs_IsBlockBad(NandInstPtr, Block); if (Status == XST_SUCCESS) { /* Move to next block */ Offset += BlockReadLen; continue; } /* * Check if we cross block boundary */ if (BytesLeft < BlockReadLen) { ReadLen = BytesLeft; } else { ReadLen = BlockReadLen; } /* * Read from the NAND flash */ Status = XNandPs_Read(NandInstPtr, Offset, ReadLen, BufPtr, NULL); if (Status != XST_SUCCESS) { return Status; } BytesLeft -= ReadLen; Offset += ReadLen; BufPtr += ReadLen; } return XST_SUCCESS; }