blob: 8c31a803133d9682abbeffc6f742204e086f19f0 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2013 Marvell. 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 "SPINAND.h"
#include "spi.h"
#include "Errors.h"
#include "misc.h"
#include "timer.h"
#include "PlatformConfig.h"
#include "platform_interrupts.h"
#include "xllp_dmac.h"
extern volatile P_XLLP_DMAC_T pDmacHandle;
extern UINT_T ssp_52mhz;
extern UINT_T spi_tx_dma, spi_rx_dma;
/***********************************************************
* InitializeSPINAND()
* Initializes the SSP port on the platform and issues
* a Read ID command to see if a device is connected
* returns:
* NoError - on a successful read ID
* NotFoundError - when read ID value is bogus (0xFFFF or 0x0000)
************************************************************/
UINT_T InitializeSPINAND(UINT8_T FlashNum, FlashBootType_T FlashBootType, UINT8_T* P_DefaultPartitionNum)
{
unsigned char mid, did, sn_feature;
P_FlashProperties_T pFlashP = GetFlashProperties(FlashBootType);
int i;
ssp_52mhz = 1;
ChipSelectSPINAND();
SPINAND_Reset(FlashBootType);
SPINAND_ReadID(&mid, &did);
obm_printf("Manufactory and Device ID: 0x%08x\n\r", (mid<<8)|(did));
SPINAND_UnProtectBlocks();
sn_feature = SPINAND_GetFeatures(SN_FEATURE);
obm_printf("SN_FEATURE: 0x%x\n\r", sn_feature);
if ((sn_feature & GIGA_SPINAND_FEATURE_ECC_EN) == 0)
SPINAND_SetFeatures(SN_FEATURE, (sn_feature | GIGA_SPINAND_FEATURE_ECC_EN));
//define functions
pFlashP->ReadFromFlash = &SPINAND_Read;
pFlashP->WriteToFlash = &SPINAND_Write;
pFlashP->EraseFlash = &SPINAND_Erase;
pFlashP->ResetFlash = &SPINAND_Reset;
pFlashP->FlashSettings.UseBBM = 1;
pFlashP->FlashSettings.UseSpareArea = 0;
pFlashP->PageSize = 2048;
pFlashP->BlockSize = 128*1024;
pFlashP->FlashSettings.SASize = 0;
pFlashP->FlashSettings.UseHwEcc = 0;
pFlashP->StreamingFlash = FALSE;
pFlashP->FlashType = SPI_NAND;
pFlashP->FinalizeFlash = NULL;
pFlashP->TimFlashAddress = 0;
pFlashP->NumBlocks = 1024;
*P_DefaultPartitionNum = 0;
SPI_GetSSPDMAReqNum(&spi_tx_dma, &spi_rx_dma);
return NoError;
}
/***********************************************************
* SPINAND_ReadID
* Reads the 16 bit MID and DID
* Returns:
* None
*************************************************************/
void SPINAND_ReadID(unsigned char *mid, unsigned char *did)
{
unsigned char cmd[4], data[4];
cmd[0] = SN_READ_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[2];
*did = data[3];
return;
}
// SPI NAND READ: using DMA
unsigned int SPINAND_Read(unsigned int FlashOffset, unsigned int Buffer, unsigned int Size)
{
unsigned int retval = NoError, read_size, start_time;
unsigned char status;
//calculate the initial read size (for the first page)
read_size = SN_PAGE_SIZE - (FlashOffset & (SN_PAGE_SIZE - 1)); //whole page - pre_bytes
//for each loop iteration, one page of flash will be read into internal memory
while (Size > 0)
{ //update read_size if there are post_bytes (i.e. leftover for the last page)
read_size = read_size > Size ? Size : read_size;
/** Step 1: Cache Load: Load the correct page into cache **/
SPINAND_CacheLoad(FlashOffset);
/** Step 2: Get Features: wait for OIP to be cleared **/
retval = SPINAND_CheckReady();
if(retval != NoError)
break;
/** Step 3: Cache Read: Read the page in cache to memory (DMA) **/
retval = SPINAND_CacheRead_4Bytes(FlashOffset, Buffer, read_size);
if(retval != NoError)
break;
retval = SPINAND_CheckReady();
if(retval != NoError)
break;
/** Step 4: Update counters: make sure to adjust up to a page boundary each iteration **/
FlashOffset += read_size;
Buffer += read_size;
Size -= read_size;
read_size = SN_PAGE_SIZE;
}
return retval;
}
/***********************************************************
* SPINAND_CacheLoad
* Issues command to read a page of NAND into the cache
* Inputs:
* The flash address of the page to be loaded
* Returns:
* no returns
*************************************************************/
void SPINAND_CacheLoad(unsigned int Address)
{
SN_ADDRESS_FIELD_T addr;
unsigned int input;
//store the command into the highest byte
input = SN_CACHE_LOAD << 24;
//put the 16 bits of Row Address (RA) into the lowest two bytes
addr.value = Address;
input |= (addr.fields.RA & 0xFFFF);
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);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
//load the input data
BU_REG_WRITE(SSP_DR, input);
SPI_WaitSSPComplete();
Deassert_CS();
SPI_DisableSSP();
return;
}
/***********************************************************
* SPINAND_GetFeatures
* Reads the corresponding feature value of SPI device.
* Inputs:
* The feature type to be read out
* Returns:
* status value
*************************************************************/
unsigned char SPINAND_GetFeatures(SN_Feature_E feature_type)
{
unsigned int input, status;
//fill out the command (2 bytes) plus dummy bytes for the readback
input = SN_GET_FEATURES << 24;
input |= (feature_type & 0xFF) << 16;
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);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
//load the command
BU_REG_WRITE(SSP_DR, input);
SPI_WaitSSPComplete();
Deassert_CS();
status = BU_REG_READ(SSP_DR); //actual status value
SPI_DisableSSP();
//return last known status
return (unsigned char) ((status >> 8) & 0xff);
}
/***********************************************************
* SPINAND_SetFeatures
* set the corresponding feature value of SPI device.
* Inputs:
* The feature type to be set
* Returns:
* none
*************************************************************/
unsigned char SPINAND_SetFeatures(SN_Feature_E feature_type, unsigned char feature)
{
unsigned int input;
//fill out the command (2 bytes) plus dummy bytes for the readback
input = SN_SET_FEATURES << 24;
input |= (feature_type & 0xFF) << 16;
input |= (feature & 0xff) << 8;
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);
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
//load the command
BU_REG_WRITE(SSP_DR, input);
SPI_WaitSSPComplete();
Deassert_CS();
SPI_DisableSSP();
return;
}
/***********************************************************
* SPINAND_CacheRead
* Reads the loaded page from Cache to internal memory using DMA
* Inputs:
* Offset into page
* Buffer location
* Size to be read
* Returns:
* error status
*************************************************************/
extern __attribute__ ((aligned(16))) XLLP_DMAC_DESCRIPTOR_T pRX_data, pTX_cmd;
extern __attribute__ ((aligned(16)))unsigned int tx_command[2112];
int tt = 0;
unsigned int SPINAND_CacheRead_4Bytes(unsigned int Offset, unsigned int Buffer, unsigned int Size)
{
unsigned int command, dummy, start_time, i, Retval = NoError;
SN_ADDRESS_FIELD_T addr;
DMA_CMDx_T RX_data, TX_cmd;
unsigned int * buff = (unsigned int *) Buffer;
//fill out the "command" sequence: CMD + Column Address (CA) + dummy byte
addr.value = Offset;
command = SN_CACHE_READ << 24;
command |= (addr.fields.CA << 8); //(upper bits will be 0's for the 'wrap')
command |= 0xA5; //0xA5 is a dummy byte that easily seen on a scope
tx_command[0] = command;
//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[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
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 + 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[0], sizeof(tx_command));
dcache_invalidate_range(Buffer, Size);
#endif
//fire it up
reg_bit_set(SSP_CR0, SSP_CR0_SSE);
Assert_CS();
BU_REG_WRITE(SSP_DR, tx_command[0]);
SPI_WaitSSPComplete();
BU_REG_READ(SSP_DR);
//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 Retval;
}
unsigned int SPINAND_CacheRead_1Byte(unsigned int Offset, unsigned int Buffer, unsigned int Size)
{
unsigned int command, dummy, start_time, i, Retval = NoError;
SN_ADDRESS_FIELD_T addr;
DMA_CMDx_T RX_data, TX_cmd;
unsigned char cmd[4], data[4];
unsigned int * buff = (unsigned int *) Buffer;
//fill out the "command" sequence: CMD + Column Address (CA) + dummy byte
addr.value = Offset;
cmd[0] = SN_CACHE_READ;
cmd[1] = ((addr.fields.CA >> 8) & (~0xC0)) | 0x40;
cmd[2] = addr.fields.CA & 0xff;
cmd[3] = 0xFF;
//fill out commands
RX_data.value = 0;
RX_data.bits.IncTrgAddr = 1;
RX_data.bits.FlowSrc = 1;
RX_data.bits.Width = 1;
RX_data.bits.MaxBurstSize = 1;
TX_cmd.value = 0;
TX_cmd.bits.IncSrcAddr = 1;
TX_cmd.bits.FlowTrg = 1;
TX_cmd.bits.Width = 1;
TX_cmd.bits.MaxBurstSize = 1;
//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[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|
(8 << SSP_SSCR1_TFT_BASE) |
(3 << SSP_SSCR1_RFT_BASE));
reg_write(SSP_TO, 0xffff);
//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);
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 Retval;
}
// SPI NAND WRITE: using DMA
unsigned int SPINAND_Write(unsigned int FlashOffset, unsigned int Buffer, unsigned int Size)
{
unsigned int retval = NoError, write_size;
//calculate the initial write size (for the first page)
//write_size = SN_PAGE_SIZE - (FlashOffset & (SN_PAGE_SIZE - 1)); //whole page - pre_bytes
//for each loop iteration, one page of flash will be written
while (Size > 0)
{ //update write_size if there are post_bytes (i.e. leftover for the last page)
write_size = Size > SN_PAGE_SIZE ? SN_PAGE_SIZE : Size;
/** Step 1: Program Load: Load the data into cache (DMA) **/
retval = SPINAND_ProgramLoad_4Bytes(FlashOffset, Buffer, write_size);
if(retval != NoError)
break;
retval = SPINAND_CheckReady();
if(retval != NoError)
break;
/** Step 2: Write Enable: set the write enable bit **/
SPINAND_WriteEnable();
/** Step 3: Program Execute: Write the page in cache to flash **/
SPINAND_ProgramExecute(FlashOffset);
/** Step 4: Get Features: wait for OIP to be cleared **/
retval = SPINAND_CheckReady();
if(retval != NoError)
break;
/** Step 5: Update counters: make sure to adjust up to a page boundary each iteration **/
FlashOffset += write_size;
Buffer += write_size;
Size -= write_size;
write_size = SN_PAGE_SIZE;
}
return retval;
}
unsigned int SPINAND_ProgramLoad_4Bytes(unsigned int Address, unsigned int Buffer, unsigned int Size)
{
unsigned int Retval = NoError, i;
DMA_CMDx_T TX_data;
unsigned char cmd[3], data[3];
unsigned int convert_size = Size;
unsigned int * convert_buff = (unsigned int *) DDR_SPI_CONVERT_ADDR;
unsigned int * orginal_buff = (unsigned int *) Buffer;
//postprocessing... endian convert
convert_size >>= 2; //convert Size from bytes to words
for(i = 0; i < convert_size; i++)
convert_buff[i] = Endian_Convert(orginal_buff[i]);
//#if ENABLE_MMU
//dcache_invalidate_range(convert_buff, Size);
//#endif
cmd[0] = SN_PROGRAM_LOAD;
cmd[1] = 0;
cmd[2] = 0;
TX_data.value = 0;
TX_data.bits.IncSrcAddr = 1;
TX_data.bits.FlowTrg = 1;
TX_data.bits.Width = 3;
TX_data.bits.MaxBurstSize = 2;
TX_data.bits.Length = Size;
//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)convert_buff, (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 |
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);
Assert_CS();
SPI_Write_Read(cmd, data, sizeof(cmd));
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);
//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;
}
/***********************************************************
* SPINAND_ProgramLoad
* Writes a page of data to Cache from internal memory using DMA
* Inputs:
* Offset into page
* Buffer location
* Size to be write
* Returns:
* error status
*************************************************************/
unsigned int SPINAND_ProgramLoad_1Byte(unsigned int Address, unsigned int Buffer, unsigned int Size)
{
unsigned int dummy, start_time, Retval = NoError;
DMA_CMDx_T TX_data;
unsigned char cmd[3], data[3];
cmd[0] = SN_PROGRAM_LOAD;
cmd[1] = 0;
cmd[2] = 0;
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;
//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;
}
/***********************************************************
* SPINAND_WriteEnable
* Sets the WEL bit in the SPI NAND status register,
* allowing the device to be programmed or erased
* Returns:
* none
*************************************************************/
void SPINAND_WriteEnable(void)
{
unsigned char cmd[1], data[1];
cmd[0] = SN_WRITE_ENABLE;
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();
}
/***********************************************************
* SPINAND_ProgramExecute
* Issues command to program a page of NAND from the cache
* Inputs:
* The flash address of the page to be loaded
* Returns:
* no returns
*************************************************************/
void SPINAND_ProgramExecute(unsigned int Address)
{
unsigned char cmd[4], data[4];
cmd[0] = SN_PROGRAM_EXECUTE;
cmd[1] = ((Address>>11)&0xffff) >> 16;
cmd[2] = ((Address>>11)&0xffff) >> 8;
cmd[3] = ((Address>>11)&0xffff);
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;
}
// SPI NAND ERASE: Erases 1 whole block at a time
unsigned int SPINAND_Erase(unsigned int FlashOffset, unsigned int Size)
{
unsigned int retval = NoError;
//adjust the size/offset fields to start on a block boundary
Size += FlashOffset & (SN_BLOCK_SIZE - 1);
FlashOffset &= ~(SN_BLOCK_SIZE - 1);
//for each loop iteration, one block of flash will be erased
while (Size > 0)
{ /** Step 1: Write Enable: set the write enable bit **/
SPINAND_WriteEnable();
/** Step 2: Block Erase: erase 1 block **/
SPINAND_BlockErase(FlashOffset);
/** Step 3: Get Features: wait for OIP to be cleared **/
retval = SPINAND_CheckReady();
if(retval != NoError)
break;
/** Step 4: Update counters **/
FlashOffset += SN_BLOCK_SIZE;
Size = (Size > SN_BLOCK_SIZE) ? (Size - SN_BLOCK_SIZE) : 0;
}
return retval;
}
/***********************************************************
* SPINAND_BlockErase
* Issues command to erase 1 block of flash
* Inputs:
* The flash address of the block to be erased
* Returns:
* no returns
*************************************************************/
void SPINAND_BlockErase(unsigned int Address)
{
unsigned char cmd[4], data[4];
cmd[0] = SN_BLOCK_ERASE;
cmd[1] = ((Address>>11)&0xffff) >> 16;
cmd[2] = ((Address>>11)&0xffff) >> 8;
cmd[3] = ((Address>>11)&0xffff);
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;
}
/***********************************************************
* SPINAND_Reset
* Issues command to reset flash
* Inputs:
* The flash boot type
* Returns:
* no error
*************************************************************/
unsigned int SPINAND_Reset(FlashBootType_T fbt)
{
unsigned char cmd[1], data[1];
cmd[0] = SN_RESET;
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 NoError;
}
/***********************************************************
* SPINAND_UnProtectBlocks
* unprotect the protected flash blocks
* Inputs:
* none
* Returns:
* none
*************************************************************/
void SPINAND_UnProtectBlocks(void)
{
unsigned char protection;
protection = SPINAND_GetFeatures(SN_PROTECTION);
obm_printf("SN_PROTECTION: 0x%x\n\r", protection);
if ((protection & (GIGA_SPINAND_PROTECTION_BP2 |
GIGA_SPINAND_PROTECTION_BP1 |
GIGA_SPINAND_PROTECTION_BP0)) == 0)
{
obm_printf("Giga SPINAND is already unprotected\n\r");
return;
}
else
{
obm_printf("Giga SPINAND is not unprotected\n\r");
}
// clear BP0/BP1/BP2
protection &= ~(GIGA_SPINAND_PROTECTION_BP2 |
GIGA_SPINAND_PROTECTION_BP1 |
GIGA_SPINAND_PROTECTION_BP0);
SPINAND_SetFeatures(SN_PROTECTION, protection);
obm_printf("Giga SPINAND unprotect done\n\r");
}
UINT_T SPINAND_CheckReady(void)
{
unsigned int start_time, retval = NoError;
unsigned char status;
start_time = GetOSCR0();
do
{ //Read the Status register on the device
status = SPINAND_GetFeatures(SN_STATUS);
//Check for timeout
if( OSCR0IntervalInMilli(start_time, GetOSCR0()) > 5 )
retval = SPINANDCheckReadyTimeOutError;
if (status & GIGA_SPINAND_STATUS_P_FAIL)
retval = SPI_PROGRAMFAIL;
if (status & GIGA_SPINAND_STATUS_E_FAIL)
retval = SPI_ERASEFAIL;
//stay in loop if OIP bit is still high AND no timeout error has occured
} while( (status & GIGA_SPINAND_STATUS_OIP) && (retval == NoError) );
return retval;
}