stlink/src/stlink-lib/option_bytes.c

1104 wiersze
29 KiB
C

/*
* File: option_bytes.c
*
* Read and write option bytes and option control registers
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stlink.h>
#include "option_bytes.h"
#include "common_flash.h"
#include "flash_loader.h"
#include "logging.h"
#include "map_file.h"
#include "md5.h"
#include "read_write.h"
/**
* Read option control register F0
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t 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);
}
/**
* Write option bytes F0
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) {
int32_t 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 control register F0
* @param sl
* @param option_cr
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr) {
int32_t ret = 0;
uint16_t opt_val[8];
uint32_t protection, optiondata;
uint16_t user_options, user_data, rdp;
uint32_t option_offset, user_data_offset;
ILOG("Asked to write option control register %#10x to %#010x.\n", option_cr, 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_cr >> option_offset >> 2) & 0xFFFF;
user_data = (option_cr >> user_data_offset) & 0xFFFF;
#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00))
opt_val[0] = (option_cr & (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, STM32_F0_OPTION_BYTES_BASE, (uint8_t*)opt_val, sizeof(opt_val));
if (ret)
return ret;
ret = check_flash_error(sl);
if (!ret) {
ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr,
FLASH_OBR);
}
return ret;
}
/**
* Read option control register F2
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte);
}
/**
* Read option bytes F2
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_option_control_register_f2(sl, option_byte);
}
/**
* Read option control register F4
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte);
}
/**
* Read option bytes F4
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_option_control_register_f4(sl, option_byte);
}
/**
* Write option bytes F4
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
uint32_t option_byte;
int32_t ret = 0;
(void)addr;
(void)len;
// Clear errors
clear_flash_error(sl);
write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
// write option byte, ensuring we dont lock opt, and set strt bit
stlink_write_debug32(sl, FLASH_F4_OPTCR,
(option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) |
(1 << FLASH_F4_OPTCR_START));
wait_flash_busy(sl);
ret = check_flash_error(sl);
// option bytes are reloaded at reset only, no obl. */
return (ret);
}
/**
* Read option bytes F7
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
// Since multiple bytes can be read, we read and print32_t all, but one here
// and then return the last one just like other devices.
int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) {
int32_t err = -1;
for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) {
err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte);
if (err == -1) {
return err;
} else {
printf("%08x\n", *option_byte);
}
}
return stlink_read_debug32(
sl,
sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t),
option_byte);
}
/**
* Write option bytes F7
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
uint32_t option_byte;
int32_t ret = 0;
// Clear errors
clear_flash_error(sl);
ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), addr);
write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr);
if (addr == 0) {
addr = FLASH_F7_OPTCR;
ILOG("No address provided, using %#10x\n", addr);
}
if (addr == FLASH_F7_OPTCR) {
/* write option byte, ensuring we dont lock opt, and set strt bit */
stlink_write_debug32(sl, FLASH_F7_OPTCR,
(option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) |
(1 << FLASH_F7_OPTCR_START));
} else if (addr == FLASH_F7_OPTCR1) {
// Read FLASH_F7_OPTCR
uint32_t oldvalue;
stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue);
/* write option byte */
stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte);
// Write FLASH_F7_OPTCR lock and start address
stlink_write_debug32(sl, FLASH_F7_OPTCR,
(oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) |
(1 << FLASH_F7_OPTCR_START));
} else {
WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr);
stlink_write_debug32(sl, addr, option_byte);
}
wait_flash_busy(sl);
ret = check_flash_error(sl);
if (!ret)
ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, addr);
/* option bytes are reloaded at reset only, no obl. */
return ret;
}
/**
* Read option control register F7
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte) {
DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR);
return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
}
/**
* Write option control register F7
* @param sl
* @param option_cr
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr) {
int32_t ret = 0;
// Clear errors
clear_flash_error(sl);
ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
option_cr, FLASH_F7_OPTCR);
/* write option byte, ensuring we dont lock opt, and set strt bit */
stlink_write_debug32(sl, FLASH_F7_OPTCR,
(option_cr & ~(1 << FLASH_F7_OPTCR_LOCK)) |
(1 << FLASH_F7_OPTCR_START));
wait_flash_busy(sl);
ret = check_flash_error(sl);
if (!ret)
ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr,
FLASH_F7_OPTCR);
return ret;
}
/**
* Read option control register1 F7
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte) {
DLOG("@@@@ Read option control register 1 byte from %#10x\n",
FLASH_F7_OPTCR1);
return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte);
}
/**
* Write option control register1 F7
* @param sl
* @param option_cr1
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1) {
int32_t ret = 0;
// Clear errors
clear_flash_error(sl);
ILOG("Asked to write option control register 1 %#010x to %#010x.\n",
option_cr1, FLASH_F7_OPTCR1);
/* write option byte, ensuring we dont lock opt, and set strt bit */
uint32_t current_control_register_value;
stlink_read_debug32(sl, FLASH_F7_OPTCR, &current_control_register_value);
/* write option byte */
stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_cr1);
stlink_write_debug32(
sl, FLASH_F7_OPTCR,
(current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) |
(1 << FLASH_F7_OPTCR_START));
wait_flash_busy(sl);
ret = check_flash_error(sl);
if (!ret)
ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr1, FLASH_F7_OPTCR1);
return ret;
}
/**
* Read option bytes boot address F7
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) {
DLOG("@@@@ Read option byte boot address\n");
return stlink_read_option_control_register1_f7(sl, option_byte);
}
/**
* Write option bytes boot address F7
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) {
ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add);
return stlink_write_option_control_register1_f7(sl, option_byte_boot_add);
}
/**
* Read option control register Gx
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_debug32(sl, FLASH_Gx_OPTR, option_byte);
}
/**
* Read option bytes Gx
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte) {
return stlink_read_option_control_register_gx(sl, option_byte);
}
/**
* Write option bytes Gx
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
/* Write options bytes */
uint32_t val;
int32_t ret = 0;
(void)len;
uint32_t data;
clear_flash_error(sl);
write_uint32((unsigned char *)&data, *(uint32_t *)(base));
WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
stlink_write_debug32(sl, FLASH_Gx_OPTR, data);
// Set Options Start bit
stlink_read_debug32(sl, FLASH_Gx_CR, &val);
val |= (1 << FLASH_Gx_CR_OPTSTRT);
stlink_write_debug32(sl, FLASH_Gx_CR, val);
wait_flash_busy(sl);
ret = check_flash_error(sl);
// Reload options
stlink_read_debug32(sl, FLASH_Gx_CR, &val);
val |= (1 << FLASH_Gx_CR_OBL_LAUNCH);
stlink_write_debug32(sl, FLASH_Gx_CR, val);
return (ret);
}
/**
* Write option bytes H7
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
uint32_t val;
uint32_t data;
// Wait until previous flash option has completed
wait_flash_busy(sl);
// Clear previous error
stlink_write_debug32(sl, FLASH_H7_OPTCCR,
1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
while (len != 0) {
switch (addr) {
case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG
case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1
case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1
case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1
case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG
/* Write to FLASH_xxx_PRG registers */
write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes
WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
/* Skip if the value in the CUR register is identical */
stlink_read_debug32(sl, addr - 4, &val);
if (val == data) {
break;
}
/* Write new option byte values and start modification */
stlink_write_debug32(sl, addr, data);
stlink_read_debug32(sl, FLASH_H7_OPTCR, &val);
val |= (1 << FLASH_H7_OPTCR_OPTSTART);
stlink_write_debug32(sl, FLASH_H7_OPTCR, val);
/* Wait for the option bytes modification to complete */
do {
stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val);
} while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0);
/* Check for errors */
if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) {
stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
return -1;
}
break;
default:
/* Skip non-programmable registers */
break;
}
len -= 4;
addr += 4;
base += 4;
}
return 0;
}
/**
* Write option bytes L0
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
uint32_t flash_base = get_stm32l0_flash_base(sl);
uint32_t val;
uint32_t data;
int32_t ret = 0;
// Clear errors
clear_flash_error(sl);
while (len != 0) {
write_uint32((unsigned char *)&data,
*(uint32_t *)(base)); // write options bytes
WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
stlink_write_debug32(sl, addr, data);
wait_flash_busy(sl);
if ((ret = check_flash_error(sl))) {
break;
}
len -= 4;
addr += 4;
base += 4;
}
// Reload options
stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val);
val |= (1 << FLASH_L0_OBL_LAUNCH);
stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val);
return (ret);
}
/**
* Write option bytes L4
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
uint32_t val;
int32_t ret = 0;
(void)addr;
(void)len;
// Clear errors
clear_flash_error(sl);
// write options bytes
uint32_t data;
write_uint32((unsigned char *)&data, *(uint32_t *)(base));
WLOG("Writing option bytes 0x%04x\n", data);
stlink_write_debug32(sl, FLASH_L4_OPTR, data);
// set options start bit
stlink_read_debug32(sl, FLASH_L4_CR, &val);
val |= (1 << FLASH_L4_CR_OPTSTRT);
stlink_write_debug32(sl, FLASH_L4_CR, val);
wait_flash_busy(sl);
ret = check_flash_error(sl);
// apply options bytes immediate
stlink_read_debug32(sl, FLASH_L4_CR, &val);
val |= (1 << FLASH_L4_CR_OBL_LAUNCH);
stlink_write_debug32(sl, FLASH_L4_CR, val);
return (ret);
}
/**
* Write option bytes WB
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
/* Write options bytes */
uint32_t val;
int32_t ret = 0;
(void)len;
uint32_t data;
clear_flash_error(sl);
while (len != 0) {
write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes
WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
stlink_write_debug32(sl, addr, data);
wait_flash_busy(sl);
if ((ret = check_flash_error(sl))) {
break;
}
len -= 4;
addr += 4;
base += 4;
}
// Set Options Start bit
stlink_read_debug32(sl, FLASH_WB_CR, &val);
val |= (1 << FLASH_WB_CR_OPTSTRT);
stlink_write_debug32(sl, FLASH_WB_CR, val);
wait_flash_busy(sl);
ret = check_flash_error(sl);
// Reload options
stlink_read_debug32(sl, FLASH_WB_CR, &val);
val |= (1 << FLASH_WB_CR_OBL_LAUNCH);
stlink_write_debug32(sl, FLASH_WB_CR, val);
return (ret);
}
/**
* Read option control register WB
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte) {
DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_WB_OPTR);
return stlink_read_debug32(sl, FLASH_WB_OPTR, option_byte);
}
/**
* Write option control register WB
* @param sl
* @param option_cr
* @return 0 on success, -ve on failure.
*/
static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr) {
int32_t ret = 0;
// Clear errors
clear_flash_error(sl);
ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
option_cr, FLASH_WB_OPTR);
/* write option byte, ensuring we dont lock opt, and set strt bit */
stlink_write_debug32(sl, FLASH_WB_OPTR, option_cr);
wait_flash_busy(sl);
// Set Options Start bit
uint32_t val = (1 << FLASH_WB_CR_OPTSTRT);
stlink_write_debug32(sl, FLASH_WB_CR, val);
wait_flash_busy(sl);
ret = check_flash_error(sl);
if (!ret)
ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_WB_OPTR);
return ret;
}
/**
* Read option bytes generic
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) {
DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
return stlink_read_debug32(sl, sl->option_base, option_byte);
}
/**
* Write option bytes
* @param sl
* @param addr of the memory mapped option bytes
* @param base option bytes
* @param len of option bytes
* @return 0 on success, -ve on failure.
*/
int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
int32_t ret = -1;
if (sl->option_base == 0) {
ELOG("Option bytes writing is currently not supported for connected chip\n");
return (-1);
}
if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) {
ELOG("Option bytes start address out of Option bytes range\n");
return (-1);
}
if (addr + len > sl->option_base + sl->option_size) {
ELOG("Option bytes data too long\n");
return (-1);
}
wait_flash_busy(sl);
if (unlock_flash_if(sl)) {
ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
return (-1);
}
if (unlock_flash_option_if(sl)) {
ELOG("Flash option unlock failed!\n");
return (-1);
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F0_F1_F3:
case STM32_FLASH_TYPE_F1_XL:
ret = stlink_write_option_bytes_f0(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_F2_F4:
ret = stlink_write_option_bytes_f4(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_F7:
ret = stlink_write_option_bytes_f7(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_L0_L1:
ret = stlink_write_option_bytes_l0(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_L4:
ret = stlink_write_option_bytes_l4(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_G0:
case STM32_FLASH_TYPE_G4:
ret = stlink_write_option_bytes_gx(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_H7:
ret = stlink_write_option_bytes_h7(sl, addr, base, len);
break;
case STM32_FLASH_TYPE_WB_WL:
ret = stlink_write_option_bytes_wb(sl, addr, base, len);
break;
default:
ELOG("Option bytes writing is currently not implemented for connected chip\n");
break;
}
if (ret) {
ELOG("Flash option write failed!\n");
} else {
ILOG("Wrote %d option bytes to %#010x!\n", len, addr);
}
/* Re-lock flash. */
lock_flash_option(sl);
lock_flash(sl);
return ret;
}
/**
* Write the given binary file with option bytes
* @param sl
* @param path readable file path, should be binary image
* @param addr of the memory mapped option bytes
* @return 0 on success, -ve on failure.
*/
int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr) {
/* Write the file in flash at addr */
int32_t err;
mapped_file_t mf = MAPPED_FILE_INITIALIZER;
if (map_file(&mf, path) == -1) {
ELOG("map_file() == -1\n");
return (-1);
}
printf("file %s ", path);
md5_calculate(&mf);
stlink_checksum(&mf);
err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len);
stlink_fwrite_finalize(sl, addr);
unmap_file(&mf);
return (err);
}
/**
* Read option control register 32
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
if (sl->option_base == 0) {
ELOG("Option bytes read is currently not supported for connected chip\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F0_F1_F3:
case STM32_FLASH_TYPE_F1_XL:
return stlink_read_option_control_register_f0(sl, option_byte);
case STM32_FLASH_TYPE_F7:
return stlink_read_option_control_register_f7(sl, option_byte);
case STM32_FLASH_TYPE_WB_WL:
return stlink_read_option_control_register_wb(sl, option_byte);
default:
return -1;
}
}
/**
* Write option control register 32
* @param sl
* @param option_cr
* @return 0 on success, -ve on failure.
*/
int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr) {
int32_t ret = -1;
wait_flash_busy(sl);
if (unlock_flash_if(sl)) {
ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
if (unlock_flash_option_if(sl)) {
ELOG("Flash option unlock failed!\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F0_F1_F3:
case STM32_FLASH_TYPE_F1_XL:
ret = stlink_write_option_control_register_f0(sl, option_cr);
break;
case STM32_FLASH_TYPE_F7:
ret = stlink_write_option_control_register_f7(sl, option_cr);
break;
case STM32_FLASH_TYPE_WB_WL:
ret =
stlink_write_option_control_register_wb(sl, option_cr);
break;
default:
ELOG("Option control register writing is currently not implemented for connected chip\n");
break;
}
if (ret)
ELOG("Flash option write failed!\n");
else
ILOG("Wrote option control register %#010x!\n", option_cr);
/* Re-lock flash. */
lock_flash_option(sl);
lock_flash(sl);
return ret;
}
/**
* Read option control register1 32
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte) {
if (sl->option_base == 0) {
ELOG("Option bytes read is currently not supported for connected chip\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F7:
return stlink_read_option_control_register1_f7(sl, option_byte);
default:
return -1;
// return stlink_read_option_control_register1_generic(sl, option_byte);
}
}
/**
* Write option control register1 32
* @param sl
* @param option_cr
* @return 0 on success, -ve on failure.
*/
int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1) {
int32_t ret = -1;
wait_flash_busy(sl);
if (unlock_flash_if(sl)) {
ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
if (unlock_flash_option_if(sl)) {
ELOG("Flash option unlock failed!\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F7:
ret =
stlink_write_option_control_register1_f7(sl, option_cr1);
break;
default:
ELOG("Option control register 1 writing is currently not implemented for "
"connected chip\n");
break;
}
if (ret)
ELOG("Flash option write failed!\n");
else
ILOG("Wrote option control register 1 %#010x!\n", option_cr1);
lock_flash_option(sl);
lock_flash(sl);
return (ret);
}
/**
* Read option bytes 32
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) {
if (sl->option_base == 0) {
ELOG("Option bytes read is currently not supported for connected chip\n");
return (-1);
}
switch (sl->chip_id) {
case STM32_CHIPID_F2:
return stlink_read_option_bytes_f2(sl, option_byte);
case STM32_CHIPID_F4:
case STM32_CHIPID_F446:
return stlink_read_option_bytes_f4(sl, option_byte);
case STM32_CHIPID_F76xxx:
return stlink_read_option_bytes_f7(sl, option_byte);
case STM32_CHIPID_G0_CAT1:
case STM32_CHIPID_G0_CAT2:
case STM32_CHIPID_G4_CAT2:
case STM32_CHIPID_G4_CAT3:
case STM32_CHIPID_G4_CAT4:
return stlink_read_option_bytes_gx(sl, option_byte);
default:
return stlink_read_option_bytes_generic(sl, option_byte);
}
}
/**
* Write option bytes 32
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) {
WLOG("About to write option byte %#10x to %#10x.\n", option_byte,
sl->option_base);
return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, 4);
}
/**
* Read option bytes boot address 32
* @param sl
* @param option_byte
* @return 0 on success, -ve on failure.
*/
int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
if (sl->option_base == 0) {
ELOG("Option bytes boot address read is currently not supported for connected chip\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F7:
return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
default:
return -1;
// return stlink_read_option_bytes_boot_add_generic(sl, option_byte);
}
}
/**
* Write option bytes boot address 32
* @param sl
* @param option_bytes_boot_add
* @return 0 on success, -ve on failure.
*/
int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) {
int32_t ret = -1;
wait_flash_busy(sl);
if (unlock_flash_if(sl)) {
ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
return -1;
}
if (unlock_flash_option_if(sl)) {
ELOG("Flash option unlock failed!\n");
return -1;
}
switch (sl->flash_type) {
case STM32_FLASH_TYPE_F7:
ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add);
break;
default:
ELOG("Option bytes boot address writing is currently not implemented for connected chip\n");
break;
}
if (ret)
ELOG("Flash option write failed!\n");
else
ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add);
/* Re-lock flash. */
lock_flash_option(sl);
lock_flash(sl);
return ret;
}