Flash handling for STM32F76x/77x and F446 added

- added ids for various parts
- rewrite of sector allocation to deal with dual-bank F76x/77x
- single- / dual-bank mode for F76x/77x
- sector protection adapted for F76x/77x in dual-bank mode
- handling of additional option bits (28-31) in FLASH_OPTCR
  in options_read and options_write for F42x/43x/469/479/7xx,
  options bits 0-1 masked out
- check for sensible value of user_options in options_write

- some #defines clarified, non-needed ones removed

- docs updated (options read, options write)

Change-Id: Ie4db80e60baa7d2663e024ab1f278640b1ce901b
Signed-off-by: Andreas Bolsch <hyphen0break@gmail.com>
Reviewed-on: http://openocd.zylin.com/3526
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
__archive__
Andreas Bolsch 2016-06-20 21:02:29 +02:00 committed by Andreas Fritiofson
parent f4dfa3b0d0
commit 4e9ee81f0c
2 changed files with 331 additions and 100 deletions

View File

@ -5827,8 +5827,8 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn {Flash Driver} stm32f2x @deffn {Flash Driver} stm32f2x
All members of the STM32F2 and STM32F4 microcontroller families from ST Microelectronics All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from ST Microelectronics
include internal flash and use ARM Cortex-M3/M4 cores. include internal flash and use ARM Cortex-M3/M4/M7 cores.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -5851,6 +5851,19 @@ The @var{num} parameter is a value shown by @command{flash banks}.
Unlocks the entire stm32 device. Unlocks the entire stm32 device.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn Command {stm32f2x options_read} num
Reads and displays user options and (where implemented) boot_addr0 and boot_addr1.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn Command {stm32f2x options_write} num user_options boot_addr0 boot_addr1
Writes user options and (where implemented) boot_addr0 and boot_addr1 in raw format.
Warning: The meaning of the various bits depends on the device, always check datasheet!
The @var{num} parameter is a value shown by @command{flash banks}, user_options a
12 bit value, consisting of bits 31-28 and 7-0 of FLASH_OPTCR, boot_addr0 and boot_addr1
two halfwords (of FLASH_OPTCR1).
@end deffn
@end deffn @end deffn
@deffn {Flash Driver} stm32lx @deffn {Flash Driver} stm32lx

View File

