|  | /****************************************************************************** | 
|  | * | 
|  | *  (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 UINT_T Spansion_SPINOR_Flash; | 
|  | extern __attribute__ ((aligned(16)))unsigned char	 tx_command_spinor[SIZE_4KB] = {0}; | 
|  |  | 
|  | unsigned int Extend_Read(unsigned int Offset, unsigned int Buffer, unsigned int Size) | 
|  | { | 
|  | unsigned int i, timeout; | 
|  | 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(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(); | 
|  |  | 
|  | #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 | 
|  | SPI_FireUp(); | 
|  |  | 
|  | Assert_CS(); | 
|  |  | 
|  | SPI_Write_Read(tx_command_spinor, data, 5); | 
|  |  | 
|  | SPI_DisableSSP(); | 
|  | 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); | 
|  |  | 
|  | //fire it up | 
|  | SPI_FireUp(); | 
|  |  | 
|  | //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_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, timeout; | 
|  | 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]); | 
|  | #endif | 
|  |  | 
|  | 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(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)convert_buff, (unsigned int) SSP_DR, &TX_data, SSP_TX_CHANNEL); | 
|  |  | 
|  | SPI_DisableSSP(); | 
|  |  | 
|  | Assert_CS(); | 
|  | //fire it up | 
|  | SPI_FireUp(); | 
|  |  | 
|  | SPI_Write_Read(cmd, data, sizeof(cmd)); | 
|  |  | 
|  | SPI_DisableSSP(); | 
|  | SPI_ConfigDSS(32); | 
|  |  | 
|  | //setup for DMA: TX and RX DMA request + DMA handles Trailing bytes | 
|  | SPI_ConfigDMA(4, 3, 0, 0, 0); | 
|  |  | 
|  | //setup IER | 
|  | SPI_ConfigInt(0); | 
|  |  | 
|  | //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); | 
|  |  | 
|  | 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(); | 
|  |  | 
|  | //fire it up | 
|  | SPI_FireUp(); | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  |