Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for writing option bytes on STM32F0/F1/F3 #1112

Merged
merged 7 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions flashloaders/stm32f0.s
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,9 @@ copy:
# add r3 to flash_base for support dual bank (see flash_loader.c)
ldr r7, flash_base
add r7, r7, r3
ldr r6, flash_off_cr
add r6, r6, r7
ldr r5, flash_off_sr
add r5, r5, r7

# FLASH_CR = 0x01 (set PG)
ldr r4, =0x1
str r4, [r6]

loop:
# copy 2 bytes
ldrh r4, [r0]
Expand Down Expand Up @@ -68,18 +62,10 @@ wait:
bgt loop

exit:
# FLASH_CR &= ~1
ldr r7, =0x1
ldr r4, [r6]
bics r4, r4, r7
str r4, [r6]

bkpt

.align 2
flash_base:
.word 0x40022000
flash_off_cr:
.word 0x10
flash_off_sr:
.word 0x0c
214 changes: 193 additions & 21 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@
#define FLASH_CR_PER 1
#define FLASH_CR_MER 2
#define FLASH_CR_OPTPG 4
#define FLASH_CR_OPTER 5
#define FLASH_CR_STRT 6
#define FLASH_CR_LOCK 7
#define FLASH_CR_OPTWRE 9
#define FLASH_CR_OBL_LAUNCH 13

#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
Expand Down Expand Up @@ -3137,17 +3139,6 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
}

int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {

// According to DDI0419C, Table C1-7 firstly force halt
stlink_write_debug32(sl, STLINK_REG_DHCSR,
STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
STLINK_REG_DHCSR_C_HALT);
// and only then disable interrupts
stlink_write_debug32(sl, STLINK_REG_DHCSR,
STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
STLINK_REG_DHCSR_C_HALT |
STLINK_REG_DHCSR_C_MASKINTS);

// disable DMA
set_dma_state(sl, fl, 0);

Expand Down Expand Up @@ -3257,6 +3248,15 @@ int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {
ELOG("stlink_flash_loader_init() == -1\n");
return (-1);
}

// unlock flash
unlock_flash_if(sl);

// set programming mode
set_flash_cr_pg(sl, BANK_1);
if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
set_flash_cr_pg(sl, BANK_2);
}
} else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
ILOG("Starting Flash write for H7\n");

Expand Down Expand Up @@ -3437,7 +3437,9 @@ int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl,
int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
uint32_t dhcsr;

if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
(sl->flash_type == STLINK_FLASH_TYPE_F1_XL) ||
(sl->flash_type == STLINK_FLASH_TYPE_F4) ||
(sl->flash_type == STLINK_FLASH_TYPE_F7) ||
(sl->flash_type == STLINK_FLASH_TYPE_L4) ||
(sl->flash_type == STLINK_FLASH_TYPE_WB) ||
Expand All @@ -3446,8 +3448,9 @@ int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
(sl->flash_type == STLINK_FLASH_TYPE_H7)) {

clear_flash_cr_pg(sl, BANK_1);
if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
if ((sl->flash_type == STLINK_FLASH_TYPE_H7 &&
sl->chip_flags & CHIP_F_HAS_DUAL_BANK) ||
sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
clear_flash_cr_pg(sl, BANK_2);
}
lock_flash(sl);
Expand Down Expand Up @@ -3840,6 +3843,64 @@ int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
return (err);
}

/**
* Write option bytes
* @param sl
* @param base option bytes to write
* @param addr of the memory mapped option bytes
* @param len of options bytes to write
* @return 0 on success, -ve on failure.
*/
static int stlink_write_option_bytes_f0(
stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) {
int ret = 0;

if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) {
WLOG("Only full write of option bytes area is supported\n");
return -1;
}

clear_flash_error(sl);

WLOG("Erasing option bytes\n");

/* erase option bytes */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE));
ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE));
if (ret) {
return ret;
}

wait_flash_busy(sl);

ret = check_flash_error(sl);
if (ret) {
return ret;
}

WLOG("Writing option bytes to %#10x\n", addr);

/* Set the Option PG bit to enable programming */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE));

/* Use flash loader for write OP
* because flash memory writable by half word */
flash_loader_t fl;
ret = stlink_flash_loader_init(sl, &fl);
if (ret) {
return ret;
}
ret = stlink_flash_loader_run(sl, &fl, addr, base, len);
if (ret) {
return ret;
}

/* Reload option bytes */
stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH));

return check_flash_error(sl);
}

