blob: 86666c368281d26a1a753ad67b6286042aeaf227 [file] [log] [blame]
/******************************************************************************
*
* (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;
extern UINT_T ssp_52mhz;
extern UINT_T spi_tx_dma, spi_rx_dma;
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;
}
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();
SPINOR_Reset();
SPINOR_ReadId(&mid, &did);
obm_printf("Manufacturer ID: %x, device ID: %x\n\r", mid, did);
ssp_52mhz = 0;
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;
default:
break;
}
if (spinor_info->large_capacity == 1) // 1: 32MB, 2: 64MB???
{
Flash_size = 0x02000000;
pFlashP->ReadFromFlash = &SPINOR_Extend_Read;
pFlashP->WriteToFlash = &SPINOR_Extend_Write;
pFlashP->EraseFlash = &SPINOR_Extend_Erase;
}
else
{
pFlashP->ReadFromFlash = &SPINOR_Read;
pFlashP->WriteToFlash = &SPINOR_Write;
pFlashP->EraseFlash = &SPINOR_Erase;
}
SPINOR_Enable4BytesMode();
SPINOR_UnProtectBlocks();
SPI_GetSSPDMAReqNum(&spi_tx_dma, &spi_rx_dma);
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();
//need to use 32bits data
reg_bit_set(SSP_CR0, SSP_CR0_DSS_16);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
*SSP_DR = command << 8;
SPI_WaitSSPComplete();
dummy = *SSP_DR;
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();
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//need to use 24bit data
reg_bit_set(SSP_CR0, SSP_CR0_DSS_16);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
BU_REG_WRITE(SSP_DR, temp);
SPI_WaitSSPComplete();
Deassert_CS();
SPI_DisableSSP();
return;
}
void SPINOR_ReadStatus(UINT_T Wait)
{
UINT_T i=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();
//need to use 32bits data
reg_bit_set(SSP_CR0, SSP_CR0_DSS_16);
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
//load the command + 1 dummy byte
BU_REG_WRITE(SSP_DR, SPI_CMD_READ_STATUS << 8);
SPI_WaitSSPComplete();
Deassert_CS();
dummy = *SSP_DR;
//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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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];
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;
TX_data.bits.MaxBurstSize = 1;
TX_data.bits.Length = Size;
//setup DMA
//Map Device to Channels
XllpDmacMapDeviceToChannel(spi_tx_dma, 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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//setup for DMA: TX and RX DMA request
reg_bit_set(SSP_CR1, SSP_SSCR1_TRAIL |
SSP_SSCR1_TSRE |
SSP_SSCR1_RSRE |
(8 << SSP_SSCR1_TFT_BASE) |
(3 << SSP_SSCR1_RFT_BASE));
//reg_write(SSP_TO, 0xfff);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
SPI_Write_Read(cmd, data, sizeof(cmd));
//Kick off DMA's
XllpDmacStartTransfer(SSP_TX_CHANNEL);
//wait until the RX channel gets the stop interrupt
while( (readDmaStatusRegister(SSP_TX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
ROW_DELAY(DEFAULT_TIMEOUT);
SPI_WaitSSPComplete();
Deassert_CS();
SPI_DisableSSP();
//clear out DMA settings
XllpDmacUnMapDeviceToChannel(spi_tx_dma, SSP_TX_CHANNEL);
return Retval;
}
extern __attribute__ ((aligned(16))) XLLP_DMAC_DESCRIPTOR_T pRX_data, pTX_cmd;
extern __attribute__ ((aligned(16)))unsigned char tx_command_spinor[SIZE_4KB];
int ii = 0;
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];
unsigned int * buff = (unsigned int *) Buffer;
tx_command_spinor[0] = SPI_CMD_READ;
tx_command_spinor[1] = (Offset >> 16) & 0xFF;
tx_command_spinor[2] = (Offset >> 8) & 0xFF;
tx_command_spinor[3] = (Offset >> 0) & 0xFF;
//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(spi_rx_dma, SSP_RX_CHANNEL);
XllpDmacMapDeviceToChannel(spi_tx_dma, 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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//setup for DMA: TX and RX DMA request + DMA handles Trailing bytes
reg_bit_set(SSP_CR1, SSP_SSCR1_TRAIL |
SSP_SSCR1_TSRE |
SSP_SSCR1_RSRE |
SSP_SSCR1_TINTE|
(3 << SSP_SSCR1_TFT_BASE) |
(4 << SSP_SSCR1_RFT_BASE));
reg_write(SSP_TO, 0x400);
#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
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
SPI_Write_Read(tx_command_spinor, data, 4);
SPI_DisableSSP();
//setup in 32 bit mode
reg_bit_set(SSP_CR0, SSP_CR0_DSS_32);
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
//setup for DMA: TX and RX DMA request
reg_bit_set(SSP_CR1, SSP_SSCR1_TRAIL |
SSP_SSCR1_TSRE |
SSP_SSCR1_RSRE |
SSP_SSCR1_TINTE|
(3 << SSP_SSCR1_TFT_BASE) |
(4 << SSP_SSCR1_RFT_BASE));
reg_write(SSP_TO, 0x400);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
//Kick off DMA's
XllpDmacStartTransfer(SSP_TX_CHANNEL);
XllpDmacStartTransfer(SSP_RX_CHANNEL);
//wait until the RX channel gets the stop interrupt
while( (readDmaStatusRegister(SSP_RX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
ROW_DELAY(DEFAULT_TIMEOUT);
while( (readDmaStatusRegister(SSP_TX_CHANNEL) & XLLP_DMAC_DCSR_STOP_INTR) != XLLP_DMAC_DCSR_STOP_INTR )
ROW_DELAY(DEFAULT_TIMEOUT);
SPI_WaitSSPComplete();
Deassert_CS();
SPI_DisableSSP();
//clear out DMA settings
XllpDmacUnMapDeviceToChannel(spi_rx_dma, SSP_RX_CHANNEL);
XllpDmacUnMapDeviceToChannel(spi_tx_dma, SSP_TX_CHANNEL);
//postprocessing... endian convert
Size >>= 2; //convert Size from bytes to words
for(i = 0; i < Size; i++)
buff[i] = Endian_Convert(buff[i]);
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();
reg_bit_set(SSP_CR0, SSP_CR0_DSS_32);
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
BU_REG_WRITE(SSP_DR, 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();
// workaround for 52MHz SPI bit shift
if (ssp_52mhz)
reg_bit_set(SSP_CR0, SSP_SSCR0_52MM);
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
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;
//for(i = 0; i < total_size; i++)
// buff[i] = Endian_Convert(buff[i]);
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;
}