ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/Flash/SPI/NZAS/SPINOR.c b/marvell/obm/Common/Flash/SPI/NZAS/SPINOR.c
new file mode 100644
index 0000000..42fb602
--- /dev/null
+++ b/marvell/obm/Common/Flash/SPI/NZAS/SPINOR.c
@@ -0,0 +1,969 @@
+/******************************************************************************
+ *
+ *  (C)Copyright 2013 Marvell Hefei Branch. All Rights Reserved.
+ *
+ *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
+ *  The copyright notice above does not evidence any actual or intended
+ *  publication of such source code.
+ *  This Module contains Proprietary Information of Marvell and should be
+ *  treated as Confidential.
+ *  The information in this file is provided for the exclusive use of the
+ *  licensees of Marvell.
+ *  Such users have the right to use, modify, and incorporate this code into
+ *  products for purposes authorized by the license agreement provided they
+ *  include this notice and the associated copyright notice with any such
+ *  product.
+ *  The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "spi.h"
+#include "SPINOR.h"
+#include "GPIO.h"
+#include "Typedef.h"
+#include "Errors.h"
+#include "PlatformConfig.h"
+#include "xllp_dmac.h"
+#include "timer.h"
+#include "SPINOR_extened.h"
+
+extern UINT_T Flash_size;
+
+SPINOR_T G_spinor_info;
+P_SPINOR_T pGspinor_info = &G_spinor_info;
+
+UINT_T Spansion_SPINOR_Flash = 0;
+
+P_SPINOR_T getSPINor_Info(void) {
+	return pGspinor_info;
+}
+
+__attribute__ ((aligned(16))) XLLP_DMAC_DESCRIPTOR_T pRX_data, pTX_cmd;
+__attribute__ ((aligned(16)))unsigned char tx_command_spinor[SIZE_4KB];
+
+UINT_T InitializeSPIDevice(UINT8_T FlashNum, UINT8_T* P_DefaultPartitionNum)
+{
+	UINT_T Retval = NoError;
+	UINT_T i, ID, status;
+	UINT_T status_value, config_value;
+	unsigned char mid, status2;
+	unsigned short did;
+	P_SPINOR_T spinor_info = getSPINor_Info();
+
+	P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
+
+	memset(spinor_info, 0, sizeof(SPINOR_T));
+
+	ChipSelectSPINOR();
+	SPI_ConfigCS();
+	SPINOR_Reset();
+	SPINOR_ReadId(&mid, &did);
+	obm_printf("Manufacturer ID: %x, device ID: %x\n\r", mid, did);
+
+	SetCurrentFlashBootType(BOOT_FLASH);
+
+	//setup Flash Properties info
+	pFlashP->BlockSize					= 0x10000;		// 64KB
+	pFlashP->PageSize					= 0x100; 		// 256B
+	pFlashP->NumBlocks				= 0x100;			// 256
+	pFlashP->ResetFlash				= NULL;
+	pFlashP->FlashSettings.UseBBM 		= 0;
+	pFlashP->FlashSettings.UseSpareArea 	= 0;
+	pFlashP->FlashSettings.SASize 		= 0;
+	pFlashP->FlashSettings.UseHwEcc 		= 0;
+	pFlashP->StreamingFlash 			= FALSE;
+	pFlashP->StagedInitRequired 			= FALSE;
+	pFlashP->FlashType 				= SPI_FLASH;
+	pFlashP->FinalizeFlash 				= NULL;
+	pFlashP->TimFlashAddress 			= 0;
+	
+	*P_DefaultPartitionNum = 0;
+
+	switch (mid)
+	{
+		case SPANSION_ID:
+			obm_printf("Spansion SPI-Nor\n\r");
+			switch (did)
+			{
+				case 0x0219:
+					spinor_info->large_capacity				= 0x01;
+					spinor_info->enable_4bytes				= 0x00;
+					//spinor_info->write_enable_4enable_4bytes	= 0x00;
+					//spinor_info->read_4bytes_status_cmd		= 0x00;
+					//spinor_info->spi_4bytes_enabled_bit		= 0x00;
+					spinor_info->read_4bytes_cmd			= SPINOR_READ_4Bytes_CMD1;
+					spinor_info->write_4bytes_cmd			= SPINOR_PROGRAM_4Bytes_CMD1;
+					spinor_info->erase_4bytes_cmd			= SPINOR_SECTOR_ERASE_4Bytes_CMD1;
+					Spansion_SPINOR_Flash = 1;
+				break;
+
+				case 0x0218:
+					Spansion_SPINOR_Flash = 1;
+				default:
+					break;
+			}
+			break;
+			
+		case MACRONIX_ID:
+			obm_printf("Macronix SPI-Nor\n\r");
+			switch (did)
+			{
+				case 0x2539:
+					spinor_info->large_capacity				= 0x01;
+					spinor_info->enable_4bytes				= 0x00;
+					//spinor_info->write_enable_4enable_4bytes	= 0x00;
+					//spinor_info->read_4bytes_status_cmd		= 0x00;
+					//spinor_info->spi_4bytes_enabled_bit		= 0x00;
+					spinor_info->read_4bytes_cmd			= SPINOR_READ_4Bytes_CMD1;
+					spinor_info->write_4bytes_cmd			= SPINOR_PROGRAM_4Bytes_CMD1;
+					spinor_info->erase_4bytes_cmd			= SPINOR_SECTOR_ERASE_4Bytes_CMD1;
+					break;
+				default:
+					break;
+			}
+			break;
+		case GIGADEVICE_ID:
+			obm_printf("Giga SPI-Nor\n\r");
+			switch (did)
+			{
+				case 0x6019:
+					spinor_info->large_capacity				= 0x01; // need to check spec
+					spinor_info->enable_4bytes				= 0x01; // need to check spec
+					spinor_info->write_enable_4enable_4bytes	= 0x00; // need to check spec
+					spinor_info->read_4bytes_status_cmd		= SPINOR_READ_STATUS_CMD0;
+					spinor_info->spi_4bytes_enabled_bit		= BIT3; // need to check spec
+					spinor_info->read_4bytes_cmd			= SPINOR_READ_4Bytes_CMD0;
+					spinor_info->write_4bytes_cmd			= SPINOR_PROGRAM_4Bytes_CMD0;
+					spinor_info->erase_4bytes_cmd			= SPINOR_SECTOR_ERASE_4Bytes_CMD0;
+					break;
+				default:
+					break;
+			}
+			break;
+		case MICRON_ID:
+			obm_printf("Micron SPI-Nor\n\r");
+			switch (did)
+			{
+				case 0xcb19:
+					spinor_info->large_capacity				= 0x01; // need to check spec
+					spinor_info->enable_4bytes				= 0x01; // need to check spec
+					spinor_info->write_enable_4enable_4bytes	= 0x01; // need to check spec
+					spinor_info->read_4bytes_status_cmd		= SPINOR_READ_STATUS_CMD1;
+					spinor_info->spi_4bytes_enabled_bit		= BIT0; // need to check spec
+					spinor_info->read_4bytes_cmd			= SPINOR_READ_4Bytes_CMD1;
+					spinor_info->write_4bytes_cmd			= SPINOR_PROGRAM_4Bytes_CMD0;
+					spinor_info->erase_4bytes_cmd			= SPINOR_SECTOR_ERASE_4Bytes_CMD0;
+					break;
+				default:
+					break;
+			}
+			break;
+		case FIDELIX_ID:
+			obm_printf("Fidelix SPI-NOR\n\r");
+			switch(did)
+			{
+				case 0x4218:
+					spinor_info->large_capacity	= 0x0;
+					break;
+				default:
+					break;
+			}
+			break;
+		default:
+			break;
+	}
+	if (spinor_info->large_capacity == 1) // 1: 32MB, 2:  64MB???
+	{
+		obm_printf("Large capacity\n\r");
+		Flash_size = 0x02000000;
+
+		pFlashP->ReadFromFlash 	= &SPINOR_Extend_Read;
+		pFlashP->WriteToFlash	= &SPINOR_Extend_Write;
+		pFlashP->EraseFlash		= &SPINOR_Extend_Erase;
+		SPINOR_Enable4BytesMode();
+	}
+	else
+	{
+		pFlashP->ReadFromFlash	= &SPINOR_Read;
+		pFlashP->WriteToFlash	= &SPINOR_Write;
+		pFlashP->EraseFlash		= &SPINOR_Erase;
+	}
+
+	SPINOR_UnProtectBlocks();
+
+	//fill tx dummy buffer with special pattern
+	memset(tx_command_spinor, 0xA5, sizeof(tx_command_spinor));
+
+	return Retval;
+}
+
+UINT8_T SPINOR_ReadReg(SPINOR_Register reg)
+{
+	UINT_T dummy;
+	UINT8_T status, command;
+
+	P_SPINOR_T spinor_info = getSPINor_Info();
+	switch (reg)
+	{
+		case SPINOR_4bytes_Status_Register:
+			command = spinor_info->read_4bytes_status_cmd;
+			break;
+		case SPINOR_write_enable_Status_Register:
+			command = SPI_CMD_READ_STATUS;
+			break;
+		default:
+			command = SPI_CMD_READ_STATUS;
+			break;
+	}
+
+	SPI_DisableSSP();
+	SPI_ConfigDSS(16);
+
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_WriteData(command << 8);
+	SPI_WaitSSPComplete();
+	dummy = SPI_ReadData();
+	status = dummy & 0xFF;	//the status will be in the second byte
+
+	Deassert_CS();
+
+	SPI_DisableSSP();
+
+	//return last known status
+	return status;
+}
+
+void SPINOR_Enable4BytesMode(void)
+{
+	UINT8_T status, cmd[1], data[1];
+	
+	P_SPINOR_T spinor_info = getSPINor_Info();
+	if (!spinor_info->enable_4bytes)
+		return;
+
+	status = SPINOR_ReadReg(SPINOR_4bytes_Status_Register);
+	if ((status & spinor_info->spi_4bytes_enabled_bit) == spinor_info->spi_4bytes_enabled_bit)
+	{
+		// It's already 4-Bytes Modes!!!
+		return;
+	}
+
+	if (spinor_info->write_enable_4enable_4bytes)
+		SPINOR_WriteEnable();
+
+	cmd[0] = SPINOR_ENABLE_4BYTE_MODE;
+
+	SPI_DisableSSP();
+	SPI_ConfigDSS(8);
+	Assert_CS();
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	//make sure SSP is disabled
+	SPI_DisableSSP();
+
+	status = SPINOR_ReadReg(SPINOR_4bytes_Status_Register);
+	if ((status & spinor_info->spi_4bytes_enabled_bit) != spinor_info->spi_4bytes_enabled_bit)
+	{
+		obm_printf("Enter 4-Bytes Modes failed!!!\n\r");
+	}
+
+	return;
+}
+
+void SPINOR_Disable4BytesMode(void)
+{
+	UINT8_T status, cmd[1], data[1];
+
+	P_SPINOR_T spinor_info = getSPINor_Info();
+	if (!spinor_info->enable_4bytes)
+		return;
+
+	status = SPINOR_ReadReg(SPINOR_4bytes_Status_Register);
+	if ((status & spinor_info->spi_4bytes_enabled_bit) == 0x00)
+	{
+		// It's already 3-Bytes Modes!!!
+		return;
+	}
+
+	if (spinor_info->write_enable_4enable_4bytes)
+		SPINOR_WriteEnable();
+
+	cmd[0] = SPINOR_DISABLE_4BYTE_MODE;
+
+	SPI_DisableSSP();
+	Assert_CS();
+	SPI_FireUp();
+		
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	//make sure SSP is disabled
+	SPI_DisableSSP();
+
+	status = SPINOR_ReadReg(SPINOR_4bytes_Status_Register);
+	if ((status & spinor_info->spi_4bytes_enabled_bit) != 0x00)
+	{
+		obm_printf("Exit 4-Bytes Modes failed!!!\n\r");
+	}
+ 
+	return;
+}
+
+void SPINOR_Protect_Blocks(void)
+{
+	UINT_T status_value, status1_value;
+
+#if 0
+	// make sure it's ready
+	SPINOR_ReadStatus(TRUE);
+
+	// read out status register and configuration register
+	status_value = Giga_SPINor_ReadReg(Giga_Status_Register);
+	status1_value = Giga_SPINor_ReadReg(Giga_Status_Register1);
+
+	if (((status1_value & GIGA_STATUS_CMP) == 0x0)
+		&& ((status_value & (GIGA_STATUS_BP0 |
+								GIGA_STATUS_BP1 |
+								GIGA_STATUS_BP2|
+								GIGA_STATUS_BP3 |
+								GIGA_STATUS_BP4))
+		== (GIGA_STATUS_BP0 | GIGA_STATUS_BP3)))
+	{
+		obm_printf("SPI Nor is already protected\n\r");
+		return;
+	}
+	else
+	{
+		obm_printf("SPI Nor is not protected\n\r");
+	}
+	
+	SPINOR_WriteEnable();
+
+	// clear BP0/BP1/BP2/BP3/BP4
+	status_value &= ~(GIGA_STATUS_BP0 |
+						GIGA_STATUS_BP1 |
+						GIGA_STATUS_BP2|
+						GIGA_STATUS_BP3 |
+						GIGA_STATUS_BP4);
+
+	// set BP0/BP3
+	status_value |= GIGA_STATUS_BP0 | GIGA_STATUS_BP3;
+
+	// clear CMP
+	status1_value &= ~GIGA_STATUS_CMP;
+
+	MX_SPINOR_WriteStatus(status_value, status1_value);
+	SPINOR_ReadStatus(TRUE);
+	
+	status_value = Giga_SPINor_ReadReg(Giga_Status_Register);
+	status1_value = Giga_SPINor_ReadReg(Giga_Status_Register1);
+
+	obm_printf("SPI Nor protect done\n\r");
+#endif
+}
+
+void SPINOR_UnProtectBlocks(void)
+{
+	UINT_T status_value, status1_value;
+	
+	SPINOR_ReadStatus(TRUE);
+	
+	status_value = SPINOR_ReadReg(SPINOR_write_enable_Status_Register);
+
+	if (((status_value & (BIT2 | BIT3 | BIT4)) == 0) )
+	{
+		obm_printf("SPI Nor is already unprotected\n\r");
+		return;
+	}
+	else
+	{
+		obm_printf("SPI Nor is not unprotected\n\r");
+	}
+	
+	SPINOR_WriteEnable();
+
+	// clear BP0/BP1/BP2, BP3/BP4 doesn't matter
+	status_value &= ~(BIT2 | BIT3 | BIT4);
+	
+	SPINOR_WriteStatus(status_value);	
+	
+	SPINOR_ReadStatus(TRUE);
+	
+	obm_printf("SPI Nor unprotect done\n\r");
+}
+
+void SPINOR_Reset(void)
+{
+	UINT8_T status, cmd[1], data[1];
+
+	cmd[0] = SPI_CMD_RELEASE_POWER_DOWN;
+	SPI_DisableSSP();
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	SPI_DisableSSP();
+	// reset memory
+	SPINOR_ResetEnable();
+	SPINOR_ResetMemory();
+	SPINOR_ReadStatus(TRUE);
+	return;
+}
+
+void SPINOR_ResetEnable(void)
+{
+	UINT8_T status, cmd[1], data[1];
+
+	cmd[0] = 0x66;
+	
+	SPI_DisableSSP();
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	SPI_DisableSSP();
+
+	return;
+}
+
+void SPINOR_ResetMemory(void)
+{
+	UINT8_T status, cmd[1], data[1];
+
+	cmd[0] = 0x99;
+	
+	SPI_DisableSSP();
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+
+	SPI_DisableSSP();
+
+	return;
+}
+
+void SPINOR_WriteStatus(unsigned char status)
+{
+	unsigned int temp;
+
+	temp = 0x01 << 8;
+	temp |= status;
+
+	SPI_DisableSSP();
+
+	SPI_ConfigDSS(16);
+
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+	
+	SPI_WriteData(temp);
+	SPI_WaitSSPComplete();
+	
+	Deassert_CS();
+	SPI_DisableSSP();
+
+	return;
+}
+
+
+void SPINOR_ReadStatus(UINT_T Wait)
+{
+	UINT_T i=0, timeout=0;
+	UINT_T read, ready, dummy, status;
+
+	status = NoError;
+	read = FALSE;	//this flag gets set when we read first entry from fifo
+	//if the caller waits to 'Wait' for the BUSY to be cleared, start READY off as FALSE
+	//if the caller doesn't wait to wait, set READY as true, so we don't wait on the bit
+	ready = (Wait) ? FALSE : TRUE;
+
+	do{
+		SPI_DisableSSP();
+		
+		SPI_ConfigDSS(16);
+		Assert_CS();
+		//fire it up
+		SPI_FireUp();
+
+		//load the command + 1 dummy byte
+		SPI_WriteData(SPI_CMD_READ_STATUS << 8);
+		SPI_WaitSSPComplete();
+		dummy = SPI_ReadData();
+		Deassert_CS();
+
+		//set the READ flag, and read the status
+		read = TRUE;
+		status = dummy & 0xFF;	//the status will be in the second byte
+
+		//set the READY flag if the status wait bit is cleared
+		if((status & 1) == 0)		// operation complete (eg. not busy)?
+			ready = TRUE;
+
+		SPI_DisableSSP();
+
+		//we need to wait until we read at least 1 valid status entry
+		//if we're waiting for the Write, wait till WIP bits goes to 0
+	}while ((!read) || (!ready));
+
+
+	//return last known status
+	return;
+}
+
+void SPINOR_WriteEnable(void)
+{
+	UINT8_T status, cmd[1], data[1];
+
+	cmd[0] = SPI_CMD_WRITE_ENABLE;
+
+	P_SPINOR_T spinor_info = getSPINor_Info();
+
+	SPI_DisableSSP();
+	
+	Assert_CS();
+	SPI_FireUp();
+		
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	//make sure SSP is disabled
+	SPI_DisableSSP();
+
+	status = SPINOR_ReadReg(SPINOR_write_enable_Status_Register);
+	if (status & BIT1 !=BIT1)
+	{
+		obm_printf("Write enable failed!!!\n\r");
+	}
+ 
+	return;
+}
+
+void SPINOR_ReadId(unsigned char *mid, unsigned short *did)
+{
+	UINT8_T cmd[4], data[4];
+
+	cmd[0] = SPI_CMD_JEDEC_ID;
+	cmd[1] = 0;
+	cmd[2] = 0;
+	cmd[3] = 0;
+
+	SPI_DisableSSP();
+
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();	
+	SPI_DisableSSP();
+
+
+	*mid = data[1];
+	*did = data[3] | (data[2] << 8);
+
+	return;
+}
+
+unsigned int SPINOR_Page_Program_DMA(unsigned int Address, unsigned int Buffer, unsigned int Size)
+{
+	unsigned int dummy, start_time, Retval = NoError;
+	DMA_CMDx_T TX_data;
+	UINT8_T cmd[4], data[4];
+	INT_T i;
+	volatile int timeout = 0xFFFFF;
+
+	cmd[0] = SPI_CMD_PROGRAM;
+	cmd[1] = ((Address & 0x00FFFFFF) >> 16) & 0xff;
+	cmd[2] = ((Address & 0x00FFFFFF) >> 8) & 0xff;
+	cmd[3] = Address & 0xFF;
+
+	TX_data.value = 0;
+	TX_data.bits.IncSrcAddr = 1;
+	TX_data.bits.FlowTrg = 1;
+	TX_data.bits.Width = 1;   //Don't need to convert Endian if transmit by byte
+	TX_data.bits.MaxBurstSize = 1;
+	TX_data.bits.Length = Size;
+
+	//setup DMA
+	//Map Device to Channels
+	XllpDmacMapDeviceToChannel(SSP_TX_DMA_DEVICE, SSP_TX_CHANNEL);
+	XllpDmacNoDescriptorFetch(SSP_TX_CHANNEL );
+
+	//turn ON user alignment - in case buffer address is 64bit aligned
+	alignChannel(SSP_TX_CHANNEL, 1);
+
+	loadNonDescriptor((unsigned int)Buffer, (unsigned int) SSP_DR, &TX_data, SSP_TX_CHANNEL);
+
+	SPI_DisableSSP();
+
+	//setup for DMA: TX and RX DMA request + DMA handles Trailing bytes
+	SPI_ConfigDMA(4, 3, 0, 0, 0);
+
+	//setup IER
+	SPI_ConfigInt(0);
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	//fire it up
+	SPI_FireUp();
+	//Kick off DMA's
+	XllpDmacStartTransfer(SSP_TX_CHANNEL);
+
+	//wait until the TX channel gets the stop interrupt
+	timeout = 0xFFFFFF;
+	while( (readDmaStatusRegister(SSP_TX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
+	{
+		ROW_DELAY(DEFAULT_TIMEOUT);
+
+		//if we've waited long enough, fail
+		if((timeout--) <= 0)
+		{
+			obm_printf("TX channel gets the stop interrupt timeout\n\r");
+			break;
+		}
+	}
+	
+	SPI_WaitSSPComplete();
+
+	Deassert_CS();
+	SPI_DisableSSP();
+
+	//clear out DMA settings
+	XllpDmacUnMapDeviceToChannel(SSP_TX_DMA_DEVICE, SSP_TX_CHANNEL);
+
+	return Retval;
+
+}
+
+unsigned int SPINOR_Read_DMA(unsigned int Offset, unsigned int Buffer, unsigned int Size)
+{
+	unsigned int i;
+	DMA_CMDx_T RX_data, TX_cmd;
+	UINT8_T data[4];
+	UINT_T command, dummy, timeout;
+
+	unsigned int * buff = (unsigned int *) Buffer;
+
+	command = SPI_CMD_READ;
+	command |= (((Offset >> 16) & 0xFF) << 8);
+	command |= (((Offset >> 8) & 0xFF) << 16);
+	command |= (((Offset >> 0) & 0xFF) << 24);
+
+	//fill out commands
+	RX_data.value = 0;
+	RX_data.bits.IncTrgAddr = 1;
+	RX_data.bits.FlowSrc = 1;
+	RX_data.bits.Width = 3;
+	RX_data.bits.MaxBurstSize = 2;
+
+	TX_cmd.value = 0;
+	TX_cmd.bits.IncSrcAddr = 1;
+	TX_cmd.bits.FlowTrg = 1;
+	TX_cmd.bits.Width = 3;
+	TX_cmd.bits.MaxBurstSize = 2;
+
+	//Map Device to Channels
+	XllpDmacMapDeviceToChannel(SSP_RX_DMA_DEVICE, SSP_RX_CHANNEL);
+	XllpDmacMapDeviceToChannel(SSP_TX_DMA_DEVICE, SSP_TX_CHANNEL);
+
+	//turn ON user alignment - in case buffer address is 64bit aligned
+	alignChannel(SSP_RX_CHANNEL, 1);
+
+	// * configure RX & TX descriptors * //
+	configDescriptor(&pRX_data, NULL, (unsigned int)SSP_DR,	(unsigned int)Buffer, &RX_data, Size, 1);
+	configDescriptor(&pTX_cmd,
+					 NULL,
+					 (unsigned int)&tx_command_spinor[0],
+					 (unsigned int)SSP_DR,
+					 &TX_cmd,
+					 Size,
+					 1);
+
+	//Load descriptors
+	loadDescriptor (&pRX_data, SSP_RX_CHANNEL);
+	loadDescriptor (&pTX_cmd, SSP_TX_CHANNEL);
+
+	SPI_DisableSSP();
+
+	//setup in 32 bit mode
+	SPI_ConfigDSS(32);
+
+    //setup for DMA: TX and RX DMA request + DMA handles Trailing bytes + FIFO RX Thresh+1
+	//SSP controller does endian convert, enable RX FIFO Auto Full Control
+	SPI_ConfigDMA(3, 3, 2, 2, 1);
+
+    //setup IER
+	SPI_ConfigInt(0);
+
+	#if ENABLE_MMU
+	dcache_clean_range(&pRX_data, sizeof(XLLP_DMAC_DESCRIPTOR_T));
+	dcache_clean_range(&pTX_cmd, sizeof(XLLP_DMAC_DESCRIPTOR_T));
+	dcache_clean_range(&tx_command_spinor[0], sizeof(tx_command_spinor));
+	dcache_invalidate_range(Buffer, Size);
+	#endif
+	
+	Assert_CS();
+	//fire it up
+	SPI_FireUp();
+
+	SPI_WriteData(command);
+	SPI_WaitSSPComplete();
+	dummy = SPI_ReadData();
+	
+	//Kick off DMA's
+	XllpDmacStartTransfer(SSP_TX_CHANNEL);
+	XllpDmacStartTransfer(SSP_RX_CHANNEL);
+
+	//wait until the RX channel gets the stop interrupt
+	timeout = 0xFFFFF;
+	while( (readDmaStatusRegister(SSP_RX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
+	{
+		ROW_DELAY(DEFAULT_TIMEOUT);
+
+		if((timeout--) <= 0)
+		{
+			obm_printf("RX channel gets the stop interrupt timeout\n\r");
+			break;
+		}
+	}
+
+	timeout = 0xFFFFF;
+	while( (readDmaStatusRegister(SSP_TX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
+	{
+		ROW_DELAY(DEFAULT_TIMEOUT);
+
+		if((timeout--) <= 0)
+		{
+			obm_printf("TX channel gets the stop interrupt timeout\n\r");
+			break;
+		}
+	}
+
+	SPI_WaitSSPComplete();
+
+	Deassert_CS();
+	SPI_DisableSSP();
+
+	//clear out DMA settings
+	XllpDmacUnMapDeviceToChannel(SSP_RX_DMA_DEVICE, SSP_RX_CHANNEL);
+	XllpDmacUnMapDeviceToChannel(SSP_TX_DMA_DEVICE, SSP_TX_CHANNEL);
+
+	return NoError;
+}
+
+
+UINT_T SPINOR_Read(UINT_T FlashOffset, UINT_T Buffer, UINT_T Size)
+{
+	UINT_T Retval = NoError, i, total_size, read_size, status;
+
+	do {
+
+		read_size = Size > SIZE_4KB ? SIZE_4KB : Size;
+	
+		Retval = SPINOR_Read_DMA(FlashOffset, Buffer, SIZE_4KB);
+
+		//update counters
+		FlashOffset+=read_size;
+		Buffer+=read_size;
+		Size-=read_size;
+
+	} while( (Size > 0) && (Retval == NoError) );
+
+	return Retval;
+}
+
+UINT_T SPINOR_EraseSector(UINT_T secAddr, UINT_T cmdSel)
+{
+	UINT_T temp, command, CMDSelect;
+	
+	SPINOR_ReadStatus(TRUE);
+	SPINOR_WriteEnable();
+	SPINOR_ReadStatus(TRUE);
+
+	switch (cmdSel)
+	{
+		case 0:
+			//obm_printf("4KB erase command 0x20\n\r");
+			CMDSelect = 0x20;
+			break;
+
+		case 1:
+			//obm_printf("32KB erase command 0xd8\n\r");
+			CMDSelect = 0xd8;
+			break;
+
+		default:
+			//obm_printf("64KB erase command 0xd8\n\r");
+			CMDSelect = 0xd8;
+			break;
+	}
+
+	if (Spansion_SPINOR_Flash)
+		command = CMDSelect << 24;
+	else
+		command = SPI_CMD_SECTOR_ERASE << 24;
+	
+	command |= secAddr & 0xFFFFFF;
+
+	SPI_DisableSSP();
+	
+	SPI_ConfigDSS(32);
+
+	Assert_CS();
+	SPI_FireUp();
+	
+	SPI_WriteData(command);
+	SPI_WaitSSPComplete();
+
+	Deassert_CS();
+	//make sure SSP is disabled
+	SPI_DisableSSP();
+
+	SPINOR_ReadStatus(TRUE);
+
+	return NoError;
+}
+
+UINT_T SPINOR_Wipe(void)
+{
+	UINT8_T cmd[1], data[1];
+
+	cmd[0] = SPI_CMD_CHIP_ERASE;
+	
+	//make sure the device is ready for the command
+	SPINOR_ReadStatus(TRUE);
+	SPINOR_WriteEnable();
+	SPINOR_ReadStatus(TRUE);
+
+	SPI_DisableSSP();
+	
+	Assert_CS();
+	SPI_FireUp();
+
+	SPI_Write_Read(cmd, data, sizeof(cmd));
+
+	Deassert_CS();
+	//make sure SSP is disabled
+	SPI_DisableSSP();
+
+	SPINOR_ReadStatus(TRUE);
+	
+	return NoError;
+}
+
+UINT_T SPINOR_Write(UINT_T Address, UINT_T Buffer, UINT_T Size)
+{
+	UINT_T Retval, i, total_size, write_size, status;
+	UINT_T *buff = (UINT_T *) Buffer;
+
+	if(Size & 0x3)    //make size 4bytes-align
+    	Size = (Size+4)&(~3);
+
+	total_size = Size >> 2;
+
+	//postprocessing... endian convert
+	if ((Address + Size) > 0x1000000)
+		return FlashAddrOutOfRange;
+
+	do {
+		//make sure the device is ready to be written to
+		SPINOR_ReadStatus(TRUE);
+		//get device ready to Program
+		SPINOR_WriteEnable();
+		
+		SPINOR_ReadStatus(TRUE);
+
+		write_size = Size > WRITE_SIZE ? WRITE_SIZE : Size;
+
+		//write a byte
+		if (write_size == WRITE_SIZE)
+		{
+			Retval = SPINOR_Page_Program_DMA(Address, Buffer, WRITE_SIZE);
+			
+			//update counters
+			Address+=WRITE_SIZE;
+			Buffer+=WRITE_SIZE;
+			Size-=WRITE_SIZE;
+		}
+		else
+		{
+			Retval = SPINOR_Page_Program_DMA(Address, Buffer, WRITE_SIZE);
+			Size=0;
+		}
+
+		SPINOR_ReadStatus(TRUE);
+
+	} while( (Size > 0) && (Retval == NoError) );
+
+	return Retval;
+}
+
+UINT_T SPINOR_Erase(UINT_T Address, UINT_T Size)
+{
+	UINT_T numSectors, i, sector_size, Retval = NoError, zero_address = 0;
+	
+	P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH);
+
+	if ((Address + Size) > 0x1000000)
+		return FlashAddrOutOfRange;
+
+	if ((Spansion_SPINOR_Flash) && (Address == 0))
+		zero_address = 1;
+
+	if (zero_address)
+	{
+		for (i = 0; i < 8; i++)
+		{
+			SPINOR_EraseSector(Address, 0);
+			Address += 0x1000;
+		}
+
+		SPINOR_EraseSector(Address, 1);
+		Address += 0x8000;
+	}
+
+	sector_size = pFlashP->BlockSize;
+
+	if (Size % pFlashP->BlockSize == 0)
+		numSectors = Size / pFlashP->BlockSize;
+	else
+		numSectors = Size / pFlashP->BlockSize + 1;
+
+	if (zero_address)
+		numSectors -= 1;
+
+	for (i = 0; i < numSectors; i++)
+	{
+		//erase this sector
+		Retval = SPINOR_EraseSector(Address, 2);
+
+		Address += sector_size;
+
+		if (Retval != NoError)
+			break;
+	}
+
+	return Retval;
+}
+