/**
* Write option bytes
* @param sl
Expand Down Expand Up @@ -4192,6 +4253,18 @@ int stlink_read_option_control_register_f7(stlink_t *sl,
return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
}

/**
* Read option bytes
* @param sl
* @param option_byte value to read
* @return 0 on success, -ve on failure.
*/
int stlink_read_option_control_register_f0(stlink_t *sl,
uint32_t *option_byte) {
DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR);
return stlink_read_debug32(sl, FLASH_OBR, option_byte);
}

/**
* Read option bytes
* @param sl
Expand Down Expand Up @@ -4335,8 +4408,8 @@ int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
default:
return -1;
Expand All @@ -4356,12 +4429,14 @@ int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
return stlink_read_option_control_register_f0(sl, option_byte);
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_control_register_f7(sl, option_byte);
default:
return -1;
// return stlink_read_option_control_register_generic(sl, option_byte);
}
}

Expand All @@ -4378,8 +4453,8 @@ int stlink_read_option_control_register1_32(stlink_t *sl,
return -1;
}

switch (sl->chip_id) {
case STLINK_CHIPID_STM32_F7XXXX:
switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F7:
return stlink_read_option_control_register1_f7(sl, option_byte);
default:
return -1;
Expand Down Expand Up @@ -4441,6 +4516,10 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
}

switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
ret = stlink_write_option_bytes_f0(sl, base, addr, len);
break;
case STLINK_FLASH_TYPE_F4:
ret = stlink_write_option_bytes_f4(sl, base, addr, len);
break;
Expand Down Expand Up @@ -4511,6 +4590,95 @@ stlink_write_option_control_register_f7(stlink_t *sl,
return ret;
}


/**
* Write option bytes
* @param sl
* @param option_byte value to write
* @return 0 on success, -ve on failure.
*/
static int
stlink_write_option_control_register_f0(stlink_t *sl,
uint32_t option_control_register) {
int ret = 0;
uint16_t opt_val[8];
unsigned protection, optiondata;
uint16_t user_options, user_data, rdp;
unsigned option_offset, user_data_offset;

ILOG("Asked to write option control register %#10x to %#010x.\n",
option_control_register, FLASH_OBR);

/* Clear errors */
clear_flash_error(sl);

/* Retrieve current values */
ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata);
if (ret) {
return ret;
}
ret = stlink_read_debug32(sl, FLASH_WRPR, &protection);
if (ret) {
return ret;
}

/* Translate OBR value to flash store structure
* F0: RM0091, Option byte description, pp. 75-78
* F1: PM0075, Option byte description, pp. 19-22
* F3: RM0316, Option byte description, pp. 85-87 */
switch(sl->chip_id)
{
case 0x422: /* STM32F30x */
case 0x432: /* STM32F37x */
case 0x438: /* STM32F303x6/8 and STM32F328 */
case 0x446: /* STM32F303xD/E and STM32F398xE */
case 0x439: /* stm32f302x6/8 */
case 0x440: /* stm32f05x */
case 0x444: /* stm32f03x */
case 0x445: /* stm32f04x */
case 0x448: /* stm32f07x */
case 0x442: /* stm32f09x */
option_offset = 6;
user_data_offset = 16;
rdp = 0x55AA;
break;
default:
option_offset = 0;
user_data_offset = 10;
rdp = 0x5AA5;
break;
}

user_options = (option_control_register >> option_offset >> 2) & 0xFFFF;
user_data = (option_control_register >> user_data_offset) & 0xFFFF;

#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00))

opt_val[0] = (option_control_register & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp;
opt_val[1] = VAL_WITH_COMPLEMENT(user_options);
opt_val[2] = VAL_WITH_COMPLEMENT(user_data);
opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8);
opt_val[4] = VAL_WITH_COMPLEMENT(protection);
opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8);
opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16);
opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24);

#undef VAL_WITH_COMPLEMENT

/* Write bytes and check errors */
ret = stlink_write_option_bytes_f0(sl, (uint8_t*)opt_val, STM32_F0_OPTION_BYTES_BASE, sizeof(opt_val));
if (ret)
return ret;

ret = check_flash_error(sl);
if (!ret) {
ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register,
FLASH_OBR);
}

return ret;
}

/**
* Write option bytes
* @param sl
Expand Down Expand Up @@ -4631,6 +4799,10 @@ int stlink_write_option_control_register32(stlink_t *sl,
}

switch (sl->flash_type) {
case STLINK_FLASH_TYPE_F0:
case STLINK_FLASH_TYPE_F1_XL:
ret = stlink_write_option_control_register_f0(sl, option_control_register);
break;
case STLINK_FLASH_TYPE_F7:
ret = stlink_write_option_control_register_f7(sl, option_control_register);
break;
Expand Down
Loading