/**
*
* This function fetches and displays the geometry and properties of the Flash *
* device.
*
* @param	None.
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashDeviceControlExample(void)
{
	int Status;
	u32 Index;
	DeviceCtrlParam IoctlParams;

	/*
	 * Initialize the Flash Library.
	 */
	Status = XFlash_Initialize(&FlashInstance, FLASH_BASE_ADDRESS,
				   FLASH_MEM_WIDTH, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Reset the Flash Device. This clears the Status registers and puts
	 * the device in Read mode.
	 */
	Status = XFlash_Reset(&FlashInstance);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Fetch the flash device properties and display.
	 */
	Status = XFlash_DeviceControl(&FlashInstance,
				XFL_DEVCTL_GET_PROPERTIES, &IoctlParams);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	xil_printf("\n\r\t\tFlash Properties\n\r");
	xil_printf("FlashProperties->PartID.ManufacturerID = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						PartID.ManufacturerID);

	xil_printf("FlashProperties->PartID.DeviceID = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
							PartID.DeviceID);

	xil_printf("FlashProperties->PartID.DeviceID = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
							PartID.CommandSet);

	xil_printf("FlashProperties->TimeTypical.WriteSingle_Us = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeTypical.WriteSingle_Us);

	xil_printf("FlashProperties->TimeTypical.WriteBuffer_Us = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeTypical.WriteBuffer_Us);

	xil_printf("FlashProperties->TimeTypical.EraseBlock_Ms = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeTypical.EraseBlock_Ms);

	xil_printf("FlashProperties->TimeTypical.EraseChip_Ms = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeTypical.EraseChip_Ms);

	xil_printf("FlashProperties->TimeMax.WriteSingle_Us = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeMax.WriteSingle_Us);

	xil_printf("FlashProperties->TimeMax.WriteBuffer_Us = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeMax.WriteBuffer_Us);

	xil_printf("FlashProperties->TimeMax.EraseBlock_Ms = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeMax.EraseBlock_Ms);

	xil_printf("FlashProperties->TimeMax.EraseChip_Ms = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						TimeMax.EraseChip_Ms);

	xil_printf("FlashProperties->ProgCap.WriteBufferSize = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						ProgCap.WriteBufferSize);

	xil_printf("FlashProperties->ProgCap.WriteBufferAlignMask = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->ProgCap.
						WriteBufferAlignmentMask);

	xil_printf("FlashProperties->ProgCap.EraseQueueSize = 0x%x\n\r",
			IoctlParams.PropertiesParam.PropertiesPtr->
						ProgCap.EraseQueueSize);

	/*
	 * Fetch the flash device geometry and display.
	 */
	Status = XFlash_DeviceControl(&FlashInstance,
				XFL_DEVCTL_GET_GEOMETRY, &IoctlParams);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	xil_printf("\n\r\n\r\t\tFlash Geometry\n\r");

	xil_printf("FlashGeometry->BaseAddress = 0x%x\n\r",
			IoctlParams.GeometryParam.GeometryPtr->BaseAddress);

	xil_printf("FlashGeometry->MemoryLayout = 0x%x\n\r",
			IoctlParams.GeometryParam.GeometryPtr->MemoryLayout);

	xil_printf("FlashGeometry->DeviceSize = 0x%x\n\r",
			IoctlParams.GeometryParam.GeometryPtr->DeviceSize);

	xil_printf("FlashGeometry->NumEraseRegions = 0x%x\n\r",
			IoctlParams.GeometryParam.GeometryPtr->NumEraseRegions);

	xil_printf("FlashGeometry->NumBlocks = 0x%x\n\r",
			IoctlParams.GeometryParam.GeometryPtr->NumBlocks);

	for(Index = 0; Index < IoctlParams.GeometryParam.GeometryPtr->
					NumEraseRegions; Index++) {
		xil_printf("\tErase region %d\n\r", Index);

		xil_printf("Absolute Offset = 0x%x\n\r",
				IoctlParams.GeometryParam.GeometryPtr->
					EraseRegion[Index].AbsoluteOffset);

		xil_printf("Absolute Block = 0x%x\n\r",
				IoctlParams.GeometryParam.GeometryPtr->
					EraseRegion[Index].AbsoluteBlock);

		xil_printf("Num Of Block = 0x%x\n\r",
				IoctlParams.GeometryParam.GeometryPtr->
						EraseRegion[Index].Number);

		xil_printf("Size Of Block = 0x%x\n\r",
				IoctlParams.GeometryParam.GeometryPtr->
						EraseRegion[Index].Size);
	}

	return XST_SUCCESS;
}
/**
*
* This function writes, reads, and verifies the data to the Flash device.
*
* @param	None
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashReadWriteExample(void)
{
	int Status;
	u32 Index;

	/*
	 * Initialize the Flash Library.
	 */
	Status = XFlash_Initialize(&FlashInstance, FLASH_BASE_ADDRESS,
				   FLASH_MEM_WIDTH, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Reset the Flash Device. This clears the Status registers and puts
	 * the device in Read mode.
	 */
	Status = XFlash_Reset(&FlashInstance);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform an unlock operation before the erase operation for the Intel
	 * Flash. The erase operation will result in an error if the block is
	 * locked.
	 */
	if ((FlashInstance.CommandSet == XFL_CMDSET_INTEL_STANDARD) ||
	    (FlashInstance.CommandSet == XFL_CMDSET_INTEL_EXTENDED)) {
		Status = XFlash_Unlock(&FlashInstance, BLOCK_OFFSET_ADDR, 0);
		if(Status != XST_SUCCESS) {
			return XST_FAILURE;
		}
	}

	/*
	 * Perform the Erase operation.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Prepare the write buffer. Fill in the data need to be written into
	 * Flash Device.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		WriteBuffer[Index] = Index + 1;
	}

	/*
	 * Perform the Write operation.
	 */
	Status = XFlash_Write(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
								WriteBuffer);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform the read operation.
	 */
	Status = XFlash_Read(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
								ReadBuffer);
		if(Status != XST_SUCCESS) {
			return XST_FAILURE;
	}

	/*
	 * Compare the data read against the data Written.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		if(ReadBuffer[Index] != WriteBuffer[Index]) {
			return XST_FAILURE;
		}
	}

	return XST_SUCCESS;
}
/**
*
* This function verifies the locking and unlocking features of the Flash device.
*
* @param	None
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashProtectionExample(void)
{
	int Status;
	u32 Index;

	/*
	 * Initialize the Flash Library.
	 */
	xil_printf("-- Entering Main --\r\n");
	Status = XFlash_Initialize(&FlashInstance, FLASH_BASE_ADDRESS,
				   FLASH_MEM_WIDTH, 0);
	if(Status != XST_SUCCESS) {
	xil_printf("-- Fail at Initialize --\r\n");
		return XST_FAILURE;
	}
	xil_printf("-- Initialized the Flash library successfully --\r\n");
	/*
	 * Reset the Flash Device. This clears the Status registers and puts
	 * the device in Read mode.
	 */
	Status = XFlash_Reset(&FlashInstance);
	if(Status != XST_SUCCESS) {
	xil_printf("-- Fail at reset --\r\n");
		return XST_FAILURE;
	}

	/*
	 * Unlock all the Blocks.
	 */
	for (Index = 0; Index < NumBlocks; Index++)
	{
		Status = XFlash_Unlock(&FlashInstance, (Index * BLOCK_SIZE), 0);
		if(Status != XST_SUCCESS) {
		xil_printf("-- Unlock error --\r\n");
		return XST_FAILURE;
		}
	}
    	xil_printf("-- Unlocked all the blocks successfully --\r\n");

	/*
	 * Perform the Erase operation. This should succeed as the block is
	 * unlocked.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
		xil_printf("-- Erase failed --\r\n");
	}
   	xil_printf("-- Erased the Flash memory contents successfully --\r\n");

	/*
	 * Prepare the write buffer. Fill in the data need to be written into
	 * Flash Device.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		WriteBuffer[Index] = (u8)Index;
	}

	/*
	 * Perform the Write operation.
	 */
	Status = XFlash_Write(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			      WriteBuffer);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
  	xil_printf("-- Write operation completed successfully --\r\n");
	/*
	 * Perform the read operation.
	 */
	Status = XFlash_Read(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			     ReadBuffer);
		if(Status != XST_SUCCESS) {
			return XST_FAILURE;
	}
   	xil_printf("-- Read operation completed successfully --\r\n");
	/*
	 * Compare the data read against the data Written.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		if(ReadBuffer[Index] != (u8)Index) {
			return XST_FAILURE;
		}
	}
   	xil_printf("-- Data comparison successful --\r\n");
	return XST_SUCCESS;
}
/**
*
* This function verifies the locking and unlocking features of the Flash device.
*
* @param	None
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashProtectionExample(void)
{
	int Status;
	u32 Index;
	char temp[120];

	/*
	 * Initialize the Flash Library.
	 */
	Status = XFlash_Initialize(&FlashInstance, FLASH_BASE_ADDRESS,
				   FLASH_MEM_WIDTH, 0);
	if(Status != XST_SUCCESS) {
		xil_printf("-- Fail at Initialize --\r\n");
		if(logenable==1) strcat(logbuf, "-- Fail at Initialize --\r\n");
		return XST_FAILURE;
	}
	xil_printf("-- Initialized the Flash library successfully --\r\n");
	if(logenable==1) strcat(logbuf, "-- Initialized the Flash library successfully --\r\n");

	/*
	 * Reset the Flash Device. This clears the Status registers and puts
	 * the device in Read mode.
	 */
	Status = XFlash_Reset(&FlashInstance);
	if(Status != XST_SUCCESS) {
		xil_printf("-- Fail at reset --\r\n");
		if(logenable==1) strcat(logbuf, "-- Fail at reset --\r\n");
		return XST_FAILURE;
	}

	/*
	 * Lock the Block.
	 */
	Status = XFlash_Lock(&FlashInstance, BLOCK_OFFSET_ADDR, 0);
	if(Status != XST_SUCCESS) {
		xil_printf("-- Lock error --\r\n");
		if(logenable==1) strcat(logbuf, "-- Lock error --\r\n");
		return XST_FAILURE;
	}
	xil_printf("-- Locked all the blocks successfully --\r\n");
	if(logenable==1) strcat(logbuf, "-- Locked all the blocks successfully --\r\n");

	/*
	 * Perform the Erase operation. This should fail as the block is locked.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status == XST_SUCCESS) {
		xil_printf("-- Erase failed --\r\n");
		if(logenable==1) strcat(logbuf, "-- Erase failed --\r\n");
		return XST_FAILURE;
	}
	xil_printf("-- Erased the Flash memory contents at offset 0x%07x successfully --\r\n",
			START_ADDRESS);
	if(logenable==1)
	{
		sprintf(temp, "-- Erased the Flash memory contents at offset 0x%07x successfully --\r\n",
				START_ADDRESS);
		strcat(logbuf, temp);
	}
	/*
	 * Unlock the Block.
	 */
	Status = XFlash_Unlock(&FlashInstance, BLOCK_OFFSET_ADDR, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	xil_printf("-- Unlocked all the blocks successfully --\r\n");
	if(logenable==1) strcat(logbuf, "-- Unlocked all the blocks successfully --\r\n");

	/*
	 * Perform the Erase operation. This should succeed as the block is
	 * unlocked.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Prepare the write buffer. Fill in the data need to be written into
	 * Flash Device.
	 */
	xil_printf("-- Writing: ");
	if(logenable==1) strcat(logbuf, "-- Writing: ");
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		WriteBuffer[Index] = (u8)Index;
		xil_printf("%02x", WriteBuffer[Index]);
		if(logenable==1)
		{
			sprintf(temp, "%02x", WriteBuffer[Index]);
			strcat(logbuf, temp);
		}
	}
	xil_printf("\r\n");
	if(logenable==1) strcat(logbuf, "\r\n");

	/*
	 * Perform the Write operation.
	 */
	Status = XFlash_Write(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			      WriteBuffer);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	xil_printf("-- Write operation at offset 0x%07x completed successfully --\r\n",
			START_ADDRESS);
	if(logenable==1)
	{
		sprintf(temp, "-- Write operation at offset 0x%07x completed successfully --\r\n",
					START_ADDRESS);
		strcat(logbuf, temp);
	}

	/*
	 * Perform the read operation.
	 */
	Status = XFlash_Read(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			     ReadBuffer);
		if(Status != XST_SUCCESS) {
			return XST_FAILURE;
	}
	xil_printf("-- Read operation completed successfully --\r\n");
	if(logenable==1) strcat(logbuf, "-- Read operation completed successfully --\r\n");

	/*
	 * Compare the data read against the data Written.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		if(ReadBuffer[Index] != (u8)Index) {
			return XST_FAILURE;
		}
	}
	xil_printf("-- Data comparison successful --\r\n");
	if(logenable==1) strcat(logbuf, "-- Data comparison successful --\r\n");
	return XST_SUCCESS;
}
/**
*
* This function verifies the locking and unlocking features of the Flash device.
*
* @param	None
*
* @return	XST_SUCCESS if successful else XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashProtectionExample(void)
{
	int Status;
	u32 Index;

	#ifdef XPAR_XFL_DEVICE_FAMILY_INTEL
		#if XFL_TO_ASYNCMODE
		/*
		 * Set Flash to Async mode.
		 */
		if (FLASH_MEM_WIDTH == 1) {
			WRITE_FLASH_8(FLASH_BASE_ADDRESS + ASYNC_ADDR, 0x60);
			WRITE_FLASH_8(FLASH_BASE_ADDRESS + ASYNC_ADDR, 0x03);
		} else if (FLASH_MEM_WIDTH == 2) {
			WRITE_FLASH_16(FLASH_BASE_ADDRESS + ASYNC_ADDR,
					INTEL_CMD_CONFIG_REG_SETUP);
			WRITE_FLASH_16(FLASH_BASE_ADDRESS + ASYNC_ADDR,
					INTEL_CMD_CONFIG_REG_CONFIRM);
		}
		#endif
	#endif

	/*
	 * Initialize the Flash Library.
	 */
	Status = XFlash_Initialize(&FlashInstance, FLASH_BASE_ADDRESS,
				   FLASH_MEM_WIDTH, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Reset the Flash Device. This clears the Status registers and puts
	 * the device in Read mode.
	 */
	Status = XFlash_Reset(&FlashInstance);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Lock the Block.
	 */
	Status = XFlash_Lock(&FlashInstance, BLOCK_OFFSET_ADDR, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform the Erase operation. This should fail as the block is locked.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status == XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Unlock the Block.
	 */
	Status = XFlash_Unlock(&FlashInstance, BLOCK_OFFSET_ADDR, 0);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform the Erase operation. This should succeed as the block is
	 * unlocked.
	 */
	Status = XFlash_Erase(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Prepare the write buffer. Fill in the data need to be written into
	 * Flash Device.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		WriteBuffer[Index] = (u8)Index;
	}

	/*
	 * Perform the Write operation.
	 */
	Status = XFlash_Write(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			      WriteBuffer);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Perform the read operation.
	 */
	Status = XFlash_Read(&FlashInstance, START_ADDRESS, FLASH_TEST_SIZE,
			     ReadBuffer);
		if(Status != XST_SUCCESS) {
			return XST_FAILURE;
	}

	/*
	 * Compare the data read against the data Written.
	 */
	for(Index = 0; Index < FLASH_TEST_SIZE; Index++) {
		if(ReadBuffer[Index] != (u8)Index) {
			return XST_FAILURE;
		}
	}

	return XST_SUCCESS;
}