diff --git a/config/chips/L45x_L46x.chip b/config/chips/L45x_L46x.chip index cbe948c1f..c32030be9 100644 --- a/config/chips/L45x_L46x.chip +++ b/config/chips/L45x_L46x.chip @@ -12,3 +12,5 @@ bootrom_size 0x7000 // 28 KB option_base 0x0 option_size 0x0 flags swo +otp_base 0x1fff7000 +otp_size 0x400 // 1 KB diff --git a/config/chips/L496x_L4A6x.chip b/config/chips/L496x_L4A6x.chip index 24788c092..65fa3dcbc 100644 --- a/config/chips/L496x_L4A6x.chip +++ b/config/chips/L496x_L4A6x.chip @@ -12,3 +12,5 @@ bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_L4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo +otp_base 0x1fff7000 +otp_size 0x400 // 1 KB diff --git a/inc/stlink.h b/inc/stlink.h index dec608e97..557a9eeaa 100644 --- a/inc/stlink.h +++ b/inc/stlink.h @@ -232,6 +232,9 @@ struct _stlink { uint32_t chip_flags; // stlink_chipid_params.flags, set by stlink_load_device_params(), values: CHIP_F_xxx uint32_t max_trace_freq; // set by stlink_open_usb() + + uint32_t otp_base; + uint32_t otp_size; }; /* Functions defined in common.c */ diff --git a/src/st-flash/flash.c b/src/st-flash/flash.c index 0577ee179..0b7c0cfca 100644 --- a/src/st-flash/flash.c +++ b/src/st-flash/flash.c @@ -61,6 +61,8 @@ static void usage(void) { puts("example write option control register1 byte: ./st-flash --area=optcr write 0xXXXXXXXX"); puts("example read option control register1 byte: ./st-flash --area=optcr1 read"); puts("example write option control register1 byte: ./st-flash --area=optcr1 write 0xXXXXXXXX"); + puts("example read OTP area: ./st-flash --area=otp read [path]"); + puts("example write OTP area: ./st-flash --area=otp write [path] 0xXXXXXXXX"); } int32_t main(int32_t ac, char** av) { @@ -180,6 +182,18 @@ int32_t main(int32_t ac, char** av) { DLOG("@@@@ Write %d (%0#10x) to option bytes boot address\n", o.val, o.val); err = stlink_write_option_bytes_boot_add32(sl, o.val); + } else if (o.area == FLASH_OTP) { + if(sl->otp_base == 0) { + err = -1; + printf("OTP Write NOT implemented\n"); + goto on_error; + } + err = stlink_fwrite_flash(sl, o.filename, o.addr); + + if (err == -1) { + printf("stlink_fwrite_flash() == -1\n"); + goto on_error; + } } else { err = -1; printf("Unknown memory region\n"); @@ -284,6 +298,17 @@ int32_t main(int32_t ac, char** av) { } else { printf("%08x\n",option_byte); } + } else if (o.area == FLASH_OTP) { + if(sl->otp_base == 0) { + err = -1; + printf("OTP Read NOT implemented\n"); + goto on_error; + } + err = stlink_fread(sl, o.filename, 0, sl->otp_base, sl->otp_size); + if (err == -1) { + printf("could not read OTP area (%d)\n", err); + goto on_error; + } } } diff --git a/src/st-flash/flash_opts.c b/src/st-flash/flash_opts.c index 300203a3f..e2d4154fe 100644 --- a/src/st-flash/flash_opts.c +++ b/src/st-flash/flash_opts.c @@ -288,8 +288,7 @@ int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av) { break; } else if (o->area == FLASH_OTP) { - return bad_arg("TODO: otp not implemented yet"); - if (ac > 1) { return invalid_args("otp read: [path]"); } + if (ac > 1 || ac ==0 ) { return invalid_args("otp read: [path]"); } if (ac > 0) { o->filename = av[0]; } break; } else if (o->area == FLASH_OPTION_BYTES) { diff --git a/src/stlink-lib/chipid.c b/src/stlink-lib/chipid.c index 06edb26f3..ceeed3114 100644 --- a/src/stlink-lib/chipid.c +++ b/src/stlink-lib/chipid.c @@ -34,6 +34,8 @@ void dump_a_chip(struct stlink_chipid_params *dev) { DLOG("option_base 0x%x\n", dev->option_base); DLOG("option_size 0x%x\n", dev->option_size); DLOG("flags %d\n\n", dev->flags); + DLOG("otp_base %d\n\n", dev->otp_base); + DLOG("otp_size %d\n\n", dev->otp_size); } struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chip_id) { @@ -182,6 +184,18 @@ void process_chipfile(char *fname) { } sscanf(value, "%x", &ts->flags); + } else if (strcmp(word, "otp_base") == 0) { + buf[strlen(buf) - 1] = 0; // chomp newline + sscanf(buf, "%*s %n", &nc); + if (sscanf(value, "%i", &ts->otp_base) < 1) { + fprintf(stderr, "Failed to parse option size\n"); + } + } else if (strcmp(word, "otp_size") == 0) { + buf[strlen(buf) - 1] = 0; // chomp newline + sscanf(buf, "%*s %n", &nc); + if (sscanf(value, "%i", &ts->otp_size) < 1) { + fprintf(stderr, "Failed to parse option size\n"); + } } else { fprintf(stderr, "Unknown keyword in %s: %s\n", fname, word); } diff --git a/src/stlink-lib/chipid.h b/src/stlink-lib/chipid.h index 6726a7420..cf97e6609 100644 --- a/src/stlink-lib/chipid.h +++ b/src/stlink-lib/chipid.h @@ -21,6 +21,8 @@ struct stlink_chipid_params { uint32_t option_base; uint32_t option_size; uint32_t flags; + uint32_t otp_base; + uint32_t otp_size; struct stlink_chipid_params *next; }; diff --git a/src/stlink-lib/common.c b/src/stlink-lib/common.c index dbfcc8b9e..337fe6efa 100644 --- a/src/stlink-lib/common.c +++ b/src/stlink-lib/common.c @@ -290,6 +290,8 @@ int32_t stlink_load_device_params(stlink_t *sl) { sl->option_base = params->option_base; sl->option_size = params->option_size; sl->chip_flags = params->flags; + sl->otp_base = params->otp_base; + sl->otp_size = params->otp_size; // medium and low devices have the same chipid. ram size depends on flash // size. STM32F100xx datasheet Doc ID 16455 Table 2 diff --git a/src/stlink-lib/common_flash.c b/src/stlink-lib/common_flash.c index 3038b53e7..7172352ee 100644 --- a/src/stlink-lib/common_flash.c +++ b/src/stlink-lib/common_flash.c @@ -1310,9 +1310,16 @@ int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { * If the file is identified to be all-empty and four-bytes aligned, * still flash the whole file even if ignoring message is printed. */ - err = stlink_write_flash(sl, addr, mf.base, + + /* In case the address is within the OTP area we use a different flash method */ + if(addr >= sl->otp_base && addr < sl->otp_base + sl->otp_size) { + err = stlink_write_otp(sl, addr, mf.base, + (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty); + } else { + err = stlink_write_flash(sl, addr, mf.base, (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty, num_empty == mf.len); + } stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); @@ -1389,6 +1396,22 @@ int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uin return 0; } +// Check if an address and size are within the flash (otp area) +int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size) { + uint32_t logvar; + if (addr < sl->otp_base || addr >= (sl->otp_base + sl->otp_size)) { + logvar = sl->otp_base + sl->otp_size - 1; + ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->otp_base, logvar); + return (-1); + } + if ((addr + size) >= (sl->otp_base + sl->otp_size)) { + logvar = sl->otp_base + sl->otp_size - addr; + ELOG("The size exceeds the size of the OTP Area (0x%08x bytes available)\n", logvar); + return (-1); + } + return 0; +} + // Check if an address is aligned with the beginning of a page int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr) { stm32_addr_t page = sl->flash_base; @@ -1408,6 +1431,7 @@ int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint3 int32_t ret; flash_loader_t fl; ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); + // check addr range is inside the flash stlink_calculate_pagesize(sl, addr); @@ -1437,7 +1461,33 @@ int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint3 if (eraseonly) { return (0); } + + ret = stlink_flashloader_start(sl, &fl); + if (ret) + return ret; + ret = stlink_flashloader_write(sl, &fl, addr, base, len); + if (ret) + return ret; + ret = stlink_flashloader_stop(sl, &fl); + if (ret) + return ret; + + return (stlink_verify_write_flash(sl, addr, base, len)); +} + +int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { + int32_t ret; + flash_loader_t fl; + ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); + + // Check the address and size validity + if (stlink_check_address_range_validity_otp(sl, addr, len) < 0) { + return (-1); + } + // make sure we've loaded the context with the chip details + stlink_core_id(sl); + ret = stlink_flashloader_start(sl, &fl); if (ret) return ret; diff --git a/src/stlink-lib/common_flash.h b/src/stlink-lib/common_flash.h index 9b2b84057..238f0403e 100644 --- a/src/stlink-lib/common_flash.h +++ b/src/stlink-lib/common_flash.h @@ -44,8 +44,10 @@ int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length); int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size); +int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size); int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr); int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly); +int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); void stlink_fwrite_finalize(stlink_t *, stm32_addr_t); #endif // COMMON_FLASH_H