summaryrefslogtreecommitdiff
path: root/ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c')
-rw-r--r--ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c738
1 files changed, 738 insertions, 0 deletions
diff --git a/ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c b/ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c
new file mode 100644
index 0000000..2427947
--- /dev/null
+++ b/ecos/packages/devs/flash/cortexm/stm32/current/src/stm32_flash.c
@@ -0,0 +1,738 @@
+//==========================================================================
+//
+// stm32_flash.c
+//
+// STM32 internal flash driver
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Date: 2008-09-22
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/hal_cortexm_stm32.h>
+#include <pkgconf/devs_flash_stm32.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/io/flash.h>
+#include <cyg/io/flash_dev.h>
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_io.h>
+#include <cyg/hal/hal_if.h>
+
+#include <string.h>
+
+#include <cyg/io/stm32_flash.h>
+
+#include CYGHWR_MEMORY_LAYOUT_H
+
+// Does this look like an F1 or F2/F4 device? It makes a difference to sizing and operation.
+#if defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_F1)
+# define F1STYLE 1
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_FAMILY_HIPERFORMANCE)
+# define F2STYLE 1
+#endif
+
+// ----------------------------------------------------------------------------
+
+#if defined(F1STYLE)
+typedef cyg_uint16 STM32_TYPE;
+#elif defined(F2STYLE)
+// F2/F4's alignment requirements depend on parallelism config, so we treat as
+// bytes for now.
+typedef cyg_uint8 STM32_TYPE;
+#endif
+
+// ----------------------------------------------------------------------------
+
+// How many loops before we consider this a timeout.
+#define STM32_FLASH_TIMEOUT 1000000
+
+// A quick helper macro to avoid repetition.
+#define WAIT_FOR_FLASH_NOT_BUSY(_timeout_) \
+ CYG_MACRO_START \
+ (_timeout_) = STM32_FLASH_TIMEOUT; \
+ do { \
+ HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr ); \
+ } while( (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY) && (_timeout_)-- > 0 ); \
+ CYG_MACRO_END
+
+// ----------------------------------------------------------------------------
+
+// Note that although the F2/F4 parts need special treatment for the Flash's
+// built-in icache and dcache, that doesn't matter for suspend/resume
+// because no-one should expect any part of the Flash in the area being
+// erased/programmed to be any particular value.
+
+# define STM32_INTSCACHE_STATE int _saved_ints_
+# define STM32_INTSCACHE_BEGIN() HAL_DISABLE_INTERRUPTS(_saved_ints_)
+# define STM32_INTSCACHE_SUSPEND() HAL_RESTORE_INTERRUPTS(_saved_ints_)
+# define STM32_INTSCACHE_RESUME() HAL_DISABLE_INTERRUPTS(_saved_ints_)
+# define STM32_INTSCACHE_END() HAL_RESTORE_INTERRUPTS(_saved_ints_)
+
+#define STM32_UNCACHED_ADDRESS(__x) ((STM32_TYPE *)(__x))
+
+// ----------------------------------------------------------------------------
+// Forward declarations for functions that need to be placed in RAM:
+
+static int stm32_enable_hsi(void);
+static void stm32_disable_hsi(void);
+static int stm32_flash_hw_erase(cyg_flashaddr_t addr, cyg_uint16 block_num) __attribute__((section (".2ram.stm32_flash_hw_erase")));
+static int stm32_flash_hw_program( volatile STM32_TYPE* addr, const STM32_TYPE *buf, cyg_uint32 count) __attribute__((section (".2ram.stm32_flash_hw_program")));
+
+// ----------------------------------------------------------------------------
+// Diagnostic routines.
+
+#if 0
+#define stf_diag( __fmt, ... ) diag_printf("STF: %20s[%3d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ );
+#define stf_dump_buf( __addr, __size ) diag_dump_buf( __addr, __size )
+#else
+#define stf_diag( __fmt, ... )
+#define stf_dump_buf( __addr, __size )
+#endif
+
+// ----------------------------------------------------------------------------
+// Select Flash geometry
+
+#if defined(CYGHWR_HAL_CORTEXM_STM32_F103RC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103VC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103ZC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F105RC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F105RC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F105VC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F107VC)
+
+ // High-density device with 256K flash (2K blocks)
+#define STM32_FLASH_SIZE 0x40000
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RD) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103VD) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103ZD)
+
+ // High-density device with 384K flash (2K blocks)
+#define STM32_FLASH_SIZE 0x60000
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F103RE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103VE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F103ZE)
+
+ // High-density device with 512K flash (2K blocks)
+#define STM32_FLASH_SIZE 0x80000
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RB) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205VB) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205ZB) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207VB) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207ZB) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207IB)
+// 128K
+#define STM32_FLASH_SIZE (128*1024)
+#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 } } } // guesswork at present - documentation is elusive
+#define STM32_FLASH_NUM_BLOCK_INFOS 2
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205VC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205ZC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207VC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207ZC) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207IC)
+// 256K
+#define STM32_FLASH_SIZE (256*1024)
+#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 1 } } } // guesswork at present - documentation is elusive
+#define STM32_FLASH_NUM_BLOCK_INFOS 3
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205VE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205ZE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207VE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207ZE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207IE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407IE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407VE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407ZE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417IE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417VE) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417ZE)
+// 512K
+#define STM32_FLASH_SIZE (512*1024)
+#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 3 } } } // guesswork at present - documentation is elusive
+#define STM32_FLASH_NUM_BLOCK_INFOS 3
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RF) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205VF) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205ZF) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207VF) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207ZF) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207IF)
+// 768K
+#define STM32_FLASH_SIZE (768*1024)
+#define xxxSTM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 5 } } } // guesswork at present - documentation is elusive
+#define STM32_FLASH_NUM_BLOCK_INFOS 3
+
+#elif defined(CYGHWR_HAL_CORTEXM_STM32_F205RG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205VG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F205ZG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207VG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207ZG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F207IG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F405RG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F405VG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F405ZG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407IG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407VG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F407ZG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417IG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417VG) || \
+ defined(CYGHWR_HAL_CORTEXM_STM32_F417ZG)
+
+// 1024K
+#define STM32_FLASH_SIZE (1024*1024)
+#define STM32_FLASH_BLOCK_INFO { { { 16*1024, 4 } , { 64*1024, 1 }, { 128*1024, 7 } } }
+#define STM32_FLASH_NUM_BLOCK_INFOS 3
+
+#else
+#error Unknown STM32 microprocessor variant.
+#endif
+
+#ifdef F1STYLE
+// Always 2K blocks
+#define STM32_FLASH_BLOCK_SIZE 0x800
+#endif
+
+// If there's just one block size, it's straightforward.
+#if defined(STM32_FLASH_BLOCK_SIZE)
+const cyg_stm32_flash_dev hal_stm32_flash_priv = { { STM32_FLASH_BLOCK_SIZE, STM32_FLASH_SIZE / STM32_FLASH_BLOCK_SIZE } };
+#elif defined(STM32_FLASH_BLOCK_INFO)
+const cyg_stm32_flash_dev hal_stm32_flash_priv = STM32_FLASH_BLOCK_INFO;
+#else
+# error Incomplete STM32 variant details. It needs filling in.
+#endif
+
+// ----------------------------------------------------------------------------
+
+#ifdef CYGNUM_DEVS_FLASH_STM32_PARALLELISM
+# define CR_PSIZE_MAX CYGHWR_HAL_STM32_FLASH_CR_PSIZE(CYGNUM_DEVS_FLASH_STM32_PARALLELISM)
+# define PARALLEL_BYTES (CYGNUM_DEVS_FLASH_STM32_PARALLELISM/8)
+# define PARALLEL_ALIGN_MASK (PARALLEL_BYTES - 1)
+#endif
+
+// ----------------------------------------------------------------------------
+// Translate our error values into eCos flash driver error values
+
+// Some little helper macros for this function to make it shorter/simpler
+#define _SRBIT(_x_) CYGHWR_HAL_STM32_FLASH_SR_##_x_
+#define _FERR(_x_) CYG_FLASH_ERR_##_x_
+#define DECODE_SR_ERROR(_srbit_, _code_) if ( sr & _SRBIT(_srbit_) ) result = _FERR(_code_)
+
+static int
+stm32_flash_decode_error( int sr )
+{
+ int result = CYG_FLASH_ERR_OK;
+
+ // -1 can never be a valid sr value so we use it to indicate a timeout
+ if ( -1 == sr )
+ return CYG_FLASH_ERR_DRV_TIMEOUT;
+
+#if defined(F1STYLE)
+ DECODE_SR_ERROR( PGERR, PROGRAM );
+ DECODE_SR_ERROR( WRPRTERR, PROTECT );
+#elif defined(F2STYLE)
+ // OPERR is probably unnecessary really, but just in case.
+ // Do it before others though so they can override with a better value.
+ DECODE_SR_ERROR( OPERR, HWR );
+ DECODE_SR_ERROR( WRPERR, PROTECT );
+ DECODE_SR_ERROR( PGAERR, INVALID );
+ DECODE_SR_ERROR( PGPERR, PROTOCOL );
+ DECODE_SR_ERROR( PGSERR, PROTOCOL );
+#endif
+ return result;
+}
+
+static void stm32_flash_clear_sr_err(void)
+{
+ cyg_uint32 sr;
+#if defined(F1STYLE)
+ sr = CYGHWR_HAL_STM32_FLASH_SR_PGERR | CYGHWR_HAL_STM32_FLASH_SR_WRPRTERR;
+#elif defined(F2STYLE)
+ sr = CYGHWR_HAL_STM32_FLASH_SR_OPERR |
+ CYGHWR_HAL_STM32_FLASH_SR_WRPERR |
+ CYGHWR_HAL_STM32_FLASH_SR_PGAERR |
+ CYGHWR_HAL_STM32_FLASH_SR_PGPERR |
+ CYGHWR_HAL_STM32_FLASH_SR_PGSERR;
+#endif
+ HAL_WRITE_UINT32( CYGHWR_HAL_STM32_FLASH + CYGHWR_HAL_STM32_FLASH_SR, sr );
+}
+
+// ----------------------------------------------------------------------------
+// Initialize the flash.
+
+
+static int
+stm32_flash_init(struct cyg_flash_dev* dev)
+{
+ // Set up the block info entries.
+
+ dev->block_info = &hal_stm32_flash_priv.block_info[0];
+#if defined(STM32_FLASH_NUM_BLOCK_INFOS)
+ dev->num_block_infos = STM32_FLASH_NUM_BLOCK_INFOS;
+#else
+ dev->num_block_infos = sizeof(hal_stm32_flash_priv.block_info) / sizeof(hal_stm32_flash_priv.block_info[0]);
+#endif
+
+ // As stated in the errata sheet, the debug register can only be read in
+ // debug mode and is therefore not accessible by user software.
+
+ // Set end address
+ dev->end = dev->start + STM32_FLASH_SIZE - 1;
+
+ stf_diag("block_size %d size %08x end %08x\n", dev->block_info[0].block_size, STM32_FLASH_SIZE, dev->end );
+
+ // Ensure there's nothing hanging over from before us.
+ stm32_flash_clear_sr_err();
+
+ return CYG_FLASH_ERR_OK;
+}
+
+// ----------------------------------------------------------------------------
+
+static size_t
+stm32_flash_query(struct cyg_flash_dev* dev, void* data, size_t len)
+{
+ static char query[] = "STM32 Internal Flash";
+ memcpy( data, query, sizeof(query));
+ return sizeof(query);
+}
+
+// ----------------------------------------------------------------------------
+// Get info about the current block, i.e. base and size.
+
+static void
+stm32_flash_get_block_info(struct cyg_flash_dev* dev, const cyg_flashaddr_t addr, cyg_flashaddr_t* block_start,
+ size_t* block_size, cyg_uint16 *block_num)
+{
+ size_t offset = addr - dev->start;
+ cyg_ucount8 i;
+ cyg_uint32 bi_size_passed = 0;
+ cyg_uint16 blocks_passed = 0;
+
+ // This loop has the termination condition commented out to silence a
+ // warning. It should never be reached anyway, so that's fine, although
+ // that is checked with an assert.
+
+ for ( i=0; /* i < dev->num_block_info */ ; i++ )
+{
+ const cyg_flash_block_info_t *bi = &dev->block_info[i];
+ cyg_uint32 bi_size = bi->blocks * bi->block_size;
+
+ CYG_ASSERTC( i < dev->num_block_infos );
+
+ if ( offset < bi_size)
+ {
+ *block_start = dev->start + bi_size_passed + (offset & ~(bi->block_size-1));
+ *block_size = bi->block_size;
+ while (offset >= bi->block_size)
+ {
+ offset -= bi->block_size;
+ blocks_passed++;
+}
+ *block_num = blocks_passed;
+ break;
+ }
+ bi_size_passed += bi_size;
+ offset -= bi_size;
+ blocks_passed += bi->blocks;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+static int
+stm32_enable_hsi(void)
+{
+ CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC;
+ cyg_uint32 cr;
+
+ HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+ if( cr & CYGHWR_HAL_STM32_RCC_CR_HSIRDY )
+ return 0;
+
+ cr |= CYGHWR_HAL_STM32_RCC_CR_HSION;
+ HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+ while( cr & CYGHWR_HAL_STM32_RCC_CR_HSIRDY )
+ HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+
+ return 1;
+}
+
+static void
+stm32_disable_hsi(void)
+{
+ CYG_ADDRESS rcc = CYGHWR_HAL_STM32_RCC;
+ cyg_uint32 cr;
+
+ HAL_READ_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+ cr &= ~(CYGHWR_HAL_STM32_RCC_CR_HSION | CYGHWR_HAL_STM32_RCC_CR_HSIRDY);
+ HAL_WRITE_UINT32( rcc+CYGHWR_HAL_STM32_RCC_CR, cr );
+}
+
+// ----------------------------------------------------------------------------
+// Erase a single sector. There is no API support for chip-erase. The
+// generic code operates one sector at a time, invoking the driver for
+// each sector, so there is no opportunity inside the driver for
+// erasing multiple sectors in a single call. The address argument
+// points at the start of the sector.
+
+static int
+stm32_flash_hw_erase(cyg_flashaddr_t addr, cyg_uint16 block_num)
+{
+ cyg_uint32 base = CYGHWR_HAL_STM32_FLASH;
+ cyg_uint32 sr, cr;
+ cyg_uint32 timeout;
+
+#ifdef CYGDBG_USE_ASSERTS
+ HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr );
+ CYG_ASSERT( 0 == (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY),
+ "Flash busy at start of erase, but it shouldn't be" );
+#endif
+
+ // Unlock the flash control registers
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY1 );
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY2 );
+
+#if defined(F1STYLE)
+ cr = CYGHWR_HAL_STM32_FLASH_CR_PER;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr );
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_AR, addr );
+ cr |= CYGHWR_HAL_STM32_FLASH_CR_STRT;
+#elif defined(F2STYLE)
+ cr = CYGHWR_HAL_STM32_FLASH_CR_SER |
+ CR_PSIZE_MAX |
+ CYGHWR_HAL_STM32_FLASH_CR_SNB(block_num) |
+ CYGHWR_HAL_STM32_FLASH_CR_STRT;
+#endif
+
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr );
+
+ WAIT_FOR_FLASH_NOT_BUSY( timeout );
+
+ // Lock CR again (and clear other bits)
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, CYGHWR_HAL_STM32_FLASH_CR_LOCK );
+
+#ifdef F2STYLE
+ // For F2 parts, we need to disable and reset the icache and dcache in the ACR.
+ {
+ cyg_uint32 acr;
+
+ HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // disable
+ acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN);
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // reset
+ acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // re-enable
+ acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST);
+ acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ }
+#endif
+
+ if (0 == timeout)
+ return -1;
+
+ return sr;
+}
+
+// ----------------------------------------------------------------------------
+// Write data to flash, using individual word writes on F1, or something more
+// complicated on F2. On F1, the destination address will be aligned in a way suitable
+// for the bus. The source address need not be aligned. The count is in STM32_TYPE's on
+// F1, bytes on F2.
+
+static int
+stm32_flash_hw_program( volatile STM32_TYPE* addr, const STM32_TYPE* buf, cyg_uint32 count)
+{
+ cyg_uint32 base = CYGHWR_HAL_STM32_FLASH;
+ cyg_uint32 sr = 0, cr = 0;
+ cyg_uint32 timeout = 1; // Have to set timeout to non-zero to avoid confusing tests later.
+
+#ifdef CYGDBG_USE_ASSERTS
+ HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_SR, sr );
+ CYG_ASSERT( 0 == (sr & CYGHWR_HAL_STM32_FLASH_SR_BSY),
+ "Flash busy at start of program, but it shouldn't be" );
+#endif
+
+ // Unlock the flash control registers
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY1 );
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_KEYR, CYGHWR_HAL_STM32_FLASH_KEYR_KEY2 );
+
+#if defined(F1STYLE)
+ cr |= CYGHWR_HAL_STM32_FLASH_CR_PG;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr );
+
+ while( count-- )
+ {
+ HAL_WRITE_UINT16( addr, *buf );
+ addr++;
+ buf++;
+
+ WAIT_FOR_FLASH_NOT_BUSY(timeout);
+ if ( 0 == timeout )
+ break;
+ }
+
+
+#elif defined(F2STYLE)
+ // F2 is more complicated because the alignment depends on the parallelism.
+ // So we "simplify" by writing bytes until we've reached the desired alignment.
+
+ {
+ CYG_ADDRESS addr_max = (CYG_ADDRESS)addr + PARALLEL_ALIGN_MASK;
+ addr_max &= ~PARALLEL_ALIGN_MASK;
+
+ byte_write:
+ cr = CYGHWR_HAL_STM32_FLASH_CR_PG | CYGHWR_HAL_STM32_FLASH_CR_PSIZE_8;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr );
+
+ while (count && ((CYG_ADDRESS)addr < addr_max))
+ {
+ HAL_WRITE_UINT8( addr, *buf );
+ addr++;
+ buf++;
+ count--;
+ WAIT_FOR_FLASH_NOT_BUSY(timeout);
+ if (0 == timeout)
+ break;
+ }
+
+ if ( count && timeout )
+ {
+ // Now we should be aligned to the required parallelism boundary
+ // But we have to make sure we stop at an aligned addr too.
+ addr_max += count;
+ addr_max &= ~PARALLEL_ALIGN_MASK;
+
+ cr = CYGHWR_HAL_STM32_FLASH_CR_PG | CR_PSIZE_MAX;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, cr );
+ while ((CYG_ADDRESS)addr < addr_max)
+ {
+#if (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 8)
+ HAL_WRITE_UINT8( addr, *buf );
+#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 16)
+ cyg_uint16 wbuf = *(cyg_uint16*)buf;
+ HAL_WRITE_UINT16( addr, wbuf );
+#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 32)
+ cyg_uint32 wbuf = *(cyg_uint32*)buf;
+ HAL_WRITE_UINT32( addr, wbuf );
+#elif (CYGNUM_DEVS_FLASH_STM32_PARALLELISM == 64)
+ cyg_uint64 wbuf = *(cyg_uint64*)buf;
+ HAL_WRITE_UINT64( addr, wbuf );
+#endif
+ addr += PARALLEL_BYTES;
+ buf += PARALLEL_BYTES;
+ count -= PARALLEL_BYTES;
+ WAIT_FOR_FLASH_NOT_BUSY(timeout);
+ if (0 == timeout)
+ break;
+ } // while
+ } // if
+
+ if ( count && timeout )
+ {
+ // Still have some bytes left to write. Take a shortcut with goto, to save code.
+ addr_max = (CYG_ADDRESS)addr+count;
+ goto byte_write;
+ } // if
+ }
+
+ // For F2 parts, we need to disable and reset the icache and dcache in the ACR.
+ {
+ cyg_uint32 acr;
+
+ HAL_READ_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // disable
+ acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN);
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // reset
+ acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ // re-enable
+ acr &= ~(CYGHWR_HAL_STM32_FLASH_ACR_DCRST|CYGHWR_HAL_STM32_FLASH_ACR_ICRST);
+ acr |= CYGHWR_HAL_STM32_FLASH_ACR_DCEN|CYGHWR_HAL_STM32_FLASH_ACR_ICEN;
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_ACR, acr );
+ }
+#endif // elif defined(F2STYLE)
+
+ // Lock CR again (and clear other bits)
+ HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FLASH_CR, CYGHWR_HAL_STM32_FLASH_CR_LOCK );
+
+ if (0 == timeout)
+ return -1;
+
+ return sr;
+}
+
+// ----------------------------------------------------------------------------
+// Erase a single block. The calling code will have supplied a pointer
+// aligned to a block boundary.
+
+static int
+stm32_flash_erase(struct cyg_flash_dev* dev, cyg_flashaddr_t dest)
+{
+ int (*erase_fn)(cyg_uint32, cyg_uint16);
+ cyg_flashaddr_t block_start;
+ size_t block_size;
+ cyg_uint16 block_num;
+ int result;
+ int hsi;
+ STM32_INTSCACHE_STATE;
+
+ stf_diag("dest %p\n", (void *) dest);
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ CYG_ASSERT((dest >= dev->start) && (dest <= dev->end), "flash address out of device range");
+
+ stm32_flash_get_block_info(dev, dest, &block_start, &block_size, &block_num);
+ stf_diag("block_start %p block_size %d\n", (void *) block_start, block_size);
+ CYG_ASSERT(dest == block_start, "erase address should be the start of a flash block");
+
+ erase_fn = (int (*)(cyg_uint32, cyg_uint16)) cyg_flash_anonymizer( & stm32_flash_hw_erase );
+
+ hsi = stm32_enable_hsi();
+
+ STM32_INTSCACHE_BEGIN();
+
+ result = (*erase_fn)(block_start, block_num);
+ result = stm32_flash_decode_error( result );
+ stm32_flash_clear_sr_err();
+
+ STM32_INTSCACHE_END();
+
+ if (hsi)
+ stm32_disable_hsi();
+
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+// Write some data to the flash. The destination must be aligned to a
+// 16 bit boundary. Higher level code guarantees that the data will
+// not straddle a block boundary.
+
+int
+stm32_flash_program(struct cyg_flash_dev* dev, cyg_flashaddr_t dest, const void* src, size_t len)
+{
+ int (*program_fn)(volatile STM32_TYPE*, const STM32_TYPE*, cyg_uint32);
+ volatile STM32_TYPE* uncached;
+ const STM32_TYPE* data;
+ size_t to_write;
+ int result = CYG_FLASH_ERR_OK;
+ int hsi;
+
+ STM32_INTSCACHE_STATE;
+
+ stf_diag("dest %p src %p len %p(%d)\n", (void *) dest, src, (void *) len, len);
+ CYG_CHECK_DATA_PTR(dev, "valid flash device pointer required");
+ CYG_ASSERT((dest >= dev->start) && ((CYG_ADDRESS)dest <= dev->end), "flash address out of device range");
+
+#ifdef F1STYLE
+ // Source and destination must be 16-bit aligned.
+ if( (0 != ((CYG_ADDRESS)dest & 1)) ||
+ (0 != ((CYG_ADDRESS)src & 1)) )
+ return CYG_FLASH_ERR_INVALID;
+#endif
+
+ uncached = STM32_UNCACHED_ADDRESS(dest);
+ data = (const STM32_TYPE*) src;
+ to_write = len / sizeof(STM32_TYPE); // For F1: Number of words, not bytes. For F2: STM32_TYPE is a byte.
+ program_fn = (int (*)(volatile STM32_TYPE*, const STM32_TYPE*, cyg_uint32)) cyg_flash_anonymizer( & stm32_flash_hw_program );
+
+ hsi = stm32_enable_hsi();
+
+ STM32_INTSCACHE_BEGIN();
+ while (to_write > 0)
+ {
+ size_t this_write = (to_write < CYGNUM_DEVS_FLASH_STM32_V2_PROGRAM_BURST_SIZE) ?
+ to_write : CYGNUM_DEVS_FLASH_STM32_V2_PROGRAM_BURST_SIZE;
+
+
+ result = (*program_fn)(uncached, data, this_write);
+ result = stm32_flash_decode_error( result );
+ if (result != CYG_FLASH_ERR_OK)
+ {
+ break;
+ }
+ to_write -= this_write;
+ if (to_write > 0)
+ {
+ // There is still more to be written. The last write must have been a burst size
+ uncached += this_write;
+ data += this_write;
+ STM32_INTSCACHE_SUSPEND();
+ STM32_INTSCACHE_RESUME();
+ }
+ }
+ stm32_flash_clear_sr_err();
+ STM32_INTSCACHE_END();
+
+ if (hsi)
+ stm32_disable_hsi();
+
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+// Function table
+
+const CYG_FLASH_FUNS(cyg_stm32_flash_funs,
+ &stm32_flash_init,
+ &stm32_flash_query,
+ &stm32_flash_erase,
+ &stm32_flash_program,
+ (int (*)(struct cyg_flash_dev*, const cyg_flashaddr_t, void*, size_t))0,
+ cyg_flash_devfn_lock_nop,
+ cyg_flash_devfn_unlock_nop);
+
+// ----------------------------------------------------------------------------
+// End of stm32_flash.c