@ -63,9 +63,15 @@
* 1 MiByte STM32F42x/43x part with DB1M Option set: * 1 MiByte STM32F42x/43x part with DB1M Option set:
* 4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128. * 4 x 16, 1 x 64, 3 x 128, 4 x 16, 1 x 64, 3 x 128.
* *
* STM32F7 * STM32F7[4|5]
* 1 MiByte part with 4 x 32, 1 x 128, 3 x 256. * 1 MiByte part with 4 x 32, 1 x 128, 3 x 256.
* *
* STM32F7[6|7]
* 1 MiByte part in single bank mode with 4 x 32, 1 x 128, 3 x 256.
* 1 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 3 x 128 each.
* 2 MiByte part in single-bank mode with 4 x 32, 1 x 128, 7 x 256.
* 2 MiByte part in dual-bank mode two banks with 4 x 16, 1 x 64, 7 x 128 each.
*
* Protection size is sector size. * Protection size is sector size.
* *
* Tested with STM3220F-EVAL board. * Tested with STM3220F-EVAL board.
@ -84,6 +90,9 @@
* RM0385 * RM0385
* http://www.st.com/web/en/resource/technical/document/reference_manual/DM00124865.pdf * http://www.st.com/web/en/resource/technical/document/reference_manual/DM00124865.pdf
* *
* RM0410
* http://www.st.com/resource/en/reference_manual/dm00224583.pdf
*
* STM32F1x series - notice that this code was copy, pasted and knocked * STM32F1x series - notice that this code was copy, pasted and knocked
* into a stm32f2x driver, so in case something has been converted or * into a stm32f2x driver, so in case something has been converted or
* bugs haven't been fixed, here are the original manuals: * bugs haven't been fixed, here are the original manuals:
@ -111,11 +120,10 @@
#define STM32_FLASH_OPTCR1 0x40023c18 #define STM32_FLASH_OPTCR1 0x40023c18
/* FLASH_CR register bits */ /* FLASH_CR register bits */
#define FLASH_PG (1 << 0) #define FLASH_PG (1 << 0)
#define FLASH_SER (1 << 1) #define FLASH_SER (1 << 1)
#define FLASH_MER (1 << 2) #define FLASH_MER (1 << 2) /* MER/MER1 for f76x/77x */
#define FLASH_MER1 (1 << 15) #define FLASH_MER1 (1 << 15) /* MER2 for f76x/77x, confusing ... */
#define FLASH_STRT (1 << 16) #define FLASH_STRT (1 << 16)
#define FLASH_PSIZE_8 (0 << 8) #define FLASH_PSIZE_8 (0 << 8)
#define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_16 (1 << 8)
@ -127,7 +135,6 @@
#define FLASH_LOCK (1 << 31) #define FLASH_LOCK (1 << 31)
/* FLASH_SR register bits */ /* FLASH_SR register bits */
#define FLASH_BSY (1 << 16) #define FLASH_BSY (1 << 16)
#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ #define FLASH_PGSERR (1 << 7) /* Programming sequence error */
#define FLASH_PGPERR (1 << 6) /* Programming parallelism error */ #define FLASH_PGPERR (1 << 6) /* Programming parallelism error */
@ -138,22 +145,12 @@
#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR) #define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR)
/* STM32_FLASH_OPTCR register bits */ /* STM32_FLASH_OPTCR register bits */
#define OPTCR_LOCK (1 << 0)
#define OPT_LOCK (1 << 0) #define OPTCR_START (1 << 1)
#define OPT_START (1 << 1) #define OPTCR_NDBANK (1 << 29) /* not dual bank mode */
#define OPTCR_DB1M (1 << 30) /* 1 MiB devices dual flash bank option */
/* STM32_FLASH_OBR bit definitions (reading) */
#define OPT_ERROR 0
#define OPT_READOUT 1
#define OPT_RDWDGSW 2
#define OPT_RDRSTSTOP 3
#define OPT_RDRSTSTDBY 4
#define OPT_BFB2 5 /* dual flash bank only */
#define OPT_DB1M 14 /* 1 MiB devices dual flash bank option */
/* register unlock keys */ /* register unlock keys */
#define KEY1 0x45670123 #define KEY1 0x45670123
#define KEY2 0xCDEF89AB #define KEY2 0xCDEF89AB
@ -163,14 +160,17 @@
struct stm32x_options { struct stm32x_options {
uint8_t RDP; uint8_t RDP;
uint8_t user_options; uint16_t user_options; /* bit 0-7 usual options, bit 8-11 extra options */
uint32_t protection; uint32_t protection;
uint32_t boot_addr;
}; };
struct stm32x_flash_bank { struct stm32x_flash_bank {
struct stm32x_options option_bytes; struct stm32x_options option_bytes;
int probed; int probed;
bool has_large_mem; /* stm32f42x/stm32f43x family */ bool has_large_mem; /* F42x/43x/469/479/7xx in dual bank mode */
bool has_boot_addr; /* F7xx */
bool has_extra_options; /* F42x/43x/469/479/7xx */
uint32_t user_bank_size; uint32_t user_bank_size;
}; };
@ -284,7 +284,7 @@ static int stm32x_unlock_option_reg(struct target *target)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
if ((ctrl & OPT_LOCK) == 0) if ((ctrl & OPTCR_LOCK) == 0)
return ERROR_OK; return ERROR_OK;
/* unlock option registers */ /* unlock option registers */
@ -300,7 +300,7 @@ static int stm32x_unlock_option_reg(struct target *target)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
if (ctrl & OPT_LOCK) { if (ctrl & OPTCR_LOCK) {
LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl); LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl);
return ERROR_TARGET_FAILURE; return ERROR_TARGET_FAILURE;
} }
@ -321,18 +321,30 @@ static int stm32x_read_options(struct flash_bank *bank)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
stm32x_info->option_bytes.user_options = optiondata & 0xec; /* caution: F2 implements 5 bits (WDG_SW only)
* whereas F7 6 bits (IWDG_SW and WWDG_SW) in user_options */
stm32x_info->option_bytes.user_options = optiondata & 0xfc;
stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff;
stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff; stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff;
if (stm32x_info->has_large_mem) { if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
stm32x_info->option_bytes.user_options |= (optiondata >> 20) & 0xf00;
}
if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
retval = target_read_u32(target, STM32_FLASH_OPTCR1, &optiondata); retval = target_read_u32(target, STM32_FLASH_OPTCR1, &optiondata);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
/* append protection bits */ /* FLASH_OPTCR1 has quite diffent meanings ... */
stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000; if (stm32x_info->has_boot_addr) {
/* for F7xx it contains boot0 and boot1 */
stm32x_info->option_bytes.boot_addr = optiondata;
} else {
/* for F42x/43x/469/479 it contains 12 additional protection bits */
stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000;
}
} }
if (stm32x_info->option_bytes.RDP != 0xAA) if (stm32x_info->option_bytes.RDP != 0xAA)
@ -345,7 +357,7 @@ static int stm32x_write_options(struct flash_bank *bank)
{ {
struct stm32x_flash_bank *stm32x_info = NULL; struct stm32x_flash_bank *stm32x_info = NULL;
struct target *target = bank->target; struct target *target = bank->target;
uint32_t optiondata; uint32_t optiondata, optiondata2;
stm32x_info = bank->driver_priv; stm32x_info = bank->driver_priv;
@ -354,26 +366,36 @@ static int stm32x_write_options(struct flash_bank *bank)
return retval; return retval;
/* rebuild option data */ /* rebuild option data */
optiondata = stm32x_info->option_bytes.user_options; optiondata = stm32x_info->option_bytes.user_options & 0xfc;
optiondata |= stm32x_info->option_bytes.RDP << 8; optiondata |= stm32x_info->option_bytes.RDP << 8;
optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16; optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16;
if (stm32x_info->has_extra_options) {
/* F42x/43x/469/479 and 7xx have up to 4 bits of extra options */
optiondata |= (stm32x_info->option_bytes.user_options & 0xf00) << 20;
}
if (stm32x_info->has_large_mem || stm32x_info->has_boot_addr) {
if (stm32x_info->has_boot_addr) {
/* F7xx uses FLASH_OPTCR1 for boot0 and boot1 ... */
optiondata2 = stm32x_info->option_bytes.boot_addr;
} else {
/* F42x/43x/469/479 uses FLASH_OPTCR1 for additional protection bits */
optiondata2 = (stm32x_info->option_bytes.protection & 0x00fff000) << 4;
}
retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2);
if (retval != ERROR_OK)
return retval;
}
/* program options */ /* program options */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata); retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
if (stm32x_info->has_large_mem) {
uint32_t optiondata2 = 0;
optiondata2 |= (stm32x_info->option_bytes.protection & 0x00fff000) << 4;
retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2);
if (retval != ERROR_OK)
return retval;
}
/* start programming cycle */ /* start programming cycle */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPT_START); retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_START);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -383,7 +405,7 @@ static int stm32x_write_options(struct flash_bank *bank)
return retval; return retval;
/* relock registers */ /* relock registers */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPT_LOCK); retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPTCR_LOCK);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -401,11 +423,25 @@ static int stm32x_protect_check(struct flash_bank *bank)
return retval; return retval;
} }
for (int i = 0; i < bank->num_sectors; i++) { if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
if (stm32x_info->option_bytes.protection & (1 << i)) /* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
bank->sectors[i].is_protected = 0; for (int i = 0; i < (bank->num_sectors >> 1); i++) {
else if (stm32x_info->option_bytes.protection & (1 << i)) {
bank->sectors[i].is_protected = 1; bank->sectors[i << 1].is_protected = 0;
bank->sectors[(i << 1) + 1].is_protected = 0;
} else {
bank->sectors[i << 1].is_protected = 1;
bank->sectors[(i << 1) + 1].is_protected = 1;
}
}
} else {
/* one protection bit per sector */
for (int i = 0; i < bank->num_sectors; i++) {
if (stm32x_info->option_bytes.protection & (1 << i))
bank->sectors[i].is_protected = 0;
else
bank->sectors[i].is_protected = 1;
}
} }
return ERROR_OK; return ERROR_OK;
@ -416,8 +452,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
struct target *target = bank->target; struct target *target = bank->target;
int i; int i;
assert(first < bank->num_sectors); assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
assert(last < bank->num_sectors);
if (bank->target->state != TARGET_HALTED) { if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted"); LOG_ERROR("Target not halted");
@ -477,8 +512,18 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
return retval; return retval;
} }
for (int i = first; i <= last; i++) { if (stm32x_info->has_boot_addr && stm32x_info->has_large_mem) {
/* F76x/77x: bit k protects sectors 2*k and 2*k+1 */
if ((first & 1) != 0 || (last & 1) != 1) {
LOG_ERROR("sector protection must be double sector aligned");
return ERROR_FAIL;
} else {
first >>= 1;
last >>= 1;
}
}
for (int i = first; i <= last; i++) {
if (set) if (set)
stm32x_info->option_bytes.protection &= ~(1 << i); stm32x_info->option_bytes.protection &= ~(1 << i);
else else
@ -719,14 +764,31 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK);
} }
static void setup_sector(struct flash_bank *bank, int start, int num, int size) static int setup_sector(struct flash_bank *bank, int start, int num, int size)
{ {
for (int i = start; i < (start + num) ; i++) { for (int i = start; i < (start + num) ; i++) {
assert(i < bank->num_sectors); assert(i < bank->num_sectors);
bank->sectors[i].offset = bank->size; bank->sectors[i].offset = bank->size;
bank->sectors[i].size = size; bank->sectors[i].size = size;
bank->size += bank->sectors[i].size; bank->size += bank->sectors[i].size;
LOG_DEBUG("sector %d: %dkBytes", i, size >> 10);
} }
return start + num;
}
static void setup_bank(struct flash_bank *bank, int start,
uint16_t flash_size_in_kb, uint16_t max_sector_size_in_kb)
{
int remain;
start = setup_sector(bank, start, 4, (max_sector_size_in_kb / 8) * 1024);
start = setup_sector(bank, start, 1, (max_sector_size_in_kb / 2) * 1024);
/* remaining sectors all of size max_sector_size_in_kb */
remain = (flash_size_in_kb / max_sector_size_in_kb) - 1;
start = setup_sector(bank, start, remain, max_sector_size_in_kb * 1024);
} }
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
@ -774,6 +836,8 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->probed = 0; stm32x_info->probed = 0;
stm32x_info->has_large_mem = false; stm32x_info->has_large_mem = false;
stm32x_info->has_boot_addr = false;
stm32x_info->has_extra_options = false;
/* read stm32 device id register */ /* read stm32 device id register */
int retval = stm32x_get_device_id(bank, &device_id); int retval = stm32x_get_device_id(bank, &device_id);
@ -781,33 +845,50 @@ static int stm32x_probe(struct flash_bank *bank)
return retval; return retval;
LOG_INFO("device id = 0x%08" PRIx32 "", device_id); LOG_INFO("device id = 0x%08" PRIx32 "", device_id);
/* set max flash size depending on family */ /* set max flash size depending on family, id taken from AN2606 */
switch (device_id & 0xfff) { switch (device_id & 0xfff) {
case 0x411: case 0x411: /* F20x/21x */
case 0x413: case 0x413: /* F40x/41x */
case 0x441:
max_flash_size_in_kb = 1024; max_flash_size_in_kb = 1024;
break; break;
case 0x419:
case 0x434: case 0x419: /* F42x/43x */
case 0x434: /* F469/479 */
stm32x_info->has_extra_options = true;
max_flash_size_in_kb = 2048; max_flash_size_in_kb = 2048;
break; break;
case 0x423:
case 0x423: /* F401xB/C */
max_flash_size_in_kb = 256; max_flash_size_in_kb = 256;
break; break;
case 0x431:
case 0x433: case 0x421: /* F446 */
case 0x421: case 0x431: /* F411 */
case 0x433: /* F401xD/E */
case 0x441: /* F412 */
max_flash_size_in_kb = 512; max_flash_size_in_kb = 512;
break; break;
case 0x458:
case 0x458: /* F410 */
max_flash_size_in_kb = 128; max_flash_size_in_kb = 128;
break; break;
case 0x449:
case 0x449: /* F74x/75x */
max_flash_size_in_kb = 1024; max_flash_size_in_kb = 1024;
max_sector_size_in_kb = 256; max_sector_size_in_kb = 256;
flash_size_reg = 0x1FF0F442; flash_size_reg = 0x1FF0F442;
stm32x_info->has_extra_options = true;
stm32x_info->has_boot_addr = true;
break; break;
case 0x451: /* F76x/77x */
max_flash_size_in_kb = 2048;
max_sector_size_in_kb = 256;
flash_size_reg = 0x1FF0F442;
stm32x_info->has_extra_options = true;
stm32x_info->has_boot_addr = true;
break;
default: default:
LOG_WARNING("Cannot identify target as a STM32 family."); LOG_WARNING("Cannot identify target as a STM32 family.");
return ERROR_FAIL; return ERROR_FAIL;
@ -836,33 +917,48 @@ static int stm32x_probe(struct flash_bank *bank)
/* did we assign flash size? */ /* did we assign flash size? */
assert(flash_size_in_kb != 0xffff); assert(flash_size_in_kb != 0xffff);
/* calculate numbers of pages */
int num_pages = (flash_size_in_kb / max_sector_size_in_kb) + 4;
/* Devices with > 1024 kiByte always are dual-banked */ /* Devices with > 1024 kiByte always are dual-banked */
if (flash_size_in_kb > 1024) if (flash_size_in_kb > 1024)
stm32x_info->has_large_mem = true; stm32x_info->has_large_mem = true;
/* F42x/43x 1024 kiByte devices have a dual bank option */ /* F42x/43x/469/479 1024 kiByte devices have a dual bank option */
if ((device_id & 0xfff) == 0x419 && (flash_size_in_kb == 1024)) { if ((device_id & 0xfff) == 0x419 || (device_id & 0xfff) == 0x434) {
uint32_t optiondata; uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_DEBUG("unable to read option bytes"); LOG_DEBUG("unable to read option bytes");
return retval; return retval;
} }
if (optiondata & (1 << OPT_DB1M)) { if ((flash_size_in_kb > 1024) || (optiondata & OPTCR_DB1M)) {
stm32x_info->has_large_mem = true; stm32x_info->has_large_mem = true;
LOG_INFO("Dual Bank 1024 kiB STM32F42x/43x found"); LOG_INFO("Dual Bank %d kiB STM32F42x/43x/469/479 found", flash_size_in_kb);
} else {
stm32x_info->has_large_mem = false;
LOG_INFO("Single Bank %d kiB STM32F42x/43x/469/479 found", flash_size_in_kb);
} }
} }
/* check for dual-banked devices */ /* F76x/77x devices have a dual bank option */
if (stm32x_info->has_large_mem) if ((device_id & 0xfff) == 0x451) {
num_pages += 4; uint32_t optiondata;
retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata);
if (retval != ERROR_OK) {
LOG_DEBUG("unable to read option bytes");
return retval;
}
if (optiondata & OPTCR_NDBANK) {
stm32x_info->has_large_mem = false;
LOG_INFO("Single Bank %d kiB STM32F76x/77x found", flash_size_in_kb);
} else {
stm32x_info->has_large_mem = true;
max_sector_size_in_kb >>= 1; /* sector size divided by 2 in dual-bank mode */
LOG_INFO("Dual Bank %d kiB STM32F76x/77x found", flash_size_in_kb);
}
}
/* check that calculation result makes sense */ /* calculate numbers of pages */
assert(num_pages > 0); int num_pages = flash_size_in_kb / max_sector_size_in_kb
+ (stm32x_info->has_large_mem ? 8 : 4);
if (bank->sectors) { if (bank->sectors) {
free(bank->sectors); free(bank->sectors);
@ -872,35 +968,25 @@ static int stm32x_probe(struct flash_bank *bank)
bank->base = base_address; bank->base = base_address;
bank->num_sectors = num_pages; bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
bank->size = 0;
/* fixed memory */
setup_sector(bank, 0, 4, (max_sector_size_in_kb / 8) * 1024);
setup_sector(bank, 4, 1, (max_sector_size_in_kb / 2) * 1024);
if (stm32x_info->has_large_mem) {
if (flash_size_in_kb == 1024) {
setup_sector(bank, 5, 3, 128 * 1024);
setup_sector(bank, 12, 4, 16 * 1024);
setup_sector(bank, 16, 1, 64 * 1024);
setup_sector(bank, 17, 3, 128 * 1024);
} else {
setup_sector(bank, 5, 7, 128 * 1024);
setup_sector(bank, 12, 4, 16 * 1024);
setup_sector(bank, 16, 1, 64 * 1024);
setup_sector(bank, 17, 7, 128 * 1024);
}
} else {
setup_sector(bank, 4 + 1, MIN(12, num_pages) - 5,
max_sector_size_in_kb * 1024);
}
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
bank->sectors[i].is_erased = -1; bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 0; bank->sectors[i].is_protected = 0;
} }
bank->size = 0;
LOG_DEBUG("allocated %d sectors", num_pages);
if (stm32x_info->has_large_mem) {
/* dual-bank */
setup_bank(bank, 0, flash_size_in_kb >> 1, max_sector_size_in_kb);
setup_bank(bank, num_pages >> 1, flash_size_in_kb >> 1,
max_sector_size_in_kb);
} else {
/* single-bank */
setup_bank(bank, 0, flash_size_in_kb, max_sector_size_in_kb);
}
assert((bank->size >> 10) == flash_size_in_kb);
stm32x_info->probed = 1; stm32x_info->probed = 1;
return ERROR_OK; return ERROR_OK;
} }
@ -950,11 +1036,24 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
case 0x2003: case 0x2003:
rev_str = "X"; rev_str = "X";
break; break;
case 0x2007:
rev_str = "1";
break;
case 0x200F:
rev_str = "V";
break;
case 0x201F:
rev_str = "2";
break;
} }
break; break;
case 0x413: case 0x413:
case 0x419: case 0x419:
case 0x434:
device_str = "STM32F4xx"; device_str = "STM32F4xx";
switch (rev_id) { switch (rev_id) {
@ -979,6 +1078,7 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
break; break;
} }
break; break;
case 0x421: case 0x421:
device_str = "STM32F446"; device_str = "STM32F446";
@ -988,6 +1088,7 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
break; break;
} }
break; break;
case 0x423: case 0x423:
case 0x431: case 0x431:
case 0x433: case 0x433:
@ -1019,8 +1120,9 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
break; break;
} }
break; break;
case 0x434:
device_str = "STM32F46x/F47x"; case 0x451:
device_str = "STM32F7[6|7]x";
switch (rev_id) { switch (rev_id) {
case 0x1000: case 0x1000:
@ -1146,6 +1248,7 @@ static int stm32x_mass_erase(struct flash_bank *bank)
flash_mer = FLASH_MER | FLASH_MER1; flash_mer = FLASH_MER | FLASH_MER1;
else else
flash_mer = FLASH_MER; flash_mer = FLASH_MER;
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), flash_mer); retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), flash_mer);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -1193,6 +1296,107 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
return retval; return retval;
} }
COMMAND_HANDLER(stm32f2x_handle_options_read_command)
{
int retval;
struct flash_bank *bank;
struct stm32x_flash_bank *stm32x_info = NULL;
if (CMD_ARGC != 1) {
command_print(CMD_CTX, "stm32f2x options_read <bank>");
return ERROR_COMMAND_SYNTAX_ERROR;
}
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
retval = stm32x_read_options(bank);
if (ERROR_OK != retval)
return retval;
stm32x_info = bank->driver_priv;
if (stm32x_info->has_extra_options) {
if (stm32x_info->has_boot_addr) {
uint32_t boot_addr = stm32x_info->option_bytes.boot_addr;
command_print(CMD_CTX, "stm32f2x user_options 0x%03X,"
" boot_add0 0x%04X, boot_add1 0x%04X",
stm32x_info->option_bytes.user_options,
boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16);
} else {
command_print(CMD_CTX, "stm32f2x user_options 0x%03X,",
stm32x_info->option_bytes.user_options);
}
} else {
command_print(CMD_CTX, "stm32f2x user_options 0x%02X",
stm32x_info->option_bytes.user_options);
}
return retval;
}
COMMAND_HANDLER(stm32f2x_handle_options_write_command)
{
int retval;
struct flash_bank *bank;
struct stm32x_flash_bank *stm32x_info = NULL;
uint16_t user_options, boot_addr0, boot_addr1;
if (CMD_ARGC < 1) {
command_print(CMD_CTX, "stm32f2x options_write <bank> ...");
return ERROR_COMMAND_SYNTAX_ERROR;
}
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
retval = stm32x_read_options(bank);
if (ERROR_OK != retval)
return retval;
stm32x_info = bank->driver_priv;
if (stm32x_info->has_boot_addr) {
if (CMD_ARGC != 4) {
command_print(CMD_CTX, "stm32f2x options_write <bank> <user_options>"
" <boot_addr0> <boot_addr1>");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], boot_addr0);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], boot_addr1);
stm32x_info->option_bytes.boot_addr = boot_addr0 | (((uint32_t) boot_addr1) << 16);
} else {
if (CMD_ARGC != 2) {
command_print(CMD_CTX, "stm32f2x options_write <bank> <user_options>");
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options);
if (user_options & (stm32x_info->has_extra_options ? ~0xffc : ~0xfc)) {
command_print(CMD_CTX, "stm32f2x invalid user_options");
return ERROR_COMMAND_SYNTAX_ERROR;
}
stm32x_info->option_bytes.user_options = user_options;
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32f2x failed to write options");
return ERROR_OK;
}
/* switching between single- and dual-bank modes requires re-probe */
/* ... and reprogramming of whole flash */
stm32x_info->probed = 0;
command_print(CMD_CTX, "stm32f2x write options complete.\n"
"INFO: a reset or power cycle is required "
"for the new settings to take effect.");
return retval;
}
static const struct command_registration stm32x_exec_command_handlers[] = { static const struct command_registration stm32x_exec_command_handlers[] = {
{ {
.name = "lock", .name = "lock",
@ -1215,6 +1419,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.usage = "bank_id", .usage = "bank_id",
.help = "Erase entire flash device.", .help = "Erase entire flash device.",
}, },
{
.name = "options_read",
.handler = stm32f2x_handle_options_read_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Read and display device option bytes.",
},
{
.name = "options_write",
.handler = stm32f2x_handle_options_write_command,
.mode = COMMAND_EXEC,
.usage = "bank_id user_options [ boot_add0 boot_add1]",
.help = "Write option bytes",
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };