| /****************************************************************************** |
| * |
| * (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" |
| |
| #define DEFAULT_TIMEOUT 3000 |
| #define DEFAULT_WAIT_TIME 1000 |
| #define WRITE_SIZE (256) |
| extern UINT_T MPUFlag; |
| |
| //limited for timing and stack concerns (see SPI_page_write routine) |
| #define SSP_READ_TIME_OUT_MILLI 0x2000 |
| #define SSP_READ_DMA_DESC 0x10 //total RX descriptors |
| #define SSP_READ_DMA_SIZE 0x1ff8 //bytes per descriptor |
| #define SSP_MAX_TX_SIZE_WORDS 64 |
| #define SSP_MAX_TX_SIZE_BYTES SSP_MAX_TX_SIZE_WORDS << 2 |
| |
| |
| __attribute__ ((aligned(32))) XLLP_DMAC_DESCRIPTOR_T pRX_data, pTX_cmd; |
| __attribute__ ((aligned(32)))unsigned int tx_command[2112] = {0}; |
| /*********************************************************** |
| * 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, UINT8_T* P_DefaultPartitionNum) |
| { |
| unsigned char mid, did, sn_feature; |
| P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH); |
| int retval; |
| UINT_T ID; |
| |
| ChipSelectSPINAND(); |
| |
| SPI_ConfigCS(); |
| |
| SPINAND_Reset(BOOT_FLASH); |
| retval = SPINAND_CheckReady(); |
| if(retval != NoError) |
| { |
| obm_printf("SPINAND_Reset error\n\r"); |
| } |
| |
| 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 = 1020; |
| |
| *P_DefaultPartitionNum = 0; |
| |
| //fill tx dummy buffer with special pattern |
| memset(tx_command, 0xA5, sizeof(tx_command)); |
| |
| 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(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| 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; |
| 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 |
| SPI_ConfigDSS(32); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| //load the input data |
| SPI_WriteData(input); |
| SPI_WaitSSPComplete(); |
| |
| SPI_DisableSSP(); |
| Deassert_CS(); |
| |
| 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) |
| { |
| UINT status, i; |
| UINT8 cmd[3], data[3]; |
| //fill out the command (2 bytes) plus dummy bytes for the readback |
| cmd[0] = SN_GET_FEATURES; |
| cmd[1] = feature_type; |
| cmd[2] = 0; |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| SPI_Write_Read(cmd, data, sizeof(cmd)); |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| Deassert_CS(); |
| |
| //return last known status |
| return data[2]; |
| } |
| |
| unsigned char SPINAND_SetFeatures(SN_Feature_E feature_type, unsigned char feature) |
| { |
| UINT i; |
| UINT8 cmd[3], data[3];; |
| |
| //fill out the command (2 bytes) plus data byte |
| cmd[0] = SN_SET_FEATURES; |
| cmd[1] = feature_type; |
| cmd[2] = feature; |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| SPI_Write_Read(cmd, data, sizeof(cmd)); |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| Deassert_CS(); |
| |
| return 0; |
| } |
| |
| /*********************************************************** |
| * 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 |
| *************************************************************/ |
| 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 timeout = 0xFFFFF; |
| unsigned int recv_buf = 0; |
| |
| #ifndef HW_ENDIAN_CONVERT |
| unsigned int * convert_buff, * orginal_buff, convert_size; |
| recv_buf = malloc(Size); |
| if(recv_buf == 0) |
| return HeapExhaustedError; |
| #else |
| recv_buf = Buffer; |
| #endif |
| |
| //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 |
| |
| //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 = 1; |
| |
| TX_cmd.value = 0; |
| TX_cmd.bits.IncSrcAddr = 1; |
| TX_cmd.bits.FlowTrg = 1; |
| TX_cmd.bits.Width = 3; |
| TX_cmd.bits.MaxBurstSize = 1; |
| |
| //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, recv_buf, &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 |
| SPI_ConfigDSS(32); |
| |
| //setup for DMA: TX and RX DMA request + DMA handles Trailing bytes |
| #ifdef HW_ENDIAN_CONVERT |
| SPI_ConfigDMA(4, 3, 2, 0, 1); |
| #else |
| SPI_ConfigDMA(4, 3, 0, 0, 0); |
| #endif |
| |
| //setup IER |
| SPI_ConfigInt(0); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| #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(recv_buf, Size); |
| #endif |
| |
| 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); |
| |
| #if LZMA_SUPPORT |
| //if (MPUFlag == 1) // only for boot |
| // CacheInvalidateMemory(Buffer, Size + 4); |
| #endif |
| |
| #ifndef HW_ENDIAN_CONVERT |
| //postprocessing... endian convert |
| convert_buff = (unsigned int *) Buffer; |
| orginal_buff = (unsigned int *) recv_buf; |
| convert_size = Size >> 2; //convert Size from bytes to words |
| for(i = 0; i < convert_size; i++) |
| convert_buff[i] = Endian_Convert(orginal_buff[i]); |
| free(recv_buf); |
| #endif |
| |
| 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 |
| //unlock all blocks before programming any thing |
| SPINAND_SetFeatures(SN_PROTECTION, 0x00); |
| |
| //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 0: Write Enable: set the write enable bit **/ |
| SPINAND_WriteEnable(); |
| |
| /** Step 1: Program Load: Load the data into cache (DMA) **/ |
| retval = SPINAND_ProgramLoad_4Bytes(FlashOffset, Buffer, write_size); |
| //retval = SPINAND_ProgramLoadPIO(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; |
| volatile int timeout = 0xFFFFF; |
| |
| 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; //Don't need to convert Endian if transmit by byte |
| TX_data.bits.MaxBurstSize = 1; |
| TX_data.bits.Length = Size; |
| |
| //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); |
| SPI_ConfigInt(0); |
| |
| //setup IER |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| SPI_Write_Read(cmd, data, sizeof(cmd)); |
| |
| //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; |
| |
| } |
| |
| /*********************************************************** |
| * 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_ProgramLoadPIO(unsigned int Address, unsigned int Buffer, unsigned int Size) |
| { |
| int i = 0; |
| unsigned int Retval = NoError; |
| unsigned char cmd[3], dummy, *data; |
| |
| #if 0 |
| P_FlashProperties_T pFlashP = GetFlashProperties(BOOT_FLASH); |
| |
| //fill out the command (2 bytes) plus data byte |
| cmd[0] = SN_PROGRAM_LOAD; |
| cmd[1] = ((Address & (pFlashP->PageSize - 1)) >> 8) & 0xFF; |
| cmd[2] = Address & 0xFF; |
| #else |
| cmd[0] = SN_PROGRAM_LOAD; |
| cmd[1] = 0; |
| cmd[2] = 0; |
| #endif |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| |
| //fire it up |
| SPI_FireUp(); |
| |
| Assert_CS(); |
| |
| for(i = 0; i < 3; i++) |
| { |
| *SSP_DR = cmd[i]; |
| |
| SPI_WaitSSPComplete(); |
| |
| dummy = *SSP_DR; |
| } |
| |
| data = (UINT8 *)Buffer; |
| for(i = 0; i < Size; i++) |
| { |
| *SSP_DR = data[i]; |
| |
| SPI_WaitSSPComplete(); |
| |
| dummy = *SSP_DR; |
| } |
| |
| Deassert_CS(); |
| |
| //make sure SSP is disabled |
| SPI_DisableSSP(); |
| |
| 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(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| 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(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| 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); |
| |
| //unlock all blocks before erase |
| SPINAND_SetFeatures(SN_PROTECTION, 0x00); |
| |
| //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(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| 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(); |
| |
| Assert_CS(); |
| //fire it up |
| SPI_FireUp(); |
| |
| 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_BP3 | |
| GIGA_SPINAND_PROTECTION_BP2 | |
| GIGA_SPINAND_PROTECTION_BP1 | |
| GIGA_SPINAND_PROTECTION_BP0)) == 0) |
| { |
| obm_printf("SPINAND is already unprotected\n\r"); |
| return; |
| } |
| else |
| { |
| obm_printf("SPINAND is not unprotected\n\r"); |
| } |
| |
| // clear BP0/BP1/BP2 |
| protection &= ~(GIGA_SPINAND_PROTECTION_BP3 | |
| GIGA_SPINAND_PROTECTION_BP2 | |
| GIGA_SPINAND_PROTECTION_BP1 | |
| GIGA_SPINAND_PROTECTION_BP0); |
| |
| //SPINAND_SetFeatures(SN_PROTECTION, protection); |
| SPINAND_SetFeatures(SN_PROTECTION, 0); |
| |
| obm_printf("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 ) |
| { |
| obm_printf("SPINAND_CheckReady: SPINANDCheckReadyTimeOutError\n\r"); |
| retval = SPINANDCheckReadyTimeOutError; |
| } |
| |
| if (status & GIGA_SPINAND_STATUS_P_FAIL) |
| { |
| obm_printf("SPINAND_CheckReady: SPI_PROGRAMFAIL\n\r"); |
| retval = SPI_PROGRAMFAIL; |
| } |
| |
| if (status & GIGA_SPINAND_STATUS_E_FAIL) |
| { |
| obm_printf("SPINAND_CheckReady: SPI_ERASEFAIL\n\r"); |
| 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; |
| } |
| |