/**
*
* 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;
}
Exemple #2
0
/**
*
* 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;
}
Exemple #3
0
/**
*
* 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;
}