aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-02-26 12:52:01 +0100
committerHarald Welte <laforge@gnumonks.org>2017-02-26 12:52:01 +0100
commite9eaf90d352c3fa6101fc4273f4cc44bae75e14c (patch)
tree7bd64e5f31b321d3eadd23d866177a53dfe656fb
parent1d91058eee504b14ce3f709b4c91f6da85b884d3 (diff)
import efc.[ch] and flashd.[ch] from SAM3S softpack 2.1
-rw-r--r--firmware/include_sam3s/efc.h113
-rw-r--r--firmware/include_sam3s/flashd.h79
-rw-r--r--firmware/src_sam3s/efc.c289
-rw-r--r--firmware/src_sam3s/flashd.c512
4 files changed, 993 insertions, 0 deletions
diff --git a/firmware/include_sam3s/efc.h b/firmware/include_sam3s/efc.h
new file mode 100644
index 0000000..0a99633
--- /dev/null
+++ b/firmware/include_sam3s/efc.h
@@ -0,0 +1,113 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ * \file
+ *
+ * \section Purpose
+ *
+ * Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral.
+ *
+ * \section Usage
+ *
+ * -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt()
+ * and EFC_DisableFrdyIt().
+ * -# Translates the given address into which EEFC, page and offset values
+ * for difference density %flash memory using EFC_TranslateAddress().
+ * -# Computes the address of a %flash access given the EFC, page and offset
+ * for difference density %flash memory using EFC_ComputeAddress().
+ * -# Start the executing command with EFC_StartCommand()
+ * -# Retrieve the current status of the EFC using EFC_GetStatus().
+ * -# Retrieve the result of the last executed command with EFC_GetResult().
+ */
+
+#ifndef _EEFC_
+#define _EEFC_
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+#include "chip.h"
+
+#include <stdint.h>
+
+/*----------------------------------------------------------------------------
+ * Definitions
+ *----------------------------------------------------------------------------*/
+/* EFC command */
+#define EFC_FCMD_GETD 0x00
+#define EFC_FCMD_WP 0x01
+#define EFC_FCMD_WPL 0x02
+#define EFC_FCMD_EWP 0x03
+#define EFC_FCMD_EWPL 0x04
+#define EFC_FCMD_EA 0x05
+#define EFC_FCMD_SLB 0x08
+#define EFC_FCMD_CLB 0x09
+#define EFC_FCMD_GLB 0x0A
+#define EFC_FCMD_SFB 0x0B
+#define EFC_FCMD_CFB 0x0C
+#define EFC_FCMD_GFB 0x0D
+#define EFC_FCMD_STUI 0x0E /* Start unique ID */
+#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */
+
+/* The IAP function entry addreass */
+#define CHIP_FLASH_IAP_ADDRESS (0x00800008)
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------
+ * Exported functions
+ *----------------------------------------------------------------------------*/
+
+extern void EFC_EnableFrdyIt( Efc* efc ) ;
+
+extern void EFC_DisableFrdyIt( Efc* efc ) ;
+
+extern void EFC_SetWaitState( Efc* efc, uint8_t cycles ) ;
+
+extern void EFC_TranslateAddress( Efc** pEfc, uint32_t dwAddress, uint16_t *pwPage, uint16_t *pwOffset ) ;
+
+extern void EFC_ComputeAddress( Efc* efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) ;
+
+extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) ;
+
+extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) ;
+
+extern uint32_t EFC_GetStatus( Efc* efc ) ;
+
+extern uint32_t EFC_GetResult( Efc* efc ) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _EEFC_ */
+
diff --git a/firmware/include_sam3s/flashd.h b/firmware/include_sam3s/flashd.h
new file mode 100644
index 0000000..e58ba02
--- /dev/null
+++ b/firmware/include_sam3s/flashd.h
@@ -0,0 +1,79 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+*/
+
+/**
+ * \file
+ *
+ * The flash driver provides the unified interface for flash program operations.
+ *
+ */
+
+#ifndef _FLASHD_
+#define _FLASHD_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----------------------------------------------------------------------------
+ * Exported functions
+ *----------------------------------------------------------------------------*/
+
+extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ;
+
+extern uint32_t FLASHD_Erase( uint32_t dwAddress ) ;
+
+extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) ;
+
+extern uint32_t FLASHD_Lock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ;
+
+extern uint32_t FLASHD_Unlock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ;
+
+extern uint32_t FLASHD_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ;
+
+extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ;
+
+extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ;
+
+extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ;
+
+#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 )
+
+#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 )
+
+extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _FLASHD_ */
+
diff --git a/firmware/src_sam3s/efc.c b/firmware/src_sam3s/efc.c
new file mode 100644
index 0000000..97104d5
--- /dev/null
+++ b/firmware/src_sam3s/efc.c
@@ -0,0 +1,289 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/** \addtogroup efc_module Working with EEFC
+ * The EEFC driver provides the interface to configure and use the EEFC
+ * peripheral.
+ *
+ * The user needs to set the number of wait states depending on the frequency used.\n
+ * Configure number of cycles for flash read/write operations in the FWS field of EEFC_FMR.
+ *
+ * It offers a function to send flash command to EEFC and waits for the
+ * flash to be ready.
+ *
+ * To send flash command, the user could do in either of following way:
+ * <ul>
+ * <li>Write a correct key, command and argument in EEFC_FCR. </li>
+ * <li>Or, Use IAP (In Application Programming) function which is executed from
+ * ROM directly, this allows flash programming to be done by code running in flash.</li>
+ * <li>Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt.
+ * </ul>
+ *
+ * The command argument could be a page number,GPNVM number or nothing, it depends on
+ * the command itself. Some useful functions in this driver could help user tranlate physical
+ * flash address into a page number and vice verse.
+ *
+ * For more accurate information, please look at the EEFC section of the
+ * Datasheet.
+ *
+ * Related files :\n
+ * \ref efc.c\n
+ * \ref efc.h.\n
+*/
+/*@{*/
+/*@}*/
+
+
+/**
+ * \file
+ *
+ * Implementation of Enhanced Embedded Flash Controller (EEFC).
+ *
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+#include "chip.h"
+
+#include <assert.h>
+
+/*----------------------------------------------------------------------------
+ * Exported functions
+ *----------------------------------------------------------------------------*/
+
+/**
+ * \brief Enables the flash ready interrupt source on the EEFC peripheral.
+ *
+ * \param efc Pointer to a Efc instance
+ */
+extern void EFC_EnableFrdyIt( Efc* efc )
+{
+ efc->EEFC_FMR |= EEFC_FMR_FRDY ;
+}
+
+/**
+ * \brief Disables the flash ready interrupt source on the EEFC peripheral.
+ *
+ * \param efc Pointer to a Efc instance
+ */
+
+extern void EFC_DisableFrdyIt( Efc* efc )
+{
+ efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ;
+}
+
+
+/**
+ * \brief Set read/write wait state on the EEFC perpherial.
+ *
+ * \param efc Pointer to a Efc instance
+ * \param cycles the number of wait states in cycle.
+ */
+
+extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles )
+{
+ uint32_t dwValue ;
+
+ dwValue = efc->EEFC_FMR ;
+ dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ;
+ dwValue |= EEFC_FMR_FWS(ucCycles);
+ efc->EEFC_FMR = dwValue ;
+}
+
+/**
+ * \brief Returns the current status of the EEFC.
+ *
+ * \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE).
+ *
+ * \param efc Pointer to a Efc instance
+ */
+extern uint32_t EFC_GetStatus( Efc* efc )
+{
+ return efc->EEFC_FSR ;
+}
+
+/**
+ * \brief Returns the result of the last executed command.
+ *
+ * \param efc Pointer to a Efc instance
+ */
+extern uint32_t EFC_GetResult( Efc* efc )
+{
+ return efc->EEFC_FRR ;
+}
+
+/**
+ * \brief Translates the given address page and offset values.
+ * \note The resulting values are stored in the provided variables if they are not null.
+ *
+ * \param efc Pointer to a Efc instance
+ * \param address Address to translate.
+ * \param pPage First page accessed.
+ * \param pOffset Byte offset in first page.
+ */
+extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset )
+{
+ Efc *pEfc ;
+ uint16_t wPage ;
+ uint16_t wOffset ;
+
+ assert( dwAddress >= IFLASH_ADDR ) ;
+ assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
+
+ pEfc = EFC ;
+ wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE;
+ wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE;
+
+ TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ;
+ /* Store values */
+ if ( pEfc )
+ {
+ *ppEfc = pEfc ;
+ }
+
+ if ( pwPage )
+ {
+ *pwPage = wPage ;
+ }
+
+ if ( pwOffset )
+ {
+ *pwOffset = wOffset ;
+ }
+}
+
+/**
+ * \brief Computes the address of a flash access given the page and offset.
+ *
+ * \param efc Pointer to a Efc instance
+ * \param page Page number.
+ * \param offset Byte offset inside page.
+ * \param pAddress Computed address (optional).
+ */
+extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress )
+{
+ uint32_t dwAddress ;
+
+ assert( efc ) ;
+ assert( wPage <= IFLASH_NB_OF_PAGES ) ;
+ assert( wOffset < IFLASH_PAGE_SIZE ) ;
+
+ /* Compute address */
+ dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ;
+
+ /* Store result */
+ if ( pdwAddress != NULL )
+ {
+ *pdwAddress = dwAddress ;
+ }
+}
+
+/**
+ * \brief Starts the executing the given command on the EEFC and returns as soon as the command is started.
+ *
+ * \note It does NOT set the FMCN field automatically.
+ * \param efc Pointer to a Efc instance
+ * \param command Command to execute.
+ * \param argument Command argument (should be 0 if not used).
+ */
+extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument )
+{
+ /* Check command & argument */
+ switch ( dwCommand )
+ {
+ case EFC_FCMD_WP:
+ case EFC_FCMD_WPL:
+ case EFC_FCMD_EWP:
+ case EFC_FCMD_EWPL:
+ case EFC_FCMD_SLB:
+ case EFC_FCMD_CLB:
+ assert( dwArgument < IFLASH_NB_OF_PAGES ) ;
+ break ;
+
+ case EFC_FCMD_SFB:
+ case EFC_FCMD_CFB:
+ assert( dwArgument < 2 ) ;
+ break;
+
+ case EFC_FCMD_GETD:
+ case EFC_FCMD_EA:
+ case EFC_FCMD_GLB:
+ case EFC_FCMD_GFB:
+ case EFC_FCMD_STUI:
+ assert( dwArgument == 0 ) ;
+ break;
+
+ default: assert( 0 ) ;
+ }
+
+ /* Start command Embedded flash */
+ assert( (efc->EEFC_FSR & EEFC_FMR_FRDY) == EEFC_FMR_FRDY ) ;
+ efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
+}
+
+/**
+ * \brief Performs the given command and wait until its completion (or an error).
+ *
+ * \param efc Pointer to a Efc instance
+ * \param command Command to perform.
+ * \param argument Optional command argument.
+ *
+ * \return 0 if successful, otherwise returns an error code.
+ */
+
+extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP )
+{
+ if ( dwUseIAP != 0 )
+ {
+ /* Pointer on IAP function in ROM */
+ static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ;
+
+ IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ;
+ IAP_PerformCommand( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ;
+
+ return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ;
+ }
+ else
+ {
+ uint32_t dwStatus ;
+
+ efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
+ do
+ {
+ dwStatus = efc->EEFC_FSR ;
+ }
+ while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
+
+ return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ;
+ }
+}
+
+
diff --git a/firmware/src_sam3s/flashd.c b/firmware/src_sam3s/flashd.c
new file mode 100644
index 0000000..7dc7276
--- /dev/null
+++ b/firmware/src_sam3s/flashd.c
@@ -0,0 +1,512 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/** \addtogroup flashd_module Flash Memory Interface
+ * The flash driver manages the programming, erasing, locking and unlocking sequences
+ * with dedicated commands.
+ *
+ * To implement flash programing operation, the user has to follow these few steps :
+ * <ul>
+ * <li>Configue flash wait states to initializes the flash. </li>
+ * <li>Checks whether a region to be programmed is locked. </li>
+ * <li>Unlocks the user region to be programmed if the region have locked before.</li>
+ * <li>Erases the user page before program (optional).</li>
+ * <li>Writes the user page from the page buffer.</li>
+ * <li>Locks the region of programmed area if any.</li>
+ * </ul>
+ *
+ * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
+ * A check of this validity and padding for 32-bit alignment should be done in write algorithm.
+
+ * Lock/unlock range associated with the user address range is automatically translated.
+ *
+ * This security bit can be enabled through the command "Set General Purpose NVM Bit 0".
+ *
+ * A 128-bit factory programmed unique ID could be read to serve several purposes.
+ *
+ * The driver accesses the flash memory by calling the lowlevel module provided in \ref efc_module.
+ * For more accurate information, please look at the EEFC section of the Datasheet.
+ *
+ * Related files :\n
+ * \ref flashd.c\n
+ * \ref flashd.h.\n
+ * \ref efc.c\n
+ * \ref efc.h.\n
+*/
+/*@{*/
+/*@}*/
+
+
+/**
+ * \file
+ *
+ * The flash driver provides the unified interface for flash program operations.
+ *
+ */
+
+/*----------------------------------------------------------------------------
+ * Headers
+ *----------------------------------------------------------------------------*/
+#include "chip.h"
+
+#include <string.h>
+#include <assert.h>
+
+/*----------------------------------------------------------------------------
+ * Local variables
+ *----------------------------------------------------------------------------*/
+
+//static NO_INIT uint8_t _aucPageBuffer[IFLASH_PAGE_SIZE] ;
+static NO_INIT uint32_t _adwPageBuffer[IFLASH_PAGE_SIZE/4] ;
+static uint8_t* _aucPageBuffer = (uint8_t*)_adwPageBuffer;
+static NO_INIT uint32_t _dwUseIAP ;
+
+/*----------------------------------------------------------------------------
+ * Local macros
+ *----------------------------------------------------------------------------*/
+
+#define min( a, b ) (((a) < (b)) ? (a) : (b))
+
+/*----------------------------------------------------------------------------
+ * Local functions
+ *----------------------------------------------------------------------------*/
+
+
+/**
+ * \brief Computes the lock range associated with the given address range.
+ *
+ * \param dwStart Start address of lock range.
+ * \param dwEnd End address of lock range.
+ * \param pdwActualStart Actual start address of lock range.
+ * \param pdwActualEnd Actual end address of lock range.
+ */
+static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd )
+{
+ Efc* pStartEfc ;
+ Efc* pEndEfc ;
+ uint16_t wStartPage ;
+ uint16_t wEndPage ;
+ uint16_t wNumPagesInRegion ;
+ uint16_t wActualStartPage ;
+ uint16_t wActualEndPage ;
+
+ // Convert start and end address in page numbers
+ EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ;
+ EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ;
+
+ // Find out the first page of the first region to lock
+ wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
+ wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ;
+ wActualEndPage = wEndPage ;
+
+ if ( (wEndPage % wNumPagesInRegion) != 0 )
+ {
+ wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ;
+ }
+ // Store actual page numbers
+ EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ;
+ EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ;
+ TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r", *pdwActualStart, *pdwActualEnd ) ;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Exported functions
+ *----------------------------------------------------------------------------*/
+
+/**
+ * \brief Initializes the flash driver.
+ *
+ * \param mck Master clock frequency in Hz.
+ */
+
+extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP )
+{
+ EFC_DisableFrdyIt( EFC ) ;
+
+ if ( (dwMCk/1000000) >= 64 )
+ {
+ EFC_SetWaitState( EFC, 2 ) ;
+ }
+ else
+ {
+ if ( (dwMCk/1000000) >= 50 )
+ {
+ EFC_SetWaitState( EFC, 1 ) ;
+ }
+ else
+ {
+ EFC_SetWaitState( EFC, 0 ) ;
+ }
+ }
+
+ _dwUseIAP=dwUseIAP ;
+}
+
+/**
+ * \brief Erases the entire flash.
+ *
+ * \param address Flash start address.
+ * \return 0 if successful; otherwise returns an error code.
+ */
+extern uint32_t FLASHD_Erase( uint32_t dwAddress )
+{
+ Efc* pEfc ;
+ uint16_t wPage ;
+ uint16_t wOffset ;
+ uint32_t dwError ;
+
+ assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
+
+ // Translate write address
+ EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
+ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ;
+
+ return dwError ;
+}
+
+/**
+ * \brief Writes a data buffer in the internal flash
+ *
+ * \note This function works in polling mode, and thus only returns when the
+ * data has been effectively written.
+ * \param address Write address.
+ * \param pBuffer Data buffer.
+ * \param size Size of data buffer in bytes.
+ * \return 0 if successful, otherwise returns an error code.
+ */
+extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize )
+{
+ Efc* pEfc ;
+ uint16_t page ;
+ uint16_t offset ;
+ uint32_t writeSize ;
+ uint32_t pageAddress ;
+ uint16_t padding ;
+ uint32_t dwError ;
+ uint32_t sizeTmp ;
+ uint32_t *pAlignedDestination ;
+ uint32_t *pAlignedSource ;
+
+ assert( pvBuffer ) ;
+ assert( dwAddress >=IFLASH_ADDR ) ;
+ assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
+
+ /* Translate write address */
+ EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ;
+
+ /* Write all pages */
+ while ( dwSize > 0 )
+ {
+ /* Copy data in temporary buffer to avoid alignment problems */
+ writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ;
+ EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ;
+ padding = IFLASH_PAGE_SIZE - offset - writeSize ;
+
+ /* Pre-buffer data */
+ memcpy( _aucPageBuffer, (void *) pageAddress, offset);
+
+ /* Buffer data */
+ memcpy( _aucPageBuffer + offset, pvBuffer, writeSize);
+
+ /* Post-buffer data */
+ memcpy( _aucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding);
+
+ /* Write page
+ * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption
+ */
+ pAlignedDestination = (uint32_t*)pageAddress ;
+ pAlignedSource = (uint32_t*)_adwPageBuffer ;
+ sizeTmp = IFLASH_PAGE_SIZE ;
+
+ while ( sizeTmp >= 4 )
+ {
+ *pAlignedDestination++ = *pAlignedSource++;
+ sizeTmp -= 4;
+ }
+
+ /* Send writing command */
+ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EWP, page, _dwUseIAP ) ;
+ if ( dwError )
+ {
+ return dwError ;
+ }
+
+ /* Progression */
+ dwAddress += IFLASH_PAGE_SIZE ;
+ pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ;
+ dwSize -= writeSize ;
+ page++;
+ offset = 0;
+ }
+
+ return 0 ;
+}
+/**
+ * \brief Locks all the regions in the given address range. The actual lock range is
+ * reported through two output parameters.
+ *
+ * \param start Start address of lock range.
+ * \param end End address of lock range.
+ * \param pActualStart Start address of the actual lock range (optional).
+ * \param pActualEnd End address of the actual lock range (optional).
+ * \return 0 if successful, otherwise returns an error code.
+ */
+extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )
+{
+ Efc *pEfc ;
+ uint32_t actualStart, actualEnd ;
+ uint16_t startPage, endPage ;
+ uint32_t dwError ;
+ uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
+
+ /* Compute actual lock range and store it */
+ ComputeLockRange( start, end, &actualStart, &actualEnd ) ;
+ if ( pActualStart != NULL )
+ {
+ *pActualStart = actualStart ;
+ }
+ if ( pActualEnd != NULL )
+ {
+ *pActualEnd = actualEnd;
+ }
+
+ /* Compute page numbers */
+ EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
+ EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
+
+ /* Lock all pages */
+ while ( startPage < endPage )
+ {
+ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ;
+ if ( dwError )
+ {
+ return dwError ;
+ }
+ startPage += numPagesInRegion;
+ }
+
+ return 0 ;
+}
+
+/**
+ * \brief Unlocks all the regions in the given address range. The actual unlock range is
+ * reported through two output parameters.
+ * \param start Start address of unlock range.
+ * \param end End address of unlock range.
+ * \param pActualStart Start address of the actual unlock range (optional).
+ * \param pActualEnd End address of the actual unlock range (optional).
+ * \return 0 if successful, otherwise returns an error code.
+ */
+extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )
+{
+ Efc* pEfc ;
+ uint32_t actualStart, actualEnd ;
+ uint16_t startPage, endPage ;
+ uint32_t dwError ;
+ uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
+
+ // Compute actual unlock range and store it
+ ComputeLockRange(start, end, &actualStart, &actualEnd);
+ if ( pActualStart != NULL )
+ {
+ *pActualStart = actualStart ;
+ }
+ if ( pActualEnd != NULL )
+ {
+ *pActualEnd = actualEnd ;
+ }
+
+ // Compute page numbers
+ EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
+ EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
+
+ // Unlock all pages
+ while ( startPage < endPage )
+ {
+ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ;
+ if ( dwError )
+ {
+ return dwError ;
+ }
+ startPage += numPagesInRegion ;
+ }
+ return 0 ;
+}
+
+/**
+ * \brief Returns the number of locked regions inside the given address range.
+ *
+ * \param start Start address of range
+ * \param end End address of range.
+ */
+extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end )
+{
+ Efc *pEfc ;
+ uint16_t startPage, endPage ;
+ uint8_t startRegion, endRegion ;
+ uint32_t numPagesInRegion ;
+ uint32_t status ;
+ uint32_t dwError ;
+ uint32_t numLockedRegions = 0 ;
+
+ assert( end >= start ) ;
+ assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ;
+
+ // Compute page numbers
+ EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ;
+ EFC_TranslateAddress( 0, end, &endPage, 0 ) ;
+
+ // Compute region numbers
+ numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
+ startRegion = startPage / numPagesInRegion ;
+ endRegion = endPage / numPagesInRegion ;
+ if ((endPage % numPagesInRegion) != 0)
+ {
+ endRegion++ ;
+ }
+
+ // Retrieve lock status
+ dwError = EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ;
+ assert( !dwError ) ;
+ status = EFC_GetResult( pEfc ) ;
+
+ // Check status of each involved region
+ while ( startRegion < endRegion )
+ {
+ if ( (status & (1 << startRegion)) != 0 )
+ {
+ numLockedRegions++ ;
+ }
+ startRegion++ ;
+ }
+
+ return numLockedRegions ;
+}
+
+/**
+ * \brief Check if the given GPNVM bit is set or not.
+ *
+ * \param gpnvm GPNVM bit index.
+ * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0.
+ */
+extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM )
+{
+ uint32_t dwError ;
+ uint32_t dwStatus ;
+
+ assert( ucGPNVM < 2 ) ;
+
+ /* Get GPNVMs status */
+ dwError = EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ;
+ assert( !dwError ) ;
+ dwStatus = EFC_GetResult( EFC ) ;
+
+ /* Check if GPNVM is set */
+ if ( (dwStatus & (1 << ucGPNVM)) != 0 )
+ {
+ return 1 ;
+ }
+ else
+ {
+ return 0 ;
+ }
+}
+
+/**
+ * \brief Sets the selected GPNVM bit.
+ *
+ * \param gpnvm GPNVM bit index.
+ * \returns 0 if successful; otherwise returns an error code.
+ */
+extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM )
+{
+ assert( ucGPNVM < 2 ) ;
+
+ if ( !FLASHD_IsGPNVMSet( ucGPNVM ) )
+ {
+ return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ;
+ }
+ else
+ {
+ return 0 ;
+ }
+}
+
+/**
+ * \brief Clears the selected GPNVM bit.
+ *
+ * \param gpnvm GPNVM bit index.
+ * \returns 0 if successful; otherwise returns an error code.
+ */
+extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM )
+{
+ assert( ucGPNVM < 2 ) ;
+
+ if ( FLASHD_IsGPNVMSet( ucGPNVM ) )
+ {
+ return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ;
+ }
+ else
+ {
+ return 0 ;
+ }
+}
+/**
+ * \brief Read the unique ID.
+ *
+ * \param uniqueID pointer on a 4bytes char containing the unique ID value.
+ * \returns 0 if successful; otherwise returns an error code.
+ */
+extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )
+{
+ uint32_t dwError ;
+
+ assert( pdwUniqueID != NULL ) ;
+
+ pdwUniqueID[0] = 0 ;
+ pdwUniqueID[1] = 0 ;
+ pdwUniqueID[2] = 0 ;
+ pdwUniqueID[3] = 0 ;
+
+ EFC_StartCommand( EFC, EFC_FCMD_STUI, 0 ) ;
+
+ pdwUniqueID[0] = *(uint32_t*) IFLASH_ADDR;
+ pdwUniqueID[1] = *(uint32_t*)(IFLASH_ADDR + 4) ;
+ pdwUniqueID[2] = *(uint32_t*)(IFLASH_ADDR + 8) ;
+ pdwUniqueID[3] = *(uint32_t*)(IFLASH_ADDR + 12) ;
+
+ dwError = EFC_PerformCommand( EFC, EFC_FCMD_SPUI, 0, _dwUseIAP ) ;
+ if ( dwError )
+ {
+ return dwError ;
+ }
+
+ return 0 ;
+}