blob: 87afb01f1689cd8637c92f201d6c363fb6a8f770 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2014 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 "SPINOR_extened.h"
extern __attribute__ ((aligned(16))) XLLP_DMAC_DESCRIPTOR_T pRX_data, pTX_cmd;
extern VUINT_T ssp_52mhz;
extern UINT_T Spansion_SPINOR_Flash;
__attribute__ ((aligned(16)))unsigned char tx_command_spinor[SIZE_4KB] = {0};
extern UINT_T spi_tx_dma, spi_rx_dma;
unsigned int Extend_Read(unsigned int Offset, unsigned int Buffer, unsigned int Size)
{
unsigned int i;
DMA_CMDx_T RX_data, TX_cmd;
UINT8_T data[5];
unsigned int * buff = (unsigned int *) Buffer;
P_SPINOR_T spinor_info = getSPINor_Info();
tx_command_spinor[0] = spinor_info->read_4bytes_cmd;
tx_command_spinor[1] = (Offset >> 24) & 0xFF;
tx_command_spinor[2] = (Offset >> 16) & 0xFF;
tx_command_spinor[3] = (Offset >> 8) & 0xFF;
tx_command_spinor[4] = (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|
(8 << SSP_SSCR1_TFT_BASE) | // TFT: 3
(3 << SSP_SSCR1_RFT_BASE)); // RFT: 4
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, 5);
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|
(8 << SSP_SSCR1_TFT_BASE) | // TFT: 3
(3 << SSP_SSCR1_RFT_BASE)); // RFT: 4
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_Extend_Read(UINT_T FlashOffset, UINT_T Buffer, UINT_T Size)
{
UINT_T Retval, i, total_size, read_size, status;
do {
read_size = Size > SIZE_4KB ? SIZE_4KB : Size;
Retval = Extend_Read(FlashOffset, Buffer, SIZE_4KB);
//update counters
FlashOffset+=read_size;
Buffer+=read_size;
Size-=read_size;
} while( (Size > 0) && (Retval == NoError) );
return Retval;
}
unsigned int Extend_Write(unsigned int Address, unsigned int Buffer, unsigned int Size)
{
unsigned int i;
DMA_CMDx_T TX_data;
unsigned char cmd[5], data[5];
P_SPINOR_T spinor_info = getSPINor_Info();
unsigned int convert_size = Size;
unsigned int * convert_buff = NULL;
unsigned int * orginal_buff = (unsigned int *) Buffer;
convert_buff = (unsigned int *) malloc(Size);
if(convert_buff == NULL)
return HeapExhaustedError;
#if 1
//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]);
cmd[0] = spinor_info->write_4bytes_cmd;
cmd[1] = (Address >> 24) & 0xFF;
cmd[2] = (Address >> 16) & 0xFF;
cmd[3] = (Address >> 8) & 0xFF;
cmd[4] = (Address >> 0) & 0xFF;
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;
//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)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);
free(convert_buff);
return NoError;
}
UINT_T SPINOR_Extend_Write(UINT_T Address, UINT_T Buffer, UINT_T Size)
{
UINT_T Retval = NoError, i, total_size, write_size, status;
UINT_T *buff = (UINT_T *) Buffer;
UINT8_T status1;
if(Size & 0x3) //make size 4bytes-align
Size = (Size+4)&(~3);
total_size = Size >> 2;
if ((Address + Size) > 0x2000000)
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 = Extend_Write(Address, Buffer, WRITE_SIZE);
//update counters
Address+=WRITE_SIZE;
Buffer+=WRITE_SIZE;
Size-=WRITE_SIZE;
}
else
{
Retval = Extend_Write(Address, Buffer, WRITE_SIZE);
Size=0;
}
SPINOR_ReadStatus(TRUE);
} while( (Size > 0) && (Retval == NoError) );
return Retval;
}
UINT_T Extend_EraseSector(UINT_T secAddr, UINT_T cmdSel)
{
UINT_T Retval = NoError, CMDSelect;
unsigned char cmd[5], data[5];
P_SPINOR_T spinor_info = getSPINor_Info();
switch (cmdSel)
{
case 0:
//obm_printf("4KB erase command 0x21\n\r");
CMDSelect = 0x21;
break;
case 1:
//obm_printf("32KB erase command 0xdc\n\r");
CMDSelect = 0xdc;
break;
default:
//obm_printf("64KB erase command 0xdc\n\r");
CMDSelect = 0xdc;
break;
}
SPINOR_ReadStatus(TRUE);
SPINOR_WriteEnable();
SPINOR_ReadStatus(TRUE);
if (Spansion_SPINOR_Flash)
cmd[0] = CMDSelect;
else
cmd[0] = spinor_info->erase_4bytes_cmd;
cmd[1] = (secAddr >> 24) & 0xFF;
cmd[2] = (secAddr >> 16) & 0xFF;
cmd[3] = (secAddr >> 8) & 0xFF;
cmd[4] = (secAddr >> 0) & 0xFF;
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));
SPI_WaitSSPComplete();
Deassert_CS();
//make sure SSP is disabled
SPI_DisableSSP();
return Retval;
}
UINT_T SPINOR_Extend_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) > 0x2000000)
return FlashAddrOutOfRange;
if ((Spansion_SPINOR_Flash) && (Address == 0))
zero_address = 1;
if (zero_address)
{
for (i = 0; i < 8; i++)
{
Extend_EraseSector(Address, 0);
Address += 0x1000;
}
Extend_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++)
{
Retval = Extend_EraseSector(Address, 2);
Address += sector_size;
if (Retval != NoError)
break;
}
return Retval;
}