This is an automated email from Gerrit. "Tigran Sukiasyan <tigran.sukias...@taurotech.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8486
-- gerrit commit d1003cea6ed37402fc777320904fe23f26565895 Author: tigransukiasyan <tigran.sukias...@taurotech.com> Date: Thu Sep 12 05:43:50 2024 -0700 target: add new command for nrf91 add command nrf91_update_mfw to update nRF91 modem firmware the usage of the command is as follows: nrf91_update_mfw <loader_file> <segment_files> ... the target needs to be reset-halted before this command Change-Id: I6814682250736cfbcea94eac35bc197561b8721e Signed-off-by: tigransukiasyan <tigran.sukias...@taurotech.com> diff --git a/src/target/target.c b/src/target/target.c index 9d1d2f5507..db424952dd 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -49,6 +49,8 @@ #include "smp.h" #include "semihosting_common.h" +#include "src/target/image.h" + /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -4661,6 +4663,181 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc, return e; } +void setup_device_for_dfu(struct target *target) +{ + target_write_u32(target, 0x50039504, 0x01); + target_write_u32(target, 0x00FF801C, 0x0E); + target_write_u32(target, 0x00FF8020, 0x20); + target_write_u32(target, 0x50039504, 0x00); + + // configure IPC to be in non-secure mode + target_write_u32(target, 0x500038A8, 0x00000002); + + // configure IPC HW for DFU + target_write_u32(target, 0x4002A514, 0x00000002); + target_write_u32(target, 0x4002A51C, 0x00000008); + target_write_u32(target, 0x4002A610, 0x21000000); + target_write_u32(target, 0x4002A614, 0x00000000); + target_write_u32(target, 0x4002A590, 0x00000001); + target_write_u32(target, 0x4002A598, 0x00000004); + target_write_u32(target, 0x4002A5A0, 0x00000010); + + // configure RAM as non-secure + for (int i = 0; i < 32; ++i) + target_write_u32(target, 0x50003700 + i * 4, 0x00000007); + + // allocate memory in RAM + target_write_u32(target, 0x20000000, 0x80010000); + target_write_u32(target, 0x20000004, 0x2100000C); + target_write_u32(target, 0x20000008, 0x0003FC00); + + // reset the modem + target_write_u32(target, 0x50005610, 0); + target_write_u32(target, 0x50005614, 1); + target_write_u32(target, 0x50005610, 1); + target_write_u32(target, 0x50005614, 0); + target_write_u32(target, 0x50005610, 0); + + // wait until the modem is reset + sleep(2); + + // clear event registers before using + target_write_u32(target, 0x4002a100, 0); + target_write_u32(target, 0x4002a108, 0); + target_write_u32(target, 0x4002a110, 0); +} + +void wait_and_ack_events(struct target *target) +{ + bool fault = false; + uint32_t value = 0; + target_addr_t fault_event = 0x4002A100; + target_addr_t command_event = 0x4002A108; + target_addr_t data_event = 0x4002A110; + while (true) { + target_read_u32(target, fault_event, &value); + if (value != 0) { + fault = true; + break; + } + target_read_u32(target, command_event, &value); + if (value != 0) + break; + target_read_u32(target, data_event, &value); + if (value != 0) + break; + } + target_write_u32(target, fault_event, 0); + target_write_u32(target, command_event, 0); + target_write_u32(target, data_event, 0); + + uint32_t response = 0; + target_read_u32(target, 0x2000000C, &response); + if ((response & 0xff000000) == 0xa5000000) + LOG_DEBUG("ack"); + if ((response & 0xff000000) == 0x5a000000) + LOG_ERROR("nack\n"); + if (fault) + LOG_ERROR("fault\n"); +} + +int write_section_to_ram(Jim_Interp *interp, struct target *target, struct image *image, + size_t section_number, bool is_loader) +{ + int retval = ERROR_OK; + uint32_t count = image->sections[section_number].size; + target_addr_t address = image->sections[section_number].base_address; + target_addr_t chunk_write_address = 0x20000018; + const size_t buffersize = 0x10000; + uint8_t *buffer_addr = image->sections[section_number].private; + + while (count > 0) { + const unsigned int max_chunk_len = buffersize; + const size_t chunk_len = MIN(count, max_chunk_len); + count -= chunk_len; + + if (is_loader) + target_write_memory(target, address, 1, chunk_len, buffer_addr); + else + target_write_memory(target, chunk_write_address, 1, chunk_len, buffer_addr); + + if (retval != ERROR_OK) { + LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + address, 8, chunk_len); + Jim_SetResultString(interp, "write_memory: failed to write memory", -1); + retval = JIM_ERR; + break; + } + if (!is_loader) { + target_write_u32(target, 0x20000010, address); + target_write_u32(target, 0x20000014, chunk_len); + target_write_u32(target, 0x2000000C, 0x3); + target_write_u32(target, 0x4002a004, 1); + wait_and_ack_events(target); + } + + address += chunk_len; + buffer_addr += chunk_len; + } + return retval; +} + +static int target_jim_nrf91_update_modem_firmware(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + /* + * argv[1] = dfu loader file (.ihex) + * argv[2:] = segment files (.hex) + */ + + int e = 0; + + if (argc < 3) { + Jim_WrongNumArgs(interp, 1, argv, "dfu_loader segments..."); + return JIM_ERR; + } + + struct command_context *cmd_ctx = current_command_context(interp); + assert(cmd_ctx); + struct target *target = get_current_target(cmd_ctx); + setup_device_for_dfu(target); + + /* Arg1: dfu loader file. */ + const char *dfu_loader_path = Jim_String(argv[1]); + LOG_INFO("DFU loader: %s", dfu_loader_path); + struct image image; + image.base_address_set = false; + image.base_address = 0x0; + image.start_address_set = false; + + // Program the loader to the RAM + e = image_open(&image, dfu_loader_path, NULL); + for (size_t i = 0; i < image.num_sections; ++i) + write_section_to_ram(interp, target, &image, i, true); + + target_write_u32(target, 0x4002a004, 1); + wait_and_ack_events(target); + image_close(&image); + + /* The rest of the args: segment files. */ + int first_segment_arg_index = 2; + for (int i = first_segment_arg_index; i < argc; ++i) { + image.base_address_set = false; + image.base_address = 0x0; + image.start_address_set = false; + const char *segment_path = Jim_String(argv[i]); + + // Write and commit all the sections of each segment file + e = image_open(&image, segment_path, NULL); + for (size_t j = 0; j < image.num_sections; ++j) { + LOG_INFO("Writing section %d of segment %d", (unsigned int)(j + 1), (unsigned int)(i - 1)); + write_section_to_ram(interp, target, &image, j, false); + } + image_close(&image); + } + return e; +} + /* FIX? should we propagate errors here rather than printing them * and continuing? */ @@ -5609,6 +5786,13 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, + { + .name = "nrf91_update_mfw", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_nrf91_update_modem_firmware, + .help = "Updates the modem firmware", + .usage = "nrf91_update_mfw loader_file segments..." + }, { .name = "eventlist", .handler = handle_target_event_list, @@ -6744,6 +6928,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, + { + .name = "nrf91_update_mfw", + .mode = COMMAND_EXEC, + .jim_handler = target_jim_nrf91_update_modem_firmware, + .help = "Updates the modem firmware", + .usage = "nrf91_update_mfw loader_file segments..." + }, { .name = "debug_reason", .mode = COMMAND_EXEC, --