aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c')
-rw-r--r--thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c
new file mode 100644
index 0000000..7139219
--- /dev/null
+++ b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Composite_Example/src/nand_if.c
@@ -0,0 +1,557 @@
+/**
+ ******************************************************************************
+ * @file nand_if.c
+ * @author MCD Application Team
+ * @version V4.0.0
+ * @date 21-January-2013
+ * @brief manage NAND operations state machine
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+#include "platform_config.h"
+
+#ifdef USE_STM3210E_EVAL
+/* Includes ------------------------------------------------------------------*/
+#include "nand_if.h"
+#include "mass_mal.h"
+#include "fsmc_nand.h"
+#include "memory.h"
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* extern variables-----------------------------------------------------------*/
+extern uint32_t SCSI_LBA;
+extern uint32_t SCSI_BlkLen;
+/* Private variables ---------------------------------------------------------*/
+uint16_t LUT[1024]; //Look Up Table Buffer
+WRITE_STATE Write_State;
+BLOCK_STATE Block_State;
+NAND_ADDRESS wAddress, fAddress;
+uint16_t phBlock, LogAddress, Initial_Page, CurrentZone = 0;
+uint16_t Written_Pages = 0;
+
+uint16_t LUT[1024]; //Look Up Table Buffer
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+static uint16_t NAND_CleanLUT(uint8_t ZoneNbr);
+static NAND_ADDRESS NAND_GetAddress(uint32_t Address);
+static uint16_t NAND_GetFreeBlock(void);
+static uint16_t NAND_Write_Cleanup(void);
+SPARE_AREA ReadSpareArea(uint32_t address);
+static uint16_t NAND_Copy(NAND_ADDRESS Address_Src, NAND_ADDRESS Address_Dest, uint16_t PageToCopy);
+static NAND_ADDRESS NAND_ConvertPhyAddress(uint32_t Address);
+static uint16_t NAND_BuildLUT(uint8_t ZoneNbr);
+
+/*******************************************************************************
+* Function Name : NAND_Init
+* Description : Init NAND Interface
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+uint16_t NAND_Init(void)
+{
+ uint16_t Status = NAND_OK;
+
+ FSMC_NAND_Init();
+ Status = NAND_BuildLUT(0);
+ Write_State = WRITE_IDLE;
+ return Status;
+}
+
+/*******************************************************************************
+* Function Name : NAND_Write
+* Description : write one sector by once
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+uint16_t NAND_Write(uint32_t Memory_Offset, uint32_t *Writebuff, uint16_t Transfer_Length)
+{
+ /* check block status and calculate start and end addresses */
+ wAddress = NAND_GetAddress(Memory_Offset / 512);
+
+ /*check Zone: if second zone is requested build second LUT*/
+ if (wAddress.Zone != CurrentZone)
+ {
+ CurrentZone = wAddress.Zone;
+ NAND_BuildLUT(CurrentZone);
+ }
+
+ phBlock = LUT[wAddress.Block]; /* Block Index + flags */
+ LogAddress = wAddress.Block ; /* save logical block */
+
+ /* IDLE state */
+ /****************/
+ if ( Write_State == WRITE_IDLE)
+ {/* Idle state */
+
+ if (phBlock & USED_BLOCK)
+ { /* USED BLOCK */
+
+ Block_State = OLD_BLOCK;
+ /* Get a free Block for swap */
+ fAddress.Block = NAND_GetFreeBlock();
+ fAddress.Zone = wAddress.Zone;
+ Initial_Page = fAddress.Page = wAddress.Page;
+
+ /* write the new page */
+ FSMC_NAND_WriteSmallPage((uint8_t *)Writebuff, fAddress, PAGE_TO_WRITE);
+ Written_Pages++;
+
+ /* get physical block */
+ wAddress.Block = phBlock & 0x3FF;
+
+
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ NAND_Write_Cleanup();
+ Written_Pages = 0;
+ return NAND_OK;
+ }
+ else
+ {
+ if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
+ {
+ NAND_Write_Cleanup();
+ return NAND_OK;
+ }
+ Write_State = WRITE_ONGOING;
+ return NAND_OK;
+ }
+ }
+ else
+ {/* UNUSED BLOCK */
+
+ Block_State = UNUSED_BLOCK;
+ /* write the new page */
+ wAddress.Block = phBlock & 0x3FF;
+ FSMC_NAND_WriteSmallPage( (uint8_t *)Writebuff , wAddress, PAGE_TO_WRITE);
+
+ Written_Pages++;
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ Written_Pages = 0;
+ NAND_Write_Cleanup();
+ return NAND_OK;
+ }
+ else
+ {
+ Write_State = WRITE_ONGOING;
+ return NAND_OK;
+ }
+ }
+ }
+ /* WRITE state */
+ /***************/
+ if ( Write_State == WRITE_ONGOING)
+ {/* Idle state */
+ if (phBlock & USED_BLOCK)
+ { /* USED BLOCK */
+
+ wAddress.Block = phBlock & 0x3FF;
+ Block_State = OLD_BLOCK;
+ fAddress.Page = wAddress.Page;
+
+ /* check if next pages are in next block */
+ if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
+ {
+ /* write Last page */
+ FSMC_NAND_WriteSmallPage( (uint8_t *)Writebuff , fAddress, PAGE_TO_WRITE);
+ Written_Pages++;
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ Written_Pages = 0;
+ }
+ /* Clean up and Update the LUT */
+ NAND_Write_Cleanup();
+ Write_State = WRITE_IDLE;
+ return NAND_OK;
+ }
+
+ /* write next page */
+ FSMC_NAND_WriteSmallPage( (uint8_t *)Writebuff , fAddress, PAGE_TO_WRITE);
+ Written_Pages++;
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ Write_State = WRITE_IDLE;
+ NAND_Write_Cleanup();
+ Written_Pages = 0;
+ }
+
+ }
+ else
+ {/* UNUSED BLOCK */
+ wAddress.Block = phBlock & 0x3FF;
+ /* check if it is the last page in prev block */
+ if (wAddress.Page == (NAND_BLOCK_SIZE - 1))
+ {
+ /* write Last page */
+ FSMC_NAND_WriteSmallPage( (uint8_t *)Writebuff , wAddress, PAGE_TO_WRITE);
+ Written_Pages++;
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ Written_Pages = 0;
+ }
+
+ /* Clean up and Update the LUT */
+ NAND_Write_Cleanup();
+ Write_State = WRITE_IDLE;
+
+
+
+ return NAND_OK;
+ }
+ /* write next page in same block */
+ FSMC_NAND_WriteSmallPage( (uint8_t *)Writebuff , wAddress, PAGE_TO_WRITE);
+ Written_Pages++;
+ if (Written_Pages == SCSI_BlkLen)
+ {
+ Write_State = WRITE_IDLE;
+ NAND_Write_Cleanup();
+ Written_Pages = 0;
+ }
+ }
+ }
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_Read
+* Description : Read sectors
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+uint16_t NAND_Read(uint32_t Memory_Offset, uint32_t *Readbuff, uint16_t Transfer_Length)
+{
+ NAND_ADDRESS phAddress;
+
+ phAddress = NAND_GetAddress(Memory_Offset / 512);
+
+ if (phAddress.Zone != CurrentZone)
+ {
+ CurrentZone = phAddress.Zone;
+ NAND_BuildLUT(CurrentZone);
+ }
+
+ if (LUT [phAddress.Block] & BAD_BLOCK)
+ {
+ return NAND_FAIL;
+ }
+ else
+ {
+ phAddress.Block = LUT [phAddress.Block] & ~ (USED_BLOCK | VALID_BLOCK);
+ FSMC_NAND_ReadSmallPage ( (uint8_t *)Readbuff , phAddress, Transfer_Length / 512);
+ }
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_CleanLUT
+* Description : Erase old blocks & rebuild the look up table
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+static uint16_t NAND_CleanLUT (uint8_t ZoneNbr)
+{
+#ifdef WEAR_LEVELLING_SUPPORT
+ uint16_t BlockIdx, LUT_Item;
+#endif
+ /* Rebuild the LUT for the current zone */
+ NAND_BuildLUT (ZoneNbr);
+
+#ifdef WEAR_LEVELLING_SUPPORT
+ /* Wear Leveling : circular use of free blocks */
+ LUT_Item = LUT [BlockIdx]
+ for (BlockIdx == MAX_LOG_BLOCKS_PER_ZONE ; BlockIdx < MAX_LOG_BLOCKS_PER_ZONE + WEAR_DEPTH ; BlockIdx++)
+ {
+ LUT [BlockIdx] = LUT [BlockIdx + 1];
+ }
+ LUT [ MAX_LOG_BLOCKS_PER_ZONE + WEAR_DEPTH - 1] = LUT_Item ;
+#endif
+
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_GetAddress
+* Description : Translate logical address into a phy one
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+static NAND_ADDRESS NAND_GetAddress (uint32_t Address)
+{
+ NAND_ADDRESS Address_t;
+
+ Address_t.Page = Address & (NAND_BLOCK_SIZE - 1);
+ Address_t.Block = Address / NAND_BLOCK_SIZE;
+ Address_t.Zone = 0;
+
+ while (Address_t.Block >= MAX_LOG_BLOCKS_PER_ZONE)
+ {
+ Address_t.Block -= MAX_LOG_BLOCKS_PER_ZONE;
+ Address_t.Zone++;
+ }
+ return Address_t;
+}
+
+/*******************************************************************************
+* Function Name : NAND_GetFreeBlock
+* Description : Look for a free block for data exchange
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+static uint16_t NAND_GetFreeBlock (void)
+{
+ return LUT[MAX_LOG_BLOCKS_PER_ZONE]& ~(USED_BLOCK | VALID_BLOCK);
+}
+
+/*******************************************************************************
+* Function Name : ReadSpareArea
+* Description : Check used block
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+SPARE_AREA ReadSpareArea (uint32_t address)
+{
+ SPARE_AREA t;
+ uint8_t Buffer[16];
+ NAND_ADDRESS address_s;
+ address_s = NAND_ConvertPhyAddress(address);
+ FSMC_NAND_ReadSpareArea(Buffer , address_s, 1) ;
+
+ t = *(SPARE_AREA *)Buffer;
+
+ return t;
+}
+
+/*******************************************************************************
+* Function Name : NAND_Copy
+* Description : Copy page
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+static uint16_t NAND_Copy (NAND_ADDRESS Address_Src, NAND_ADDRESS Address_Dest, uint16_t PageToCopy)
+{
+ uint8_t Copybuff[512];
+ for ( ; PageToCopy > 0 ; PageToCopy-- )
+ {
+ FSMC_NAND_ReadSmallPage ((uint8_t *)Copybuff, Address_Src , 1 );
+ FSMC_NAND_WriteSmallPage ((uint8_t *)Copybuff, Address_Dest, 1);
+ FSMC_NAND_AddressIncrement(&Address_Src);
+ FSMC_NAND_AddressIncrement(&Address_Dest);
+ }
+
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_Format
+* Description : Format the entire NAND flash
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+uint16_t NAND_Format (void)
+{
+ NAND_ADDRESS phAddress;
+ SPARE_AREA SpareArea;
+ uint32_t BlockIndex;
+
+ for (BlockIndex = 0 ; BlockIndex < NAND_ZONE_SIZE * NAND_MAX_ZONE; BlockIndex++)
+ {
+ phAddress = NAND_ConvertPhyAddress(BlockIndex * NAND_BLOCK_SIZE );
+ SpareArea = ReadSpareArea(BlockIndex * NAND_BLOCK_SIZE);
+
+ if((SpareArea.DataStatus != 0)||(SpareArea.BlockStatus != 0)){
+ FSMC_NAND_EraseBlock (phAddress);
+ }
+ }
+ NAND_BuildLUT(0);
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_Write_Cleanup
+* Description : None
+* Input : None
+* Output : None
+* Return : Status
+*******************************************************************************/
+static uint16_t NAND_Write_Cleanup (void)
+{
+ uint16_t tempSpareArea [8];
+ uint16_t Page_Back;
+
+ if ( Block_State == OLD_BLOCK )
+ {
+ /* precopy old first pages */
+ if (Initial_Page != 0)
+ {
+ Page_Back = wAddress.Page;
+ fAddress.Page = wAddress.Page = 0;
+ NAND_Copy (wAddress, fAddress, Initial_Page);
+ wAddress.Page = Page_Back ;
+ }
+
+ /* postcopy remaining pages */
+ if ((NAND_BLOCK_SIZE - (wAddress.Page + 1)) != 0)
+ {
+ FSMC_NAND_AddressIncrement(&wAddress);
+ fAddress.Page = wAddress.Page;
+ NAND_Copy (wAddress, fAddress, NAND_BLOCK_SIZE - wAddress.Page);
+ }
+
+ /* assign logical address to new block */
+ tempSpareArea [0] = LogAddress | USED_BLOCK ;
+ tempSpareArea [1] = 0xFFFF;
+ tempSpareArea [2] = 0xFFFF;
+
+ fAddress.Page = 0x00;
+ FSMC_NAND_WriteSpareArea( (uint8_t *)tempSpareArea , fAddress , 1);
+
+ /* erase old block */
+ FSMC_NAND_EraseBlock(wAddress);
+ NAND_CleanLUT(wAddress.Zone);
+ }
+ else
+ {/* unused block case */
+ /* assign logical address to the new used block */
+ tempSpareArea [0] = LogAddress | USED_BLOCK ;
+ tempSpareArea [1] = 0xFFFF;
+ tempSpareArea [2] = 0xFFFF;
+
+ wAddress.Page = 0x00;
+ FSMC_NAND_WriteSpareArea((uint8_t *)tempSpareArea , wAddress, 1);
+ NAND_CleanLUT(wAddress.Zone);
+ }
+ return NAND_OK;
+}
+
+/*******************************************************************************
+* Function Name : NAND_ConvertPhyAddress
+* Description : None
+* Input : physical Address
+* Output : None
+* Return : Status
+*******************************************************************************/
+static NAND_ADDRESS NAND_ConvertPhyAddress (uint32_t Address)
+{
+ NAND_ADDRESS Address_t;
+
+ Address_t.Page = Address & (NAND_BLOCK_SIZE - 1);
+ Address_t.Block = Address / NAND_BLOCK_SIZE;
+ Address_t.Zone = 0;
+
+ while (Address_t.Block >= MAX_PHY_BLOCKS_PER_ZONE)
+ {
+ Address_t.Block -= MAX_PHY_BLOCKS_PER_ZONE;
+ Address_t.Zone++;
+ }
+ return Address_t;
+}
+
+/*******************************************************************************
+* Function Name : NAND_BuildLUT
+* Description : Build the look up table
+* Input : None
+* Output : None
+* Return : Status
+* !!!! NOTE : THIS ALGORITHM IS A SUBJECT OF PATENT FOR STMICROELECTRONICS !!!!!
+*******************************************************************************/
+static uint16_t NAND_BuildLUT (uint8_t ZoneNbr)
+{
+
+ uint16_t pBadBlock, pCurrentBlock, pFreeBlock;
+ SPARE_AREA SpareArea;
+ /*****************************************************************************
+ 1st step : Init.
+ *****************************************************************************/
+ /*Init the LUT (assume all blocks free) */
+ for (pCurrentBlock = 0 ; pCurrentBlock < MAX_PHY_BLOCKS_PER_ZONE ; pCurrentBlock++)
+ {
+ LUT[pCurrentBlock] = FREE_BLOCK; /* 12th bit is set to 1 */
+ }
+
+ /* Init Pointers */
+ pBadBlock = MAX_PHY_BLOCKS_PER_ZONE - 1;
+ pCurrentBlock = 0;
+
+ /*****************************************************************************
+ 2nd step : locate used and bad blocks
+ *****************************************************************************/
+
+ while (pCurrentBlock < MAX_PHY_BLOCKS_PER_ZONE)
+ {
+
+ SpareArea = ReadSpareArea(pCurrentBlock * NAND_BLOCK_SIZE + (ZoneNbr * NAND_BLOCK_SIZE * MAX_PHY_BLOCKS_PER_ZONE));
+
+ if ((SpareArea.DataStatus == 0) || (SpareArea.BlockStatus == 0))
+ {
+
+ LUT[pBadBlock--] |= pCurrentBlock | (uint16_t)BAD_BLOCK ;
+ LUT[pCurrentBlock] &= (uint16_t)~FREE_BLOCK;
+ if (pBadBlock == MAX_LOG_BLOCKS_PER_ZONE)
+ {
+ return NAND_FAIL;
+ }
+ }
+ else if (SpareArea.LogicalIndex != 0xFFFF)
+ {
+
+ LUT[SpareArea.LogicalIndex & 0x3FF] |= pCurrentBlock | VALID_BLOCK | USED_BLOCK;
+ LUT[pCurrentBlock] &= (uint16_t)( ~FREE_BLOCK);
+ }
+ pCurrentBlock++ ;
+ }
+
+ /*****************************************************************************
+ 3rd step : locate Free Blocks by scanning the LUT already built partially
+ *****************************************************************************/
+ pFreeBlock = 0;
+ for (pCurrentBlock = 0 ; pCurrentBlock < MAX_PHY_BLOCKS_PER_ZONE ; pCurrentBlock++ )
+ {
+
+ if ( !(LUT[pCurrentBlock]& USED_BLOCK))
+ {
+ do
+ {
+ if (LUT[pFreeBlock] & FREE_BLOCK)
+ {
+
+ LUT [pCurrentBlock] |= pFreeBlock;
+ LUT [pFreeBlock] &= ~FREE_BLOCK;
+ break;
+ }
+ pFreeBlock++;
+ }
+ while ( pFreeBlock < MAX_PHY_BLOCKS_PER_ZONE );
+ }
+ }
+ return NAND_OK;
+}
+#endif
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/