From 5e61d59c9065bb4347c8e85767c39ea7263010f2 Mon Sep 17 00:00:00 2001 From: Sylvain Chouleur Date: Mon, 12 Oct 2020 17:24:05 +0200 Subject: [PATCH 001/113] cortex_m: support control.FPCA Bit 2 of control register is used if the processor includes the FP extension Change-Id: Ie21bc9de8cae5bad9d841e1908eff3aa0bb29d4b Signed-off-by: Sylvain Chouleur Reviewed-on: http://openocd.zylin.com/5853 Reviewed-by: Sylvain Chouleur Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Tomas Vanek --- src/target/armv7m.c | 2 +- src/target/cortex_m.c | 6 +++--- src/target/hla_target.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index ea6ee6117..5e0694d8a 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -111,7 +111,7 @@ static const struct { { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_CONTROL, "control", 2, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, + { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 55664a79a..abc377f0d 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -541,7 +541,7 @@ static int cortex_m_debug_entry(struct target *target) arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache - ->reg_list[ARMV7M_CONTROL].value, 0, 2); + ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 @@ -1678,7 +1678,7 @@ static int cortex_m_load_core_reg_u32(struct target *target, break; case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *)value, 24, 2); + *value = buf_get_u32((uint8_t *)value, 24, 3); break; } @@ -1764,7 +1764,7 @@ static int cortex_m_store_core_reg_u32(struct target *target, break; case ARMV7M_CONTROL: - buf_set_u32((uint8_t *)®, 24, 2, value); + buf_set_u32((uint8_t *)®, 24, 3, value); break; } diff --git a/src/target/hla_target.c b/src/target/hla_target.c index f0dc57276..c02cbb643 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -123,7 +123,7 @@ static int adapter_load_core_reg_u32(struct target *target, break; case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *) value, 24, 2); + *value = buf_get_u32((uint8_t *) value, 24, 3); break; } @@ -215,7 +215,7 @@ static int adapter_store_core_reg_u32(struct target *target, break; case ARMV7M_CONTROL: - buf_set_u32((uint8_t *) ®, 24, 2, value); + buf_set_u32((uint8_t *) ®, 24, 3, value); break; } @@ -433,7 +433,7 @@ static int adapter_debug_entry(struct target *target) arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache - ->reg_list[ARMV7M_CONTROL].value, 0, 2); + ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ arm->core_mode = control & 1 From 6436f1919cc77fb1dacb00b56867991f5e0e4058 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 1 Oct 2020 12:36:00 +0200 Subject: [PATCH 002/113] tcl/target/nrf52: fix nrf52_recover nrf52_recover was merged in pre "Handle Tcl return values consistently" state - remove ocd_ prefixes. Erase and unlock sequence was changed to comply Nordic semiconductor recommendation: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fnwp_027%2FWP%2Fnwp_027%2FnWP_027_erasing.html Change-Id: Ic54236c27cf25ad8091e9e572ba1ef846f0d47c2 Signed-off-by: Tomas Vanek Reported-by: Pieter De Gendt Reviewed-on: http://openocd.zylin.com/5845 Tested-by: jenkins Reviewed-by: Pieter De Gendt --- tcl/target/nrf52.cfg | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index 88f2c6912..d0c52fdab 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -53,7 +53,7 @@ flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME # Test if MEM-AP is locked by UICR APPROTECT proc nrf52_check_ap_lock {} { set dap [[target current] cget -dap] - set err [catch {set APPROTECTSTATUS [ocd_$dap apreg 1 0xc]}] + set err [catch {set APPROTECTSTATUS [$dap apreg 1 0xc]}] if {$err == 0 && $APPROTECTSTATUS != 1} { echo "****** WARNING ******" echo "nRF52 device has AP lock engaged (see UICR APPROTECT register)." @@ -71,7 +71,7 @@ proc nrf52_recover {} { set target [target current] set dap [$target cget -dap] - set IDR [ocd_$dap apreg 1 0xfc] + set IDR [$dap apreg 1 0xfc] if {$IDR != 0x02880000} { echo "Error: Cannot access nRF52 CTRL-AP!" return @@ -79,37 +79,38 @@ proc nrf52_recover {} { poll off - # Assert reset - $dap apreg 1 0 1 - - # Reset ERASEALLSTATUS event - $dap apreg 1 8 0 - - # Trigger ERASEALL task + # Reset and trigger ERASEALL task $dap apreg 1 4 0 $dap apreg 1 4 1 for {set i 0} {1} {incr i} { - set ERASEALLSTATUS [ocd_$dap apreg 1 8] - if {$ERASEALLSTATUS == 1} { + set ERASEALLSTATUS [$dap apreg 1 8] + if {$ERASEALLSTATUS == 0} { echo "$target device has been successfully erased and unlocked." break } - if {$i >= 5} { + if {$i == 0} { + echo "Waiting for chip erase..." + } + if {$i >= 150} { echo "Error: $target recovery failed." break } sleep 100 } + # Assert reset + $dap apreg 1 0 1 + # Deassert reset $dap apreg 1 0 0 - if {$ERASEALLSTATUS == 1} { - sleep 100 - $target arp_examine - poll on - } + # Reset ERASEALL task + $dap apreg 1 4 0 + + sleep 100 + $target arp_examine + poll on } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" From 5829646343d78a6779794f67cde2f7c779969afc Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Thu, 15 Oct 2020 17:05:48 +0100 Subject: [PATCH 003/113] flash/stm32l4: add support of STM32G4 category 4 devices (G491/G4A1) STM32G4 cat.4 devices are up to 512 KB of flash memory (single bank) organized into pages of 2KB each. Reference: RM0440 rev.4 Change-Id: I0f510e2806c8f824fff8083e2d4f90d68f01046b Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5793 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/stm32l4x.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 379f1b4b3..9bdc2dbca 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -94,7 +94,7 @@ /* * STM32G4xxx series for reference. * - * RM0440 (STM32G43x/44x/47x/48x) + * RM0440 (STM32G43x/44x/47x/48x/49x/4Ax) * http://www.st.com/resource/en/reference_manual/dm00355726.pdf * * Cat. 2 devices have single bank only, page size is 2kByte. @@ -104,6 +104,8 @@ * * Bank mode is controlled by bit 22 (DBANK) in option bytes register. * Both banks are treated as a single OpenOCD bank. + * + * Cat. 4 devices have single bank only, page size is 2kByte. */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ @@ -184,6 +186,10 @@ static const struct stm32l4_rev stm32_471_revs[] = { { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32_479_revs[] = { + { 0x1000, "A" }, +}; + static const struct stm32l4_rev stm32_495_revs[] = { { 0x2001, "2.1" }, }; @@ -307,6 +313,16 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .flash_regs_base = 0x40022000, .fsize_addr = 0x1FFF75E0, }, + { + .id = 0x479, + .revs = stm32_479_revs, + .num_revs = ARRAY_SIZE(stm32_479_revs), + .device_str = "STM32G49/G4Axx", + .max_flash_size_kb = 512, + .has_dual_bank = false, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x1FFF75E0, + }, { .id = 0x495, .revs = stm32_495_revs, @@ -952,6 +968,7 @@ static int stm32l4_probe(struct flash_bank *bank) case 0x464: /* STM32L41/L42xx */ case 0x466: /* STM32G03/G04xx */ case 0x468: /* STM32G43/G44xx */ + case 0x479: /* STM32G49/G4Axx */ case 0x497: /* STM32WLEx */ /* single bank flash */ page_size_kb = 2; From e8f483139d15d824cfae48d950ec761184d89510 Mon Sep 17 00:00:00 2001 From: John Pham Date: Mon, 2 Feb 2015 05:23:32 -0500 Subject: [PATCH 004/113] Enable hla_serial for TI ICDI devices Used jtag_libusb_open from libusb_helper.h instead of libusb_open_device_with_vid_pid to get device handle, as well as managing context, i.e. similar to stlink_usb. Direct calls to libusb1 are left in for the moment. (When this Gerrit revision was originally created, the jtag_libusb_ wrappers did not return error conditions.) Tested w/ a TM4C123GXL board Change-Id: I71e9a366356c125444d4813e58ddd9b6c6498bf0 Signed-off-by: John Pham Signed-off-by: Matthew Trescott Reviewed-on: http://openocd.zylin.com/2527 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/ti_icdi_usb.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index d276e588f..920be7783 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -31,7 +31,7 @@ #include -#include +#include "libusb_helper.h" #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 @@ -44,8 +44,7 @@ #define PACKET_END "#" struct icdi_usb_handle_s { - libusb_context *usb_ctx; - libusb_device_handle *usb_dev; + struct libusb_device_handle *usb_dev; char *read_buffer; char *write_buffer; @@ -657,10 +656,7 @@ static int icdi_usb_close(void *handle) return ERROR_OK; if (h->usb_dev) - libusb_close(h->usb_dev); - - if (h->usb_ctx) - libusb_exit(h->usb_ctx); + jtag_libusb_close(h->usb_dev); free(h->read_buffer); free(h->write_buffer); @@ -670,6 +666,7 @@ static int icdi_usb_close(void *handle) static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) { + /* TODO: Convert remaining libusb_ calls to jtag_libusb_ */ int retval; struct icdi_usb_handle_s *h; @@ -682,19 +679,14 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) return ERROR_FAIL; } - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, - param->vid[0], param->pid[0]); + for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i) + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport, + param->vid[i], param->pid[i], param->serial ? param->serial : ""); - /* TODO: convert libusb_ calls to jtag_libusb_ */ - if (param->vid[1]) - LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!"); + /* TI (Stellaris) ICDI provides its serial number in the USB descriptor; + no need to provide a callback here. */ + jtag_libusb_open(param->vid, param->pid, param->serial, &h->usb_dev, NULL); - if (libusb_init(&h->usb_ctx) != 0) { - LOG_ERROR("libusb init failed"); - goto error_open; - } - - h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; From ebb88156ce1a848aa34610872c6a3c0845a811fc Mon Sep 17 00:00:00 2001 From: John Pham Date: Mon, 2 Feb 2015 21:22:38 -0500 Subject: [PATCH 005/113] Added comment to ti-icdi.cfg Added comment to ti-icdi.cfg specifying how to get serial and an example of specifying hla_serial for ti-icdi devices. This has been implemented in revision 2121a8f92969804611412b705af8114697a647dc Change-Id: I648458a4dea176beae6a3f1a4e5641d0206077eb Signed-off-by: John Pham Reviewed-on: http://openocd.zylin.com/2528 Tested-by: jenkins Reviewed-by: Matthew Trescott Reviewed-by: Antonio Borneo --- tcl/interface/ti-icdi.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index 9b46b437c..9decae9ab 100644 --- a/tcl/interface/ti-icdi.cfg +++ b/tcl/interface/ti-icdi.cfg @@ -11,3 +11,8 @@ adapter driver hla hla_layout ti-icdi hla_vid_pid 0x1cbe 0x00fd +# Optionally specify the serial number of TI-ICDI devices, for when using +# multiple devices. Serial numbers can be obtained using lsusb -v +# Ex. +#hla_serial "0F003065" + From 0d3a67b23f7848584a36712741252a73b03ae3a5 Mon Sep 17 00:00:00 2001 From: Evgeniy Didin Date: Fri, 31 Jul 2020 00:02:38 +0300 Subject: [PATCH 006/113] target/arc: introduce watchpoints support With help of actionpoint mechanism now it is possible to introduce watchpoints support for ARC. Change-Id: I5887335d0ba38c15c377bc1d24a1ef36e138cf65 Signed-off-by: Evgeniy Didin Reviewed-on: http://openocd.zylin.com/5867 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arc.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 3 deletions(-) diff --git a/src/target/arc.c b/src/target/arc.c index e1b576436..cec6441a5 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -48,6 +48,8 @@ */ +static int arc_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint); void arc_reg_data_type_add(struct target *target, struct arc_reg_data_type *data_type) @@ -1696,6 +1698,7 @@ void arc_reset_actionpoints(struct target *target) struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; struct breakpoint *next_b; + struct watchpoint *next_w; while (target->breakpoints) { next_b = target->breakpoints->next; @@ -1704,6 +1707,12 @@ void arc_reset_actionpoints(struct target *target) free(target->breakpoints); target->breakpoints = next_b; } + while (target->watchpoints) { + next_w = target->watchpoints->next; + arc_remove_watchpoint(target, target->watchpoints); + free(target->watchpoints); + target->watchpoints = next_w; + } for (unsigned int i = 0; i < arc->actionpoints_num; i++) { if ((ap_list[i].used) && (ap_list[i].reg_address)) arc_remove_auxreg_actionpoint(target, ap_list[i].reg_address); @@ -1800,6 +1809,159 @@ int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr) return retval; } + +static int arc_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + unsigned int wp_num; + struct arc_common *arc = target_to_arc(target); + struct arc_actionpoint *ap_list = arc->actionpoints_list; + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + for (wp_num = 0; wp_num < arc->actionpoints_num; wp_num++) { + if (!ap_list[wp_num].used) + break; + } + + if (wp_num >= arc->actionpoints_num) { + LOG_ERROR("No free actionpoints, maximum amount is %u", + arc->actionpoints_num); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 4) { + LOG_ERROR("Only watchpoints of length 4 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + int enable = AP_AC_TT_DISABLE; + switch (watchpoint->rw) { + case WPT_READ: + enable = AP_AC_TT_READ; + break; + case WPT_WRITE: + enable = AP_AC_TT_WRITE; + break; + case WPT_ACCESS: + enable = AP_AC_TT_READWRITE; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + return ERROR_FAIL; + } + + int retval = arc_configure_actionpoint(target, wp_num, + watchpoint->address, enable, AP_AC_AT_MEMORY_ADDR); + + if (retval == ERROR_OK) { + watchpoint->set = wp_num + 1; + ap_list[wp_num].used = 1; + ap_list[wp_num].bp_value = watchpoint->address; + ap_list[wp_num].type = ARC_AP_WATCHPOINT; + + LOG_DEBUG("wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32, + watchpoint->unique_id, wp_num, ap_list[wp_num].bp_value); + } + + return retval; +} + +static int arc_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct arc_common *arc = target_to_arc(target); + struct arc_actionpoint *ap_list = arc->actionpoints_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + unsigned int wp_num = watchpoint->set - 1; + if ((watchpoint->set == 0) || (wp_num >= arc->actionpoints_num)) { + LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, + wp_num, watchpoint->unique_id); + return ERROR_OK; + } + + int retval = arc_configure_actionpoint(target, wp_num, + watchpoint->address, AP_AC_TT_DISABLE, AP_AC_AT_MEMORY_ADDR); + + if (retval == ERROR_OK) { + watchpoint->set = 0; + ap_list[wp_num].used = 0; + ap_list[wp_num].bp_value = 0; + + LOG_DEBUG("wpid: %" PRIu32 " - releasing actionpoint ID: %u", + watchpoint->unique_id, wp_num); + } + + return retval; +} + +static int arc_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + CHECK_RETVAL(arc_set_watchpoint(target, watchpoint)); + + return ERROR_OK; +} + +static int arc_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + CHECK_RETVAL(arc_unset_watchpoint(target, watchpoint)); + + return ERROR_OK; +} + +static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) +{ + assert(target); + assert(hit_watchpoint); + + struct arc_actionpoint *actionpoint = NULL; + CHECK_RETVAL(get_current_actionpoint(target, &actionpoint)); + + if (actionpoint != NULL) { + if (!actionpoint->used) + LOG_WARNING("Target halted by unused actionpoint."); + + /* If this check fails - that is some sort of an error in OpenOCD. */ + if (actionpoint->type != ARC_AP_WATCHPOINT) + LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint."); + + for (struct watchpoint *watchpoint = target->watchpoints; + watchpoint != NULL; + watchpoint = watchpoint->next) { + if (actionpoint->bp_value == watchpoint->address) { + *hit_watchpoint = watchpoint; + LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %i", + watchpoint->unique_id, watchpoint->set - 1); + return ERROR_OK; + } + } + } + + return ERROR_FAIL; +} + /* Helper function which switches core to single_step mode by * doing aux r/w operations. */ int arc_config_step(struct target *target, int enable_step) @@ -2106,9 +2268,9 @@ struct target_type arcv2_target = { .add_context_breakpoint = NULL, .add_hybrid_breakpoint = NULL, .remove_breakpoint = arc_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, - .hit_watchpoint = NULL, + .add_watchpoint = arc_add_watchpoint, + .remove_watchpoint = arc_remove_watchpoint, + .hit_watchpoint = arc_hit_watchpoint, .run_algorithm = NULL, .start_algorithm = NULL, From 9e2a0effb2b7b933db00543f1e6879541707a2f3 Mon Sep 17 00:00:00 2001 From: Brian Brooks Date: Sun, 18 Oct 2020 08:37:09 -0500 Subject: [PATCH 007/113] server/telnet: Handle Ctrl+K Handle Ctrl+K shortcut which clears the line from the cursor position to the end of line. Change-Id: I2ecff5284473cef7c11cf9cb7e1c0c97d55f6c1c Signed-off-by: Brian Brooks Reviewed-on: http://openocd.zylin.com/5868 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Marc Schink --- src/server/telnet_server.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 0243c6328..407ab68ae 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -538,7 +538,17 @@ static int telnet_input(struct connection *connection) telnet_move_cursor(connection, 0); else if (*buf_p == CTRL('E')) telnet_move_cursor(connection, t_con->line_size); - else + else if (*buf_p == CTRL('K')) { /* kill line to end */ + if (t_con->line_cursor < t_con->line_size) { + /* overwrite with space, until end of line, move back */ + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, " ", 1); + for (size_t i = t_con->line_cursor; i < t_con->line_size; i++) + telnet_write(connection, "\b", 1); + t_con->line[t_con->line_cursor] = '\0'; + t_con->line_size = t_con->line_cursor; + } + } else LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p); } } From 895d4a599585543155dd4a7559489cf126e02c4c Mon Sep 17 00:00:00 2001 From: Diego Herranz Date: Sun, 10 May 2020 18:57:46 +0100 Subject: [PATCH 008/113] tcl/interface/ftdi: Add Steppenprobe open hardware interface https://github.com/diegoherranz/steppenprobe Change-Id: Ief2c3f4a8707fa628650697d93893b2355015898 Signed-off-by: Diego Herranz Reviewed-on: http://openocd.zylin.com/5653 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/interface/ftdi/steppenprobe.cfg | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100755 tcl/interface/ftdi/steppenprobe.cfg diff --git a/tcl/interface/ftdi/steppenprobe.cfg b/tcl/interface/ftdi/steppenprobe.cfg new file mode 100755 index 000000000..7b5b9a034 --- /dev/null +++ b/tcl/interface/ftdi/steppenprobe.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Steppenprobe +# https://github.com/diegoherranz/steppenprobe +# + +adapter driver ftdi +ftdi_vid_pid 0x0403 0x6010 + +# Initial Layout +ftdi_layout_init 0x0058 0x99fb +# Signal Data Direction Notes +# TCK 0 1 (out) +# TDI 0 1 (out) +# TDO 0 0 (in) +# TMS 1 1 (out) JTAG IEEE std recommendation +# LED 1 1 (out) LED off +# SWD_EN 0 1 (out) OpenOCD sets this high for SWD +# SWDIO_OE 1 1 (out) Ext. buffer tristated +# SRST 0 1 (out) Translates to nSRST=Z + +# Unused 0 1 (out) +# GPIO_A 0 0 (in) +# GPIO_B 0 0 (in) +# Unused 0 1 (out) +# Unused 0 1 (out) +# GPIO_C 0 0 (in) +# GPIO_D 0 0 (in) +# Unused 0 1 (out) + +# Signals definition +ftdi_layout_signal LED -ndata 0x0010 +ftdi_layout_signal SWD_EN -data 0x0020 +ftdi_layout_signal SWDIO_OE -ndata 0x0040 +ftdi_layout_signal nSRST -oe 0x0080 + +ftdi_layout_signal GPIO_A -data 0x0200 -oe 0x0200 -input 0x0200 +ftdi_layout_signal GPIO_B -data 0x0400 -oe 0x0400 -input 0x0400 +ftdi_layout_signal GPIO_C -data 0x2000 -oe 0x2000 -input 0x2000 +ftdi_layout_signal GPIO_D -data 0x4000 -oe 0x4000 -input 0x4000 From c97ccc8971b44fbce28438cb926990a6e5a63450 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 12 Apr 2020 10:15:00 +0200 Subject: [PATCH 009/113] flash/nor/nrf5: fix protection setting on nRF51 Protection setting has not ever worked. UICR CLENR0 register cannot be simply written but has to programmed because it resides in UICR page of the flash. Enable flash programming before writing CLENR0 and set back to r/o afterwards. Inform the user that reset might be required. Change-Id: Ib0f96c74ba3583ac33f4394ddb57d8c8895adf53 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5586 Tested-by: jenkins --- src/flash/nor/nrf5.c | 76 +++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 0ceb8d754..657af9b6a 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -512,25 +512,13 @@ static int nrf5_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, +static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, unsigned int last) { int res; uint32_t clenr0, ppfc; - struct nrf5_info *chip; - - /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF5_UICR_BASE) - return ERROR_FAIL; - - res = nrf5_get_probed_chip_if_halted(bank, &chip); - if (res != ERROR_OK) - return res; - - if (!(chip->features & NRF5_FEATURE_SERIES_51)) { - LOG_ERROR("Flash protection setting of this nRF device is not supported"); - return ERROR_FLASH_OPER_UNSUPPORTED; - } + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; if (first != 0) { LOG_ERROR("Code region 0 must start at the beginning of the bank"); @@ -552,25 +540,61 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, res = target_read_u32(chip->target, NRF51_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[UICR]"); + LOG_ERROR("Couldn't read code region 0 size from UICR"); return res; } - if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, - clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't write code region 0 size[UICR]"); - return res; - } - - } else { + if (!set || clenr0 != 0xFFFFFFFF) { LOG_ERROR("You need to perform chip erase before changing the protection settings"); + return ERROR_FAIL; } + res = nrf5_nvmc_write_enable(chip); + if (res != ERROR_OK) + goto error; + + clenr0 = bank->sectors[last].offset + bank->sectors[last].size; + res = target_write_u32(chip->target, NRF51_UICR_CLENR0, clenr0); + + int res2 = nrf5_wait_for_nvmc(chip); + + if (res == ERROR_OK) + res = res2; + + if (res == ERROR_OK) + LOG_INFO("A reset or power cycle is required for the new protection settings to take effect."); + else + LOG_ERROR("Couldn't write code region 0 size to UICR"); + +error: + nrf5_nvmc_read_only(chip); + nrf5_protect_check(bank); - return ERROR_OK; + return res; +} + +static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) +{ + int res; + struct nrf5_info *chip; + + /* UICR cannot be write protected so just bail out early */ + if (bank->base == NRF5_UICR_BASE) { + LOG_ERROR("UICR page does not support protection"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + res = nrf5_get_probed_chip_if_halted(bank, &chip); + if (res != ERROR_OK) + return res; + + if (chip->features & NRF5_FEATURE_SERIES_51) + return nrf5_protect_clenr0(bank, set, first, last); + + LOG_ERROR("Flash protection setting is not supported on this nRF5 device"); + return ERROR_FLASH_OPER_UNSUPPORTED; } static bool nrf5_info_variant_to_str(uint32_t variant, char *bf) From 491636c8b8328a54bef41b68771c2965dd468e05 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 16 Mar 2020 15:49:54 +0100 Subject: [PATCH 010/113] flash/nor/nrf5: check protection before flash erase/write on nRF51 nRF51 devices have a clumsy flash protection based on UICR CLENR0. A code running in RAM can write to a protected flash region without any hint the protection gets violated. NVMC flash page erase obeys protection setting but fails absolutely silently. Before this change the first problem was not addressed in the code. To justify the second one, protection was loaded during probe, after protection setting and after a mass erase. Move protection updates to the beginning of erase/write operation and limit them to nRF51 series only. Check for protected sectors before write. The change also fixes the problem of 'nrf5 mass_erase' on nRF52833/840 devices. They use ACL flash protection, which is not supported in nrf5 driver. mass_erase then looked like it failed. Change-Id: Ie58cda68eb104d410b02777c3df5b343408e2666 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5522 Tested-by: jenkins --- src/flash/nor/nrf5.c | 150 ++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 50 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 657af9b6a..f56f32e32 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -440,6 +440,38 @@ error: return ERROR_FAIL; } +static int nrf5_protect_check_clenr0(struct flash_bank *bank) +{ + int res; + uint32_t clenr0; + struct nrf5_bank *nbank = bank->driver_priv; + struct nrf5_info *chip = nbank->chip; + + assert(chip != NULL); + + res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + &clenr0); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code region 0 size[FICR]"); + return res; + } + + if (clenr0 == 0xFFFFFFFF) { + res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + &clenr0); + if (res != ERROR_OK) { + LOG_ERROR("Couldn't read code region 0 size[UICR]"); + return res; + } + } + + for (unsigned int i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_protected = + clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; + + return ERROR_OK; +} + static int nrf5_protect_check_bprot(struct flash_bank *bank) { struct nrf5_bank *nbank = bank->driver_priv; @@ -469,9 +501,6 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank) static int nrf5_protect_check(struct flash_bank *bank) { - int res; - uint32_t clenr0; - /* UICR cannot be write protected so just return early */ if (bank->base == NRF5_UICR_BASE) return ERROR_OK; @@ -484,32 +513,11 @@ static int nrf5_protect_check(struct flash_bank *bank) if (chip->features & NRF5_FEATURE_BPROT) return nrf5_protect_check_bprot(bank); - if (!(chip->features & NRF5_FEATURE_SERIES_51)) { - LOG_WARNING("Flash protection of this nRF device is not supported"); - return ERROR_FLASH_OPER_UNSUPPORTED; - } + if (chip->features & NRF5_FEATURE_SERIES_51) + return nrf5_protect_check_clenr0(bank); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, - &clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[FICR]"); - return res; - } - - if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, - &clenr0); - if (res != ERROR_OK) { - LOG_ERROR("Couldn't read code region 0 size[UICR]"); - return res; - } - } - - for (unsigned int i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_protected = - clenr0 != 0xFFFFFFFF && bank->sectors[i].offset < clenr0; - - return ERROR_OK; + LOG_WARNING("Flash protection of this nRF device is not supported"); + return ERROR_FLASH_OPER_UNSUPPORTED; } static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first, @@ -569,8 +577,6 @@ static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int fi error: nrf5_nvmc_read_only(chip); - nrf5_protect_check(bank); - return res; } @@ -845,8 +851,6 @@ static int nrf5_probe(struct flash_bank *bank) if (!bank->sectors) return ERROR_FAIL; - nrf5_protect_check(bank); - chip->bank[0].probed = true; } else { @@ -1036,6 +1040,34 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, assert(offset % 4 == 0); assert(count % 4 == 0); + /* UICR CLENR0 based protection used on nRF51 is somewhat clumsy: + * RM reads: Code running from code region 1 will not be able to write + * to code region 0. + * Unfortunately the flash loader running from RAM can write to both + * code regions whithout any hint the protection is violated. + * + * Update protection state and check if any flash sector to be written + * is protected. */ + if (chip->features & NRF5_FEATURE_SERIES_51) { + + res = nrf5_protect_check_clenr0(bank); + if (res != ERROR_OK) + return res; + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + struct flash_sector *bs = &bank->sectors[sector]; + + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bs->offset + bs->size)) + && ((offset + count - 1) >= bs->offset) + && bs->is_protected == 1) { + LOG_ERROR("Write refused, sector %d is protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + } + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; @@ -1062,11 +1094,36 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first, if (res != ERROR_OK) return res; - /* For each sector to be erased */ - for (unsigned int s = first; s <= last && res == ERROR_OK; s++) - res = nrf5_erase_page(bank, chip, &bank->sectors[s]); + /* UICR CLENR0 based protection used on nRF51 prevents erase + * absolutely silently. NVMC has no flag to indicate the protection + * was violated. + * + * Update protection state and check if any flash sector to be erased + * is protected. */ + if (chip->features & NRF5_FEATURE_SERIES_51) { - return res; + res = nrf5_protect_check_clenr0(bank); + if (res != ERROR_OK) + return res; + } + + /* For each sector to be erased */ + for (unsigned int s = first; s <= last && res == ERROR_OK; s++) { + + if (chip->features & NRF5_FEATURE_SERIES_51 + && bank->sectors[s].is_protected == 1) { + LOG_ERROR("Flash sector %d is protected", s); + return ERROR_FLASH_PROTECTED; + } + + res = nrf5_erase_page(bank, chip, &bank->sectors[s]); + if (res != ERROR_OK) { + LOG_ERROR("Error erasing sector %d", s); + return res; + } + } + + return ERROR_OK; } static void nrf5_free_driver_priv(struct flash_bank *bank) @@ -1183,23 +1240,16 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command) } res = nrf5_erase_all(chip); - if (res != ERROR_OK) { + if (res == ERROR_OK) { + LOG_INFO("Mass erase completed."); + if (chip->features & NRF5_FEATURE_SERIES_51) + LOG_INFO("A reset or power cycle is required if the flash was protected before."); + + } else { LOG_ERROR("Failed to erase the chip"); - nrf5_protect_check(bank); - return res; } - res = nrf5_protect_check(bank); - if (res != ERROR_OK) { - LOG_ERROR("Failed to check chip's write protection"); - return res; - } - - res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank); - if (res != ERROR_OK) - return res; - - return ERROR_OK; + return res; } COMMAND_HANDLER(nrf5_handle_info_command) From a5bf98f846eba410cdfc678b5b223052a68439c1 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 13 Apr 2020 14:49:46 +0200 Subject: [PATCH 011/113] flash/nor/nrf5: improve handling of nRF52 flash errors nRF52 devices indicate a flash error by emitting hard fault exception (unlike nRF51 series). Change error message when NVMC READY read fails. A hard fault from flash erase/write operation is detected here. Check exit point of the flash write algo to ensure a failed write is recognised. Change-Id: I637eda268a6bf45f7f41bcb9dcd82db8f5cb41b4 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5587 Tested-by: jenkins --- src/flash/nor/nrf5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index f56f32e32..02c144810 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -328,7 +328,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip) do { res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { - LOG_ERROR("Couldn't read NVMC_READY register"); + LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)"); return res; } @@ -1012,7 +1012,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u 0, NULL, ARRAY_SIZE(reg_params), reg_params, source->address, source->size, - write_algorithm->address, 0, + write_algorithm->address, write_algorithm->address + sizeof(nrf5_flash_write_code) - 2, &armv7m_info); target_free_working_area(target, source); From c1f4d9e6e8f9cdab122db36299e039a73151ffe4 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 13 Apr 2020 20:19:41 +0200 Subject: [PATCH 012/113] flash/nor/nrf5: unify size of HWID HWID is a part of 32 bit CONFIGID register. hwid member of struct nrf5_info was typed uint32_t to enable direct CONFIGID read and masked afterwards. Change to uint16_t to unify with hwid in struct nrf5_device_spec and RM description. Change-Id: Ib720d3ce23c301aee41d074ea78a6f00a23aed68 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5589 Tested-by: jenkins --- src/flash/nor/nrf5.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 02c144810..1784bcde5 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -158,7 +158,7 @@ struct nrf5_info { bool ficr_info_valid; struct nrf52_ficr_info ficr_info; const struct nrf5_device_spec *spec; - uint32_t hwid; + uint16_t hwid; enum nrf5_features features; unsigned int flash_size_kb; unsigned int ram_size_kb; @@ -648,7 +648,7 @@ static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) variant, &variant[2]); } else { - res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%08" PRIx32 ")", + res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid); } if (res <= 0) @@ -765,14 +765,15 @@ static int nrf5_probe(struct flash_bank *bank) struct nrf5_info *chip = nbank->chip; struct target *target = chip->target; - res = target_read_u32(target, NRF5_FICR_CONFIGID, &chip->hwid); + uint32_t configid; + res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; } - chip->hwid &= 0xFFFF; /* HWID is stored in the lower two - * bytes of the CONFIGID register */ + /* HWID is stored in the lower two bytes of the CONFIGID register */ + chip->hwid = configid & 0xFFFF; /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */ chip->features = NRF5_FEATURE_SERIES_51; From a7502ee8b9d3fbb3ceb1fc151c3bc6fbfce3dbaa Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Fri, 14 Jun 2019 15:12:28 -0700 Subject: [PATCH 013/113] target: allow profiling from running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a handful of implementations of profiling. There is the default implementation, which repeatedly halts and resumes the target, sampling PC each time. There is the Cortex-M implementation, which uses PCSR if available, otherwise falling back to halting and resuming and sampling PC. There is the OR1K implementation, which reads NPC repeatedly. Finally, there is the NDS32 implementation which uses some kind of AICE commands with which I am unfamiliar. None of these (with the possible exception of the NDS32 implementation) actually require the target to be halted when starting profiling. The Cortex-M and OR1K actually resume the target as pretty much their first action. The default implementation doesn’t do this, but is written in such a way that the target just flips back and forth between halted and running, and the code will do the right thing from either initial state. The NDS32 implementation I don’t know about. As such, for everything except NDS32, it is not really necessary that the target be halted to start profiling. For the non-PCSR Cortex-M and default implementations, there is no real harm in such a requirement, because profiling is intrusive anyway, but there is no benefit. For the PCSR-based Cortex-M and the OR1K, requiring that the target is halted is annoying because it makes profiling more intrusive. Remove the must-be-halted check from the target_profiling function. Add it to the NDS32 implementation because I am not sure if that will break when invoked with a running target. Do not add it to any of the other implementations because they don’t need it. Change-Id: I479dce999a80eccccfd3be4fa192c904f0a45709 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/5235 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- src/target/nds32.c | 6 ++++++ src/target/target.c | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/target/nds32.c b/src/target/nds32.c index 487e19c6a..add66b22f 100644 --- a/src/target/nds32.c +++ b/src/target/nds32.c @@ -2496,6 +2496,12 @@ int nds32_profiling(struct target *target, uint32_t *samples, struct aice_port_s *aice = target_to_aice(target); struct nds32 *nds32 = target_to_nds32(target); + /* REVISIT: can nds32 profile without halting? */ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + if (max_num_samples < iteration) iteration = max_num_samples; diff --git a/src/target/target.c b/src/target/target.c index fa609efdb..d1399eddf 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1324,10 +1324,6 @@ unsigned target_address_bits(struct target *target) int target_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { - if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); - return ERROR_TARGET_NOT_HALTED; - } return target->type->profiling(target, samples, max_num_samples, num_samples, seconds); } From d3aa2d35363faeec4976b34fd5cb3127820ebc8d Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Fri, 14 Jun 2019 15:25:26 -0700 Subject: [PATCH 014/113] target/cortex_m: reduce duplication in profiling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Cortex-M implementation of profiling contains a bunch of conditionals and checks to handle both chips which have PCSR and chips which do not. However, the net effect of the non-PCSR branches is actually exactly the same as what target_profiling_default does. Rather than duplicating this code, just detect the situation where PCSR isn’t available and delegate to target_profiling_default. Change-Id: I1be57ac77f983816ab6bf644a3cfca77b67d6f70 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/5236 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 62 +++++++++++++------------------------------ src/target/target.c | 4 +-- src/target/target.h | 3 +++ 3 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index abc377f0d..503995a5d 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1835,28 +1835,23 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, struct timeval timeout, now; struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t reg_value; - bool use_pcsr = false; - int retval = ERROR_OK; - struct reg *reg; - - gettimeofday(&timeout, NULL); - timeval_add_time(&timeout, seconds, 0); + int retval; retval = target_read_u32(target, DWT_PCSR, ®_value); if (retval != ERROR_OK) { LOG_ERROR("Error while reading PCSR"); return retval; } - - if (reg_value != 0) { - use_pcsr = true; - LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); - } else { - LOG_INFO("Starting profiling. Halting and resuming the" - " target as often as we can..."); - reg = register_get_by_name(target->reg_cache, "pc", 1); + if (reg_value == 0) { + LOG_INFO("PCSR sampling not supported on this processor."); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); } + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + LOG_INFO("Starting Cortex-M profiling. Sampling DWT_PCSR as fast as we can..."); + /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) @@ -1870,40 +1865,21 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t sample_count = 0; for (;;) { - if (use_pcsr) { - if (armv7m && armv7m->debug_ap) { - uint32_t read_count = max_num_samples - sample_count; - if (read_count > 1024) - read_count = 1024; + if (armv7m && armv7m->debug_ap) { + uint32_t read_count = max_num_samples - sample_count; + if (read_count > 1024) + read_count = 1024; - retval = mem_ap_read_buf_noincr(armv7m->debug_ap, - (void *)&samples[sample_count], - 4, read_count, DWT_PCSR); - sample_count += read_count; - } else { - target_read_u32(target, DWT_PCSR, &samples[sample_count++]); - } + retval = mem_ap_read_buf_noincr(armv7m->debug_ap, + (void *)&samples[sample_count], + 4, read_count, DWT_PCSR); + sample_count += read_count; } else { - target_poll(target); - if (target->state == TARGET_HALTED) { - reg_value = buf_get_u32(reg->value, 0, 32); - /* current pc, addr = 0, do not handle breakpoints, not debugging */ - retval = target_resume(target, 1, 0, 0, 0); - samples[sample_count++] = reg_value; - target_poll(target); - alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ - } else if (target->state == TARGET_RUNNING) { - /* We want to quickly sample the PC. */ - retval = target_halt(target); - } else { - LOG_INFO("Target not halted or running"); - retval = ERROR_OK; - break; - } + target_read_u32(target, DWT_PCSR, &samples[sample_count++]); } if (retval != ERROR_OK) { - LOG_ERROR("Error while reading %s", use_pcsr ? "PCSR" : "target pc"); + LOG_ERROR("Error while reading PCSR"); return retval; } diff --git a/src/target/target.c b/src/target/target.c index d1399eddf..e64004fe5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -72,8 +72,6 @@ static int target_get_gdb_fileio_info_default(struct target *target, struct gdb_fileio_info *fileio_info); static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); -static int target_profiling_default(struct target *target, uint32_t *samples, - uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); /* targets */ extern struct target_type arm7tdmi_target; @@ -2137,7 +2135,7 @@ static int target_gdb_fileio_end_default(struct target *target, return ERROR_OK; } -static int target_profiling_default(struct target *target, uint32_t *samples, +int target_profiling_default(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { struct timeval timeout, now; diff --git a/src/target/target.h b/src/target/target.h index c69aa934a..9589b535a 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -748,6 +748,9 @@ void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer); +int target_profiling_default(struct target *target, uint32_t *samples, uint32_t + max_num_samples, uint32_t *num_samples, uint32_t seconds); + #define ERROR_TARGET_INVALID (-300) #define ERROR_TARGET_INIT_FAILED (-301) #define ERROR_TARGET_TIMEOUT (-302) From d05ef53cbd08972f89bd13e8ce2739de68965a05 Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Fri, 14 Jun 2019 15:35:31 -0700 Subject: [PATCH 015/113] target: restore last run state after profiling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that it’s possible to start profiling from either a running or a halted state, rather than unconditionally halting after profiling finishes, it makes more sense to restore the processor to whatever state (running or halted) it was in before profiling started. Change-Id: If6f6e70a1a365c1ce3b348a306c435c220b8bf12 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/5237 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/target.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index e64004fe5..53d3e82d7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -4097,6 +4097,7 @@ COMMAND_HANDLER(handle_profile_command) uint32_t offset; uint32_t num_of_samples; int retval = ERROR_OK; + bool halted_before_profiling = target->state == TARGET_HALTED; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset); @@ -4127,12 +4128,23 @@ COMMAND_HANDLER(handle_profile_command) free(samples); return retval; } - if (target->state == TARGET_RUNNING) { + + if (target->state == TARGET_RUNNING && halted_before_profiling) { + /* The target was halted before we started and is running now. Halt it, + * for consistency. */ retval = target_halt(target); if (retval != ERROR_OK) { free(samples); return retval; } + } else if (target->state == TARGET_HALTED && !halted_before_profiling) { + /* The target was running before we started and is halted now. Resume + * it, for consistency. */ + retval = target_resume(target, 1, 0, 0, 0); + if (retval != ERROR_OK) { + free(samples); + return retval; + } } retval = target_poll(target); From 38277fa75280071fb4e851de291b0274a457cea1 Mon Sep 17 00:00:00 2001 From: "Cliff L. Biffle" Date: Tue, 12 May 2020 13:28:04 -0700 Subject: [PATCH 016/113] jtag/drivers/stlink_usb: fix SWO prescaler The config_trace function has an out-parameter for generating the prescaler for the TPIU. The STLink implementation wasn't always writing it, causing the tpiu command to load uninitialized stack memory (minus one) into the TPIU's prescaler register when 'external' was requested. This change ensures that the out-parameter (and the other one, trace_freq, which hadn't caused any buggy behavior for me) are written every time. Signed-off-by: Cliff L. Biffle Change-Id: I222975869b1aa49cc6b1963c79d5ea0f46522b8c Reviewed-on: http://openocd.zylin.com/5656 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/stlink_usb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index ce55b94a5..bfc27f2aa 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -2996,12 +2996,8 @@ int stlink_config_trace(void *handle, bool enabled, return ERROR_FAIL; } - if (!enabled) { - stlink_usb_trace_disable(h); - return ERROR_OK; - } - - if (*trace_freq > STLINK_TRACE_MAX_HZ) { + /* Only concern ourselves with the frequency if the STlink is processing it. */ + if (enabled && *trace_freq > STLINK_TRACE_MAX_HZ) { LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", STLINK_TRACE_MAX_HZ); return ERROR_FAIL; @@ -3024,6 +3020,10 @@ int stlink_config_trace(void *handle, bool enabled, } *prescaler = presc; + + if (!enabled) + return ERROR_OK; + h->trace.source_hz = *trace_freq; return stlink_usb_trace_enable(h); From a92d275feccb4d6e2b682f7d8f52abccac7b2b29 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Mon, 26 Oct 2020 10:51:15 +0000 Subject: [PATCH 017/113] board: drop open-bldc This is a) broken and b) doesn't include anything other than the (broken) target alias. Don't see any reason for it to exist. Change-Id: I833635eeac392bf7c0c39f51ff2f76525ba2d406 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/5884 Reviewed-by: Tarek BOCHKATI Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/open-bldc.cfg | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 tcl/board/open-bldc.cfg diff --git a/tcl/board/open-bldc.cfg b/tcl/board/open-bldc.cfg deleted file mode 100644 index da8654c8d..000000000 --- a/tcl/board/open-bldc.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Open Source Brush Less DC Motor Controller -# http://open-bldc.org - -# Work-area size (RAM size) = 20kB for STM32F103RB device -set WORKAREASIZE 0x5000 - -source [find target/stm32.cfg] From 40e9c77cb663602e77ebb3c6ebacee41f816954a Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Tue, 27 Oct 2020 16:48:06 +0000 Subject: [PATCH 018/113] jtag: xlnx-pcie-xvc: Declare function static The xlnx_pcie_xvc_execute_stableclocks() function can and should be static. Change-Id: I45fb1363caee1f1762b0b1ac2c6bc1bb0153b15b Signed-off-by: Moritz Fischer Reviewed-on: http://openocd.zylin.com/5889 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Antonio Borneo --- src/jtag/drivers/xlnx-pcie-xvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-pcie-xvc.c index 2423a9f05..22f256f35 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-pcie-xvc.c @@ -120,7 +120,7 @@ static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, return ERROR_OK; } -int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) { int tms = tap_get_state() == TAP_RESET ? 1 : 0; size_t left = cmd->cmd.stableclocks->num_cycles; From 3da7c1fc83171c5b7ad9b2e8be774f6081e977fd Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 24 Apr 2020 22:52:57 +0200 Subject: [PATCH 019/113] tcl/interface/ti-icdi: remove empty lines at end of file Change-Id: I031dc52c20b8f213b12df13c9c974d9ac3ef2164 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5603 Tested-by: jenkins --- tcl/interface/ti-icdi.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/tcl/interface/ti-icdi.cfg b/tcl/interface/ti-icdi.cfg index 9decae9ab..8561a3182 100644 --- a/tcl/interface/ti-icdi.cfg +++ b/tcl/interface/ti-icdi.cfg @@ -15,4 +15,3 @@ hla_vid_pid 0x1cbe 0x00fd # multiple devices. Serial numbers can be obtained using lsusb -v # Ex. #hla_serial "0F003065" - From 962697823e6065094aa7b925fa09e08456afde28 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 26 Oct 2020 17:54:55 +0100 Subject: [PATCH 020/113] tcl/board: drop 'tcl' prefix in 'find' command When OpenOCD is installed to the host the 'tcl' folder gets usually installed in /usr/share/openocd/, thus having 'tcl' as prefix of the target's file causes 'find' to fail. Remove the 'tcl' folder prefix. Change-Id: I3dc484c8de6af8f5aae4dd1b230522ee47ae2ba6 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5887 Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/board/tocoding_poplar.cfg | 2 +- tcl/board/tx25_stk5.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg index d0951ce64..6d2e6354e 100644 --- a/tcl/board/tocoding_poplar.cfg +++ b/tcl/board/tocoding_poplar.cfg @@ -10,7 +10,7 @@ adapter speed 10000 # SRST-only reset configuration reset_config srst_only srst_push_pull -source [find tcl/target/hi3798.cfg] +source [find target/hi3798.cfg] # make sure the default target is the boot core targets ${_TARGETNAME}0 diff --git a/tcl/board/tx25_stk5.cfg b/tcl/board/tx25_stk5.cfg index 846bf58f5..9d77afdf3 100644 --- a/tcl/board/tx25_stk5.cfg +++ b/tcl/board/tx25_stk5.cfg @@ -4,7 +4,7 @@ # ------------------------------------------------------------------------- -source [find tcl/target/imx25.cfg] +source [find target/imx25.cfg] #------------------------------------------------------------------------- # Declare Nand From 91c4c83f44760f323f3bcab44c89ac59b4ed74c7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 26 Oct 2020 17:58:33 +0100 Subject: [PATCH 021/113] tcl/board: fix changed target config filenames In commit a1ce28b118e7 ("rename some target scripts to be consistent with the rest") the following renames was applied, but the old names are still referenced: tcl/target/{sam7se512.cfg => at91sam7se512.cfg} tcl/target/{sam7x256.cfg => at91sam7x256.cfg} Fix the board files to use to correct target config filename. Change-Id: I7698aa0da7db95c2bd9ba7ab8c260905a975c857 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5888 Reviewed-by: Tomas Vanek Tested-by: jenkins --- tcl/board/eir.cfg | 2 +- tcl/board/olimex_sam7_ex256.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/board/eir.cfg b/tcl/board/eir.cfg index 422db0d88..67758b81e 100644 --- a/tcl/board/eir.cfg +++ b/tcl/board/eir.cfg @@ -1,7 +1,7 @@ # Elector Internet Radio board # http://www.ethernut.de/en/hardware/eir/index.html -source [find target/sam7se512.cfg] +source [find target/at91sam7se512.cfg] $_TARGETNAME configure -event reset-init { # WDT_MR, disable watchdog diff --git a/tcl/board/olimex_sam7_ex256.cfg b/tcl/board/olimex_sam7_ex256.cfg index 426ead6aa..08ed4c17e 100644 --- a/tcl/board/olimex_sam7_ex256.cfg +++ b/tcl/board/olimex_sam7_ex256.cfg @@ -1,3 +1,3 @@ # Olimex SAM7-EX256 has a single Atmel at91sam7ex256 on it. -source [find target/sam7x256.cfg] +source [find target/at91sam7x256.cfg] From cd19f466885d542cfee16d5341369b3c445a696f Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 29 Oct 2020 18:15:33 +0100 Subject: [PATCH 022/113] flash/nor/atsamv: fix clang static analyzer warning Warning: line 679, column 4 4th function call argument is an uninitialized value Change-Id: If62d96e1595be945c8e17885bb402e820fb1ec7b Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5903 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Jonathan McDowell --- src/flash/nor/atsamv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index af48398e0..8f1450bf7 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -676,6 +676,9 @@ showall: } if ((who >= 0) && (((unsigned)who) < SAMV_NUM_GPNVM_BITS)) { r = samv_get_gpnvm(target, who, &v); + if (r != ERROR_OK) + return r; + command_print(CMD, "samv-gpnvm%u: %u", who, v); return r; } else { From a932810f9d55256caea8c65a79506e838a17c316 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 29 Oct 2020 18:32:13 +0100 Subject: [PATCH 023/113] helper/command: fix clang static analyzer warning Warning: line 955, column 3 Argument to free() is the address of a global variable, which is not memory allocated by malloc() It is definitely a false alarm. Simplify concatenation of arguments and allocate a string always to silence the warning. Change-Id: I5ac4cc610fc35224df0b16ef4f7102700363249f Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5904 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/helper/command.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index 271e7b993..773195e2f 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -920,39 +920,29 @@ COMMAND_HANDLER(handle_help_command) bool full = strcmp(CMD_NAME, "help") == 0; int retval; struct command *c = CMD_CTX->commands; - char *cmd_match = NULL; + char *cmd_match; - if (CMD_ARGC == 0) - cmd_match = ""; - else if (CMD_ARGC >= 1) { - unsigned i; + if (CMD_ARGC <= 0) + cmd_match = strdup(""); - for (i = 0; i < CMD_ARGC; ++i) { - if (NULL != cmd_match) { - char *prev = cmd_match; + else { + cmd_match = strdup(CMD_ARGV[0]); - cmd_match = alloc_printf("%s %s", cmd_match, CMD_ARGV[i]); - free(prev); - if (NULL == cmd_match) { - LOG_ERROR("unable to build search string"); - return -ENOMEM; - } - } else { - cmd_match = alloc_printf("%s", CMD_ARGV[i]); - if (NULL == cmd_match) { - LOG_ERROR("unable to build search string"); - return -ENOMEM; - } - } + for (unsigned int i = 1; i < CMD_ARGC && cmd_match; ++i) { + char *prev = cmd_match; + cmd_match = alloc_printf("%s %s", prev, CMD_ARGV[i]); + free(prev); } - } else - return ERROR_COMMAND_SYNTAX_ERROR; + } + if (cmd_match == NULL) { + LOG_ERROR("unable to build search string"); + return -ENOMEM; + } retval = CALL_COMMAND_HANDLER(command_help_show_list, c, 0, full, cmd_match); - if (CMD_ARGC >= 1) - free(cmd_match); + free(cmd_match); return retval; } From 49b7099def030accbceb9a92782fb389d04e8e09 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 29 Oct 2020 19:57:20 +0100 Subject: [PATCH 024/113] gdb_server: fix clang static analyzer warning Warning: line 373, column 15 Assigned value is garbage or undefined Most probably a false warning, building the hex string byte per byte seems too complicated for static analyze. Change malloc to calloc to silence the warning. Change-Id: I746d43fa51abf05582ccf2680ed72dc557798a7a Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5905 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Jonathan McDowell --- src/server/gdb_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c36966554..1a209a769 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1332,7 +1332,7 @@ static int gdb_get_register_packet(struct connection *connection, } } - reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ + reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */ gdb_str_to_target(target, reg_packet, reg_list[reg_num]); From 3099d52d78ce3703cefa0a066a879fb95fd047d3 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 29 Oct 2020 20:41:54 +0100 Subject: [PATCH 025/113] jtag/tcl: fix memory leak in error return Clang static analyzer reported: Warning: line 196, column 3 Potential leak of memory pointed to by 'fields' Free allocated memory pointed by 'fields' and fields[i].in_value Change-Id: I0b3935d9a235544afc03e39a4648319047e65815 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5906 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Jonathan McDowell --- src/jtag/tcl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 153a98e1b..2fa162e56 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -194,6 +194,11 @@ static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args retval = jtag_execute_queue(); if (retval != ERROR_OK) { Jim_SetResultString(interp, "drscan: jtag execute failed", -1); + + for (i = 0; i < field_count; i++) + free(fields[i].in_value); + free(fields); + return JIM_ERR; } From 80a5285ea6157706075e783fd6cb1ad09875d660 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 14 Oct 2020 14:14:09 +0100 Subject: [PATCH 026/113] stm32h7x.cfg: alignment with RM0399 rev3 in RM0399 rev2, there was these bits in DBGMCU_CR registers: - DBGSTBY_D3 : bit 7 - DBGSTOP_D3 : bit 8 these bits have been changed to reserved in rev3 Change-Id: I9d10d90e383795dc8e25a117d59fa065dc594610 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5861 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Antonio Borneo --- tcl/target/stm32h7x.cfg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 43a8b024e..5220af3b1 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -149,8 +149,10 @@ $_CHIPNAME.cpu0 configure -event examine-end { stm32h7x_dbgmcu_mmw 0x004 0x00600000 0 # Enable debug during low power modes (uses more power) - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3, D2 & D1 Domains - stm32h7x_dbgmcu_mmw 0x004 0x000001BF 0 + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D1 Domain + stm32h7x_dbgmcu_mmw 0x004 0x00000007 0 + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP D2 Domain + stm32h7x_dbgmcu_mmw 0x004 0x00000038 0 # Stop watchdog counters during halt # DBGMCU_APB3FZ1 |= WWDG1 From 080fab2ecdcc495f68176ea72a7fc75f99ccb20e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 12 Oct 2020 00:11:07 +0200 Subject: [PATCH 027/113] target/arm_adi_v5: add helper to get mem_ap spot in configure/cget This is somehow an extension of existing adiv5_jim_configure(), but includes the 'address' in the mem_ap. Rewrite adiv5_jim_configure() using the new helper. Change-Id: Ia7effeeece044004d459b45126ed4961a98b8568 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5857 Tested-by: jenkins --- src/target/arm_adi_v5.c | 210 ++++++++++++++++++++++++---------------- src/target/arm_adi_v5.h | 10 ++ 2 files changed, 135 insertions(+), 85 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index a09e2698a..2bccf6be7 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1479,15 +1479,113 @@ int dap_info_command(struct command_invocation *cmd, enum adiv5_cfg_param { CFG_DAP, - CFG_AP_NUM + CFG_AP_NUM, + CFG_BASEADDR, }; static const Jim_Nvp nvp_config_opts[] = { - { .name = "-dap", .value = CFG_DAP }, - { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = "-dap", .value = CFG_DAP }, + { .name = "-ap-num", .value = CFG_AP_NUM }, + { .name = "-baseaddr", .value = CFG_BASEADDR }, { .name = NULL, .value = -1 } }; +static int adiv5_jim_spot_configure(Jim_GetOptInfo *goi, + struct adiv5_dap **dap_p, int *ap_num_p, uint32_t *base_p) +{ + if (!goi->argc) + return JIM_OK; + + Jim_SetEmptyResult(goi->interp); + + Jim_Nvp *n; + int e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + /* base_p can be NULL, then '-baseaddr' option is treated as unknown */ + if (!base_p && n->value == CFG_BASEADDR) + return JIM_CONTINUE; + + e = Jim_GetOpt_Obj(goi, NULL); + if (e != JIM_OK) + return e; + + switch (n->value) { + case CFG_DAP: + if (goi->isconfigure) { + Jim_Obj *o_t; + struct adiv5_dap *dap; + e = Jim_GetOpt_Obj(goi, &o_t); + if (e != JIM_OK) + return e; + dap = dap_instance_by_jim_obj(goi->interp, o_t); + if (!dap) { + Jim_SetResultString(goi->interp, "DAP name invalid!", -1); + return JIM_ERR; + } + if (*dap_p && *dap_p != dap) { + Jim_SetResultString(goi->interp, + "DAP assignment cannot be changed!", -1); + return JIM_ERR; + } + *dap_p = dap; + } else { + if (goi->argc) + goto err_no_param; + if (!*dap_p) { + Jim_SetResultString(goi->interp, "DAP not configured", -1); + return JIM_ERR; + } + Jim_SetResultString(goi->interp, adiv5_dap_name(*dap_p), -1); + } + break; + + case CFG_AP_NUM: + if (goi->isconfigure) { + jim_wide ap_num; + e = Jim_GetOpt_Wide(goi, &ap_num); + if (e != JIM_OK) + return e; + if (ap_num < 0 || ap_num > DP_APSEL_MAX) { + Jim_SetResultString(goi->interp, "Invalid AP number!", -1); + return JIM_ERR; + } + *ap_num_p = ap_num; + } else { + if (goi->argc) + goto err_no_param; + if (*ap_num_p == DP_APSEL_INVALID) { + Jim_SetResultString(goi->interp, "AP number not configured", -1); + return JIM_ERR; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *ap_num_p)); + } + break; + + case CFG_BASEADDR: + if (goi->isconfigure) { + jim_wide base; + e = Jim_GetOpt_Wide(goi, &base); + if (e != JIM_OK) + return e; + *base_p = (uint32_t)base; + } else { + if (goi->argc) + goto err_no_param; + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, *base_p)); + } + break; + }; + + return JIM_OK; + +err_no_param: + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); + return JIM_ERR; +} + int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) { struct adiv5_private_config *pc; @@ -1502,90 +1600,19 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi) target->has_dap = true; - if (goi->argc > 0) { - Jim_Nvp *n; + e = adiv5_jim_spot_configure(goi, &pc->dap, &pc->ap_num, NULL); + if (e != JIM_OK) + return e; - Jim_SetEmptyResult(goi->interp); - - /* check first if topmost item is for us */ - e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, - goi->argv[0], &n); - if (e != JIM_OK) - return JIM_CONTINUE; - - e = Jim_GetOpt_Obj(goi, NULL); - if (e != JIM_OK) - return e; - - switch (n->value) { - case CFG_DAP: - if (goi->isconfigure) { - Jim_Obj *o_t; - struct adiv5_dap *dap; - e = Jim_GetOpt_Obj(goi, &o_t); - if (e != JIM_OK) - return e; - dap = dap_instance_by_jim_obj(goi->interp, o_t); - if (dap == NULL) { - Jim_SetResultString(goi->interp, "DAP name invalid!", -1); - return JIM_ERR; - } - if (pc->dap != NULL && pc->dap != dap) { - Jim_SetResultString(goi->interp, - "DAP assignment cannot be changed after target was created!", -1); - return JIM_ERR; - } - if (target->tap_configured) { - Jim_SetResultString(goi->interp, - "-chain-position and -dap configparams are mutually exclusive!", -1); - return JIM_ERR; - } - pc->dap = dap; - target->tap = dap->tap; - target->dap_configured = true; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } - - if (pc->dap == NULL) { - Jim_SetResultString(goi->interp, "DAP not configured", -1); - return JIM_ERR; - } - Jim_SetResultString(goi->interp, adiv5_dap_name(pc->dap), -1); - } - break; - - case CFG_AP_NUM: - if (goi->isconfigure) { - jim_wide ap_num; - e = Jim_GetOpt_Wide(goi, &ap_num); - if (e != JIM_OK) - return e; - if (ap_num < 0 || ap_num > DP_APSEL_MAX) { - Jim_SetResultString(goi->interp, "Invalid AP number!", -1); - return JIM_ERR; - } - pc->ap_num = ap_num; - } else { - if (goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, - goi->argc, goi->argv, - "NO PARAMS"); - return JIM_ERR; - } - - if (pc->ap_num == DP_APSEL_INVALID) { - Jim_SetResultString(goi->interp, "AP number not configured", -1); - return JIM_ERR; - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, pc->ap_num)); - } - break; + if (pc->dap && !target->dap_configured) { + if (target->tap_configured) { + pc->dap = NULL; + Jim_SetResultString(goi->interp, + "-chain-position and -dap configparams are mutually exclusive!", -1); + return JIM_ERR; } + target->tap = pc->dap->tap; + target->dap_configured = true; } return JIM_OK; @@ -1602,6 +1629,19 @@ int adiv5_verify_config(struct adiv5_private_config *pc) return ERROR_OK; } +int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, + Jim_GetOptInfo *goi) +{ + return adiv5_jim_spot_configure(goi, &cfg->dap, &cfg->ap_num, &cfg->base); +} + +int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p) +{ + p->dap = NULL; + p->ap_num = DP_APSEL_INVALID; + p->base = 0; + return ERROR_OK; +} COMMAND_HANDLER(handle_dap_info_command) { diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index ea7155167..f319a062d 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -601,4 +601,14 @@ struct adiv5_private_config { extern int adiv5_verify_config(struct adiv5_private_config *pc); extern int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi); +struct adiv5_mem_ap_spot { + struct adiv5_dap *dap; + int ap_num; + uint32_t base; +}; + +extern int adiv5_mem_ap_spot_init(struct adiv5_mem_ap_spot *p); +extern int adiv5_jim_mem_ap_spot_configure(struct adiv5_mem_ap_spot *cfg, + Jim_GetOptInfo *goi); + #endif /* OPENOCD_TARGET_ARM_ADI_V5_H */ From ec0c23a3ab3908d9f573f7bd9b0fa33a11ec49ba Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 17 Oct 2020 16:27:13 +0200 Subject: [PATCH 028/113] target/arm_cti: use adiv5_jim_mem_ap_spot_configure() To avoid code duplication, reorganize the code to replace cti_configure() with adiv5_jim_mem_ap_spot_configure(). Reorganize 'struct arm_cti_object' and its sub-'struct arm_cti' moving DAP and mem-AP info in a 'struct adiv5_mem_ap_spot'. Replace cti_configure() with adiv5_jim_mem_ap_spot_configure(). Deprecate the use of '-ctibase' in favor of '-baseaddr'. Change-Id: I43740a37c80de67c0f5e4dc79c3400b91a12e9e8 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5869 Tested-by: jenkins --- doc/openocd.texi | 2 +- src/target/arm_adi_v5.c | 7 +- src/target/arm_cti.c | 141 ++++++++++++---------------------------- 3 files changed, 48 insertions(+), 102 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index dba2a0afa..ca10f8c0b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8593,7 +8593,7 @@ CTI is mandatory for core run control and each core has an individual CTI instance attached to it. OpenOCD has limited support for CTI using the @emph{cti} group of commands. -@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-ctibase} base_address +@deffn Command {cti create} cti_name @option{-dap} dap_name @option{-ap-num} apn @option{-baseaddr} base_address Creates a CTI instance @var{cti_name} on the DAP instance @var{dap_name} on MEM-AP @var{apn}. The @var{base_address} must match the base address of the CTI on the respective MEM-AP. All arguments are mandatory. This creates a diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 2bccf6be7..31c14597b 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1481,12 +1481,14 @@ enum adiv5_cfg_param { CFG_DAP, CFG_AP_NUM, CFG_BASEADDR, + CFG_CTIBASE, /* DEPRECATED */ }; static const Jim_Nvp nvp_config_opts[] = { { .name = "-dap", .value = CFG_DAP }, { .name = "-ap-num", .value = CFG_AP_NUM }, { .name = "-baseaddr", .value = CFG_BASEADDR }, + { .name = "-ctibase", .value = CFG_CTIBASE }, /* DEPRECATED */ { .name = NULL, .value = -1 } }; @@ -1505,7 +1507,7 @@ static int adiv5_jim_spot_configure(Jim_GetOptInfo *goi, return JIM_CONTINUE; /* base_p can be NULL, then '-baseaddr' option is treated as unknown */ - if (!base_p && n->value == CFG_BASEADDR) + if (!base_p && (n->value == CFG_BASEADDR || n->value == CFG_CTIBASE)) return JIM_CONTINUE; e = Jim_GetOpt_Obj(goi, NULL); @@ -1564,6 +1566,9 @@ static int adiv5_jim_spot_configure(Jim_GetOptInfo *goi, } break; + case CFG_CTIBASE: + LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'"); + /* fall through */ case CFG_BASEADDR: if (goi->isconfigure) { jim_wide base; diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 579bacb77..689e9df9f 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -31,28 +31,21 @@ #include "helper/command.h" struct arm_cti { - target_addr_t base; - struct adiv5_ap *ap; -}; - -struct arm_cti_object { struct list_head lh; - struct arm_cti cti; - int ap_num; char *name; + struct adiv5_mem_ap_spot spot; }; static LIST_HEAD(all_cti); const char *arm_cti_name(struct arm_cti *self) { - struct arm_cti_object *obj = container_of(self, struct arm_cti_object, cti); - return obj->name; + return self->name; } struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { - struct arm_cti_object *obj = NULL; + struct arm_cti *obj = NULL; const char *name; bool found = false; @@ -66,16 +59,17 @@ struct arm_cti *cti_instance_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) } if (found) - return &obj->cti; + return obj; return NULL; } static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t mask, uint32_t value) { + struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); uint32_t tmp; /* Read register */ - int retval = mem_ap_read_atomic_u32(self->ap, self->base + reg, &tmp); + int retval = mem_ap_read_atomic_u32(ap, self->spot.base + reg, &tmp); if (ERROR_OK != retval) return retval; @@ -85,26 +79,28 @@ static int arm_cti_mod_reg_bits(struct arm_cti *self, unsigned int reg, uint32_t tmp |= value & mask; /* write new value */ - return mem_ap_write_atomic_u32(self->ap, self->base + reg, tmp); + return mem_ap_write_atomic_u32(ap, self->spot.base + reg, tmp); } int arm_cti_enable(struct arm_cti *self, bool enable) { + struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); uint32_t val = enable ? 1 : 0; - return mem_ap_write_atomic_u32(self->ap, self->base + CTI_CTR, val); + return mem_ap_write_atomic_u32(ap, self->spot.base + CTI_CTR, val); } int arm_cti_ack_events(struct arm_cti *self, uint32_t event) { + struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); int retval; uint32_t tmp; - retval = mem_ap_write_atomic_u32(self->ap, self->base + CTI_INACK, event); + retval = mem_ap_write_atomic_u32(ap, self->spot.base + CTI_INACK, event); if (retval == ERROR_OK) { int64_t then = timeval_ms(); for (;;) { - retval = mem_ap_read_atomic_u32(self->ap, self->base + CTI_TROUT_STATUS, &tmp); + retval = mem_ap_read_atomic_u32(ap, self->spot.base + CTI_TROUT_STATUS, &tmp); if (retval != ERROR_OK) break; if ((tmp & event) == 0) @@ -138,15 +134,19 @@ int arm_cti_ungate_channel(struct arm_cti *self, uint32_t channel) int arm_cti_write_reg(struct arm_cti *self, unsigned int reg, uint32_t value) { - return mem_ap_write_atomic_u32(self->ap, self->base + reg, value); + struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); + + return mem_ap_write_atomic_u32(ap, self->spot.base + reg, value); } int arm_cti_read_reg(struct arm_cti *self, unsigned int reg, uint32_t *p_value) { + struct adiv5_ap *ap = dap_ap(self->spot.dap, self->spot.ap_num); + if (p_value == NULL) return ERROR_COMMAND_ARGUMENT_INVALID; - return mem_ap_read_atomic_u32(self->ap, self->base + reg, p_value); + return mem_ap_read_atomic_u32(ap, self->spot.base + reg, p_value); } int arm_cti_pulse_channel(struct arm_cti *self, uint32_t channel) @@ -225,7 +225,7 @@ static int cti_find_reg_offset(const char *name) int arm_cti_cleanup_all(void) { - struct arm_cti_object *obj, *tmp; + struct arm_cti *obj, *tmp; list_for_each_entry_safe(obj, tmp, &all_cti, lh) { free(obj->name); @@ -237,16 +237,16 @@ int arm_cti_cleanup_all(void) COMMAND_HANDLER(handle_cti_dump) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; + struct adiv5_ap *ap = dap_ap(cti->spot.dap, cti->spot.ap_num); int retval = ERROR_OK; for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) - retval = mem_ap_read_u32(cti->ap, - cti->base + cti_names[i].offset, cti_names[i].p_val); + retval = mem_ap_read_u32(ap, + cti->spot.base + cti_names[i].offset, cti_names[i].p_val); if (retval == ERROR_OK) - retval = dap_run(cti->ap->dap); + retval = dap_run(ap->dap); if (retval != ERROR_OK) return JIM_ERR; @@ -260,8 +260,7 @@ COMMAND_HANDLER(handle_cti_dump) COMMAND_HANDLER(handle_cti_enable) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) @@ -274,8 +273,7 @@ COMMAND_HANDLER(handle_cti_enable) COMMAND_HANDLER(handle_cti_testmode) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; bool on_off; if (CMD_ARGC != 1) @@ -288,8 +286,7 @@ COMMAND_HANDLER(handle_cti_testmode) COMMAND_HANDLER(handle_cti_write) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int offset; uint32_t value; @@ -307,8 +304,7 @@ COMMAND_HANDLER(handle_cti_write) COMMAND_HANDLER(handle_cti_read) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int offset; int retval; uint32_t value; @@ -331,8 +327,7 @@ COMMAND_HANDLER(handle_cti_read) COMMAND_HANDLER(handle_cti_ack) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; uint32_t event; if (CMD_ARGC != 1) @@ -351,8 +346,7 @@ COMMAND_HANDLER(handle_cti_ack) COMMAND_HANDLER(handle_cti_channel) { - struct arm_cti_object *obj = CMD_DATA; - struct arm_cti *cti = &obj->cti; + struct arm_cti *cti = CMD_DATA; int retval = ERROR_OK; uint32_t ch_num; @@ -436,83 +430,26 @@ static const struct command_registration cti_instance_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -enum cti_cfg_param { - CFG_DAP, - CFG_AP_NUM, - CFG_CTIBASE -}; - -static const Jim_Nvp nvp_config_opts[] = { - { .name = "-dap", .value = CFG_DAP }, - { .name = "-ctibase", .value = CFG_CTIBASE }, - { .name = "-ap-num", .value = CFG_AP_NUM }, - { .name = NULL, .value = -1 } -}; - -static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti) +static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti *cti) { - struct adiv5_dap *dap = NULL; - Jim_Nvp *n; - jim_wide w; - int e; - /* parse config or cget options ... */ while (goi->argc > 0) { - Jim_SetEmptyResult(goi->interp); - - e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); - if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); + int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi); + if (e != JIM_OK) return e; - } - switch (n->value) { - case CFG_DAP: { - Jim_Obj *o_t; - e = Jim_GetOpt_Obj(goi, &o_t); - if (e != JIM_OK) - return e; - dap = dap_instance_by_jim_obj(goi->interp, o_t); - if (dap == NULL) { - Jim_SetResultString(goi->interp, "-dap is invalid", -1); - return JIM_ERR; - } - /* loop for more */ - break; - } - case CFG_CTIBASE: - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - cti->cti.base = (uint32_t)w; - /* loop for more */ - break; - - case CFG_AP_NUM: - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - if (w < 0 || w > DP_APSEL_MAX) { - Jim_SetResultString(goi->interp, "-ap-num is invalid", -1); - return JIM_ERR; - } - cti->ap_num = (uint32_t)w; - } } - if (dap == NULL) { + if (!cti->spot.dap) { Jim_SetResultString(goi->interp, "-dap required when creating CTI", -1); return JIM_ERR; } - cti->cti.ap = dap_ap(dap, cti->ap_num); - return JIM_OK; } - static int cti_create(Jim_GetOptInfo *goi) { struct command_context *cmd_ctx; - static struct arm_cti_object *cti; + static struct arm_cti *cti; Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; @@ -536,10 +473,14 @@ static int cti_create(Jim_GetOptInfo *goi) } /* Create it */ - cti = calloc(1, sizeof(struct arm_cti_object)); + cti = calloc(1, sizeof(*cti)); if (cti == NULL) return JIM_ERR; + adiv5_mem_ap_spot_init(&cti->spot); + + /* Do the rest as "configure" options */ + goi->isconfigure = 1; e = cti_configure(goi, cti); if (e != JIM_OK) { free(cti); @@ -593,7 +534,7 @@ static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int jim_cti_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - struct arm_cti_object *obj; + struct arm_cti *obj; if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); From 360b2c27012f3f787382bee9ce0b4e4707b22dc3 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 17 Oct 2020 19:25:50 +0200 Subject: [PATCH 029/113] tcl: replace '-ctibase' with '-baseaddr' Replace the deprecated option '-ctibase' with the generic option '-baseaddr'. Change generated with command: sed -i 's/-ctibase/-baseaddr/g' $(find tcl/ -type f) Change-Id: If776934d2ac106532708768bb3a4ec6fcffb0368 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5870 Tested-by: jenkins --- tcl/target/bluefield.cfg | 2 +- tcl/target/hi3798.cfg | 2 +- tcl/target/hi6220.cfg | 4 ++-- tcl/target/imx8m.cfg | 2 +- tcl/target/ls1012a.cfg | 2 +- tcl/target/marvell/88f37x0.cfg | 2 +- tcl/target/renesas_rcar_gen3.cfg | 4 ++-- tcl/target/rk3308.cfg | 2 +- tcl/target/stm32h7x.cfg | 4 ++-- tcl/target/stm32mp15x.cfg | 8 ++++---- tcl/target/xilinx_zynqmp.cfg | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tcl/target/bluefield.cfg b/tcl/target/bluefield.cfg index b31dfe8d6..62b1e3165 100644 --- a/tcl/target/bluefield.cfg +++ b/tcl/target/bluefield.cfg @@ -46,7 +46,7 @@ set _cores 16 # Create each core for { set _core $_core_start } { $_core < $_core_start + $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg index aa811d44d..7b1921895 100644 --- a/tcl/target/hi3798.cfg +++ b/tcl/target/hi3798.cfg @@ -30,7 +30,7 @@ set $_TARGETNAME.cti(3) 0x80320000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" diff --git a/tcl/target/hi6220.cfg b/tcl/target/hi6220.cfg index c2feb0b36..ddeeaad7c 100644 --- a/tcl/target/hi6220.cfg +++ b/tcl/target/hi6220.cfg @@ -37,7 +37,7 @@ set $_TARGETNAME.cti(7) 0x801DB000 set _cores 8 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core" @@ -57,7 +57,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { eval $_smp_command -cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0x80003000 +cti create cti.sys -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80003000 # declare the auxiliary Cortex-M3 core on AP #2 (runs mcuimage.bin) target create ${_TARGETNAME}.m3 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine diff --git a/tcl/target/imx8m.cfg b/tcl/target/imx8m.cfg index e3b7d24e1..9a8bfecb1 100644 --- a/tcl/target/imx8m.cfg +++ b/tcl/target/imx8m.cfg @@ -35,7 +35,7 @@ set CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000} for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ - -ctibase [lindex $CTIBASE $_core] + -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" diff --git a/tcl/target/ls1012a.cfg b/tcl/target/ls1012a.cfg index 19d3e5838..e1bd16844 100644 --- a/tcl/target/ls1012a.cfg +++ b/tcl/target/ls1012a.cfg @@ -25,7 +25,7 @@ jtag newtap $_CHIPNAME sap -irlen 8 -expected-id $_SAP_TAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.dap -cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0x80420000 +cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80420000 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -dbgbase 0x80410000 -cti $_CHIPNAME.cti diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg index 5e7513588..5c3dd737e 100644 --- a/tcl/target/marvell/88f37x0.cfg +++ b/tcl/target/marvell/88f37x0.cfg @@ -44,7 +44,7 @@ set _smp_command "" for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [lindex $_ctis $_core] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [lindex $_ctis $_core] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core \ diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg index 72f185d61..5738d371c 100644 --- a/tcl/target/renesas_rcar_gen3.cfg +++ b/tcl/target/renesas_rcar_gen3.cfg @@ -122,7 +122,7 @@ proc setup_a5x {core_name dbgbase ctibase num boot} { set _TARGETNAME $_CHIPNAME.$core_name.$_core set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \ - -ctibase [lindex $ctibase $_core] + -baseaddr [lindex $ctibase $_core] set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME" if { $_core == 0 && $boot == 1 } { @@ -140,7 +140,7 @@ proc setup_cr7 {dbgbase ctibase boot} { global _DAPNAME set _TARGETNAME $_CHIPNAME.r7 set _CTINAME $_TARGETNAME.cti - cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -ctibase $ctibase + cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ -ap-num 1 -dbgbase $dbgbase" if { $boot == 1 } { diff --git a/tcl/target/rk3308.cfg b/tcl/target/rk3308.cfg index d3d409eaf..b55109312 100644 --- a/tcl/target/rk3308.cfg +++ b/tcl/target/rk3308.cfg @@ -45,7 +45,7 @@ set $_TARGETNAME.cti(3) 0x8101b000 set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core 1 } { - cti create cti$_core -dap $_CHIPNAME.dap -ctibase [set $_TARGETNAME.cti($_core)] -ap-num 0 + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 set _command "target create ${_TARGETNAME}$_core aarch64 \ -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 5220af3b1..4a04929aa 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -228,8 +228,8 @@ proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { if {[set $_CHIPNAME.USE_CTI]} { # create CTI instances for both cores - cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -ctibase 0xE0043000 - cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -ctibase 0xE0043000 + cti create $_CHIPNAME.cti0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0043000 + cti create $_CHIPNAME.cti1 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xE0043000 $_CHIPNAME.cpu0 configure -event halted { stm32h7x_cti_prepare_restart_all } $_CHIPNAME.cpu1 configure -event halted { stm32h7x_cti_prepare_restart_all } diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/stm32mp15x.cfg index f2ba94eec..4a8bc866c 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/stm32mp15x.cfg @@ -59,10 +59,10 @@ $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on $_CHIPNAME.cpu1 cortex_a dacrfixup on -cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE0094000 -cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D8000 -cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -ctibase 0xE00D9000 -cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -ctibase 0xE0043000 +cti create $_CHIPNAME.cti.sys -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE0094000 +cti create $_CHIPNAME.cti.cpu0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D8000 +cti create $_CHIPNAME.cti.cpu1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0xE00D9000 +cti create $_CHIPNAME.cti.cm4 -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xE0043000 # interface does not work while srst is asserted # this is target specific, valid for every board diff --git a/tcl/target/xilinx_zynqmp.cfg b/tcl/target/xilinx_zynqmp.cfg index 9be781cd8..b21603f62 100644 --- a/tcl/target/xilinx_zynqmp.cfg +++ b/tcl/target/xilinx_zynqmp.cfg @@ -74,7 +74,7 @@ set _cores 4 for { set _core 0 } { $_core < $_cores } { incr _core } { cti create $_CTINAME.$_core -dap $_CHIPNAME.dap -ap-num 1 \ - -ctibase [lindex $CTIBASE $_core] + -baseaddr [lindex $CTIBASE $_core] set _command "target create $_TARGETNAME.$_core aarch64 -dap $_CHIPNAME.dap \ -dbgbase [lindex $DBGBASE $_core] -cti $_CTINAME.$_core" From e2e8a5f467e8e35618ce4fbf16b8da4e682d8258 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 15 Oct 2020 14:45:27 +0200 Subject: [PATCH 030/113] gdb_server: allow multiple GDB connections to selected targets The default way of working is to have a single GDB attached to one target, so OpenOCD accepts only one connection to the GDB port of each targets and rejects any further connection. There are some barely safe use cases in which it could get useful having a second GDB connection to the same target. One such use case is while using GDB as a 'non-intrusive memory inspector', as explained in the OpenOCD documentation. One GDB can be left running an infinite loop to dump some memory area, or even analysing the content, while keeping a second GDB ready for user interaction or spot memory check. Add a target configure option to specify the maximum number of GDB connections allowed for that target, keeping the default to 1. Change-Id: I4985a602e61588df0b527d2f2aa5b955c93e125e Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5865 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- doc/openocd.texi | 13 ++++++++++++- src/server/gdb_server.c | 2 +- src/target/target.c | 28 +++++++++++++++++++++++++--- src/target/target.h | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ca10f8c0b..e6a14673f 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4694,6 +4694,11 @@ possible values of the parameter @var{number}, which are not only numeric values Use this option to override, for this target only, the global parameter set with command @command{gdb_port}. @xref{gdb_port,,command gdb_port}. + +@item @code{-gdb-max-connections} @var{number} -- EXPERIMENTAL: set the maximum +number of GDB connections that are allowed for the target. Default is 1. +A negative value for @var{number} means unlimited connections. +See @xref{gdbmeminspect,,Using GDB as a non-intrusive memory inspector}. @end itemize @end deffn @@ -10606,7 +10611,13 @@ of a running target. Do not use GDB commands @command{continue}, and GDB would require stopping the target to get the prompt back. Do not use this mode under an IDE like Eclipse as it caches values of -previously shown varibles. +previously shown variables. + +It's also possible to connect more than one GDB to the same target by the +target's configuration option @code{-gdb-max-connections}. This allows, for +example, one GDB to run a script that continuously polls a set of variables +while other GDB can be used interactively. Be extremely careful in this case, +because the two GDB can easily get out-of-sync. @section RTOS Support @cindex RTOS Support diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 1a209a769..c96be1034 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3508,7 +3508,7 @@ static int gdb_target_start(struct target *target, const char *port) target->gdb_service = gdb_service; ret = add_service("gdb", - port, 1, &gdb_new_connection, &gdb_input, + port, target->gdb_max_connections, &gdb_new_connection, &gdb_input, &gdb_connection_closed, gdb_service); /* initialize all targets gdb service with the same pointer */ { diff --git a/src/target/target.c b/src/target/target.c index 53d3e82d7..9443f6c86 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1263,10 +1263,10 @@ int target_get_gdb_reg_list_noread(struct target *target, bool target_supports_gdb_connection(struct target *target) { /* - * based on current code, we can simply exclude all the targets that - * don't provide get_gdb_reg_list; this could change with new targets. + * exclude all the targets that don't provide get_gdb_reg_list + * or that have explicit gdb_max_connection == 0 */ - return !!target->type->get_gdb_reg_list; + return !!target->type->get_gdb_reg_list && !!target->gdb_max_connections; } int target_step(struct target *target, @@ -4652,6 +4652,7 @@ enum target_cfg_param { TCFG_RTOS, TCFG_DEFER_EXAMINE, TCFG_GDB_PORT, + TCFG_GDB_MAX_CONNECTIONS, }; static Jim_Nvp nvp_config_opts[] = { @@ -4668,6 +4669,7 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, { .name = "-gdb-port", .value = TCFG_GDB_PORT }, + { .name = "-gdb-max-connections", .value = TCFG_GDB_MAX_CONNECTIONS }, { .name = NULL, .value = -1 } }; @@ -4975,6 +4977,25 @@ no_params: Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1); /* loop for more */ break; + + case TCFG_GDB_MAX_CONNECTIONS: + if (goi->isconfigure) { + struct command_context *cmd_ctx = current_command_context(goi->interp); + if (cmd_ctx->mode != COMMAND_CONFIG) { + Jim_SetResultString(goi->interp, "-gdb-max-conenctions must be configured before 'init'", -1); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + target->gdb_max_connections = (w < 0) ? CONNECTION_LIMIT_UNLIMITED : (int)w; + } else { + if (goi->argc != 0) + goto no_params; + } + Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->gdb_max_connections)); + break; } } /* while (goi->argc) */ @@ -5555,6 +5576,7 @@ static int target_create(Jim_GetOptInfo *goi) target->rtos_auto_detect = false; target->gdb_port_override = NULL; + target->gdb_max_connections = 1; /* Do the rest as "configure" options */ goi->isconfigure = 1; diff --git a/src/target/target.h b/src/target/target.h index 9589b535a..ee0bdfb65 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -211,6 +211,8 @@ struct target { char *gdb_port_override; /* target-specific override for gdb_port */ + int gdb_max_connections; /* max number of simultaneous gdb connections */ + /* The semihosting information, extracted from the target. */ struct semihosting *semihosting; }; From 65de0d3bfa14c59c2fea31a2974dd3492ac3320d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 23 Oct 2020 16:45:35 +0200 Subject: [PATCH 031/113] target: handle command 'target current' when no target is present Is it possible to run OpenOCD without any target, for example to only dump the rom-tables of an arm dap, or to perform low level jtag operations. But without any target created, the command 'target current' causes OpenOCD to abruptly exit. Handle in command 'target current' the case of no targets. Change-Id: Ide15cb13bec84b88ccc3e7126523c04a6d70e636 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5881 Tested-by: jenkins --- src/target/target.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/target/target.c b/src/target/target.c index 9443f6c86..e2e614ffa 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5699,7 +5699,9 @@ static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); - Jim_SetResultString(interp, target_name(get_current_target(cmd_ctx)), -1); + struct target *target = get_current_target_or_null(cmd_ctx); + if (target) + Jim_SetResultString(interp, target_name(target), -1); return JIM_OK; } From 1718e733d607914b29631c2dacf817911c84c76c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 27 Oct 2020 22:56:49 +0100 Subject: [PATCH 032/113] configure.ac: stop automake to search for scripts in parent dirs Automake will search for the helper scripts in the folder that contains the current Makefile.am (typically '.'), then some of the scripts will be also searched in '..' and '../..'. If the parent folders '..' or '../..' of OpenOCD source code contain a file named 'install.sh', then automake will use it and will assume that the same folder should contains also 'ltmain.sh'. This situation can either cause the build to fail or automake to use incorrect helper scripts. Force automake to only search for helper scripts in the current directory. Change-Id: I00bbd6bf9057c94cf5007e5ecda3fefd683481f5 Signed-off-by: Antonio Borneo Fixes: https://sourceforge.net/p/openocd/tickets/285/ Reviewed-on: http://openocd.zylin.com/5890 Tested-by: jenkins --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 569816637..47a167e28 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_PREREQ(2.64) AC_INIT([openocd], [0.10.0+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) +AC_CONFIG_AUX_DIR([.]) m4_include([config_subdir.m4])dnl From 5bb0f6befb3c3f06903cee93f14bdd917abf21e7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 00:51:30 +0100 Subject: [PATCH 033/113] openocd: add support for libftdi 1.5 The new libftdi 1.5 (2020-07-07) changes some API, deprecating the old ones. This cause a warning at compile time. Detect in configure the version of libftdi. Use the new API in the driver's code. Add an helper include file 'libftdi_helper.h' that wraps the old API for backward compatibility with old libftdi. Change-Id: I7800fbebe17dd0ce62e55b3598d8c08be8875bb7 Signed-off-by: Antonio Borneo Fixes: https://sourceforge.net/p/openocd/tickets/286/ Reviewed-on: http://openocd.zylin.com/5891 Tested-by: jenkins --- configure.ac | 6 +++++- src/jtag/drivers/Makefile.am | 1 + src/jtag/drivers/libftdi_helper.h | 27 +++++++++++++++++++++++++++ src/jtag/drivers/openjtag.c | 6 +++--- src/jtag/drivers/presto.c | 8 ++++---- 5 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/jtag/drivers/libftdi_helper.h diff --git a/configure.ac b/configure.ac index 47a167e28..055833a7f 100644 --- a/configure.ac +++ b/configure.ac @@ -669,7 +669,11 @@ for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do ]) done -PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [ +PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ + use_libftdi=yes + PKG_CHECK_EXISTS([libftdi1 >= 1.5], + [AC_DEFINE([HAVE_LIBFTDI_TCIOFLUSH], [1], [Define if your libftdi has ftdi_tcioflush()])]) + ], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index e8d20ccf8..1a5ab4a2d 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -187,6 +187,7 @@ DRIVERHEADERS = \ %D%/bitbang.h \ %D%/bitq.h \ %D%/jtag_usb_common.h \ + %D%/libftdi_helper.h \ %D%/libusb_helper.h \ %D%/minidriver_imp.h \ %D%/mpsse.h \ diff --git a/src/jtag/drivers/libftdi_helper.h b/src/jtag/drivers/libftdi_helper.h new file mode 100644 index 000000000..e187b5727 --- /dev/null +++ b/src/jtag/drivers/libftdi_helper.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H +#define OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H + +#include + +#ifndef HAVE_LIBFTDI_TCIOFLUSH +/* Backward compatibility with libftdi pre 1.5 */ + +static inline int ftdi_tciflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_rx_buffer(ftdi); +} + +static inline int ftdi_tcoflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_tx_buffer(ftdi); +} + +static inline int ftdi_tcioflush(struct ftdi_context *ftdi) +{ + return ftdi_usb_purge_buffers(ftdi); +} +#endif + +#endif /* OPENOCD_JTAG_DRIVERS_LIBFTDI_HELPER_H */ diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 2cf5751d6..6940c8870 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -82,7 +82,7 @@ typedef enum openjtag_tap_state { } openjtag_tap_state_t; /* OPENJTAG access library includes */ -#include +#include "libftdi_helper.h" /* OpenJTAG vid/pid */ static uint16_t openjtag_vid = 0x0403; @@ -436,8 +436,8 @@ static int openjtag_init_standard(void) return ERROR_JTAG_DEVICE_ERROR; } - if (ftdi_usb_purge_buffers(&ftdic) < 0) { - LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); + if (ftdi_tcioflush(&ftdic) < 0) { + LOG_ERROR("ftdi flush: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } diff --git a/src/jtag/drivers/presto.c b/src/jtag/drivers/presto.c index 6c3a187db..43d669e3e 100644 --- a/src/jtag/drivers/presto.c +++ b/src/jtag/drivers/presto.c @@ -34,7 +34,7 @@ #include "bitq.h" /* PRESTO access library includes */ -#include +#include "libftdi_helper.h" /* -------------------------------------------------------------------------- */ @@ -160,8 +160,8 @@ static int presto_open_libftdi(char *req_serial) return ERROR_JTAG_DEVICE_ERROR; } - if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) { - LOG_ERROR("unable to purge PRESTO buffers"); + if (ftdi_tcioflush(&presto->ftdic) < 0) { + LOG_ERROR("unable to flush PRESTO buffers"); return ERROR_JTAG_DEVICE_ERROR; } @@ -174,7 +174,7 @@ static int presto_open_libftdi(char *req_serial) if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_DEBUG("no response from PRESTO, retrying"); - if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) + if (ftdi_tcioflush(&presto->ftdic) < 0) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; From 21bc36c4d7c813983f7ccf3ae958d96198867136 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 23:27:02 +0100 Subject: [PATCH 034/113] flash: declare local symbols as static Functions and variables that are not used outside the file should be declared as static. Change-Id: I52d46ed6d4c9b98a7152eb23274c836416f409a3 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5893 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nand/mxc.c | 4 ++-- src/flash/nor/at91sam3.c | 2 +- src/flash/nor/bluenrg-x.c | 12 ++++++++---- src/flash/nor/kinetis_ke.c | 2 +- src/flash/nor/mrvlqspi.c | 4 ++-- src/flash/nor/psoc4.c | 2 +- src/flash/nor/psoc6.c | 2 +- src/flash/nor/tcl.c | 2 +- src/flash/nor/xcf.c | 4 ++-- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index 2c5de0394..90027070f 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -860,7 +860,7 @@ static int validate_target_state(struct nand_device *nand) return ERROR_OK; } -int ecc_status_v1(struct nand_device *nand) +static int ecc_status_v1(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; @@ -886,7 +886,7 @@ int ecc_status_v1(struct nand_device *nand) return ERROR_OK; } -int ecc_status_v2(struct nand_device *nand) +static int ecc_status_v2(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index c9baffc70..9c4afd4af 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -3099,7 +3099,7 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) * is owned by this bank. This simplification works only for one shot * deallocation like current flash_free_all_banks() */ -void sam3_free_driver_priv(struct flash_bank *bank) +static void sam3_free_driver_priv(struct flash_bank *bank) { struct sam3_chip *chip = all_sam3_chips; while (chip) { diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 57ea7396f..57aebc597 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -43,7 +43,7 @@ struct flash_ctrl_priv_data { char *part_name; }; -const struct flash_ctrl_priv_data flash_priv_data_1 = { +static const struct flash_ctrl_priv_data flash_priv_data_1 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, @@ -53,7 +53,7 @@ const struct flash_ctrl_priv_data flash_priv_data_1 = { .part_name = "BLUENRG-1", }; -const struct flash_ctrl_priv_data flash_priv_data_2 = { +static const struct flash_ctrl_priv_data flash_priv_data_2 = { .die_id_reg = 0x4090001C, .jtag_idcode_reg = 0x40900028, .flash_base = 0x10040000, @@ -63,7 +63,7 @@ const struct flash_ctrl_priv_data flash_priv_data_2 = { .part_name = "BLUENRG-2", }; -const struct flash_ctrl_priv_data flash_priv_data_lp = { +static const struct flash_ctrl_priv_data flash_priv_data_lp = { .die_id_reg = 0x40000000, .jtag_idcode_reg = 0x40000004, .flash_base = 0x10040000, @@ -79,7 +79,11 @@ struct bluenrgx_flash_bank { const struct flash_ctrl_priv_data *flash_ptr; }; -const struct flash_ctrl_priv_data *flash_ctrl[] = {&flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp}; +static const struct flash_ctrl_priv_data *flash_ctrl[] = { + &flash_priv_data_1, + &flash_priv_data_2, + &flash_priv_data_lp +}; /* flash_bank bluenrg-x 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 349b2564d..5aba7fc64 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -434,7 +434,7 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) return ERROR_OK; } -int kinetis_ke_stop_watchdog(struct target *target) +static int kinetis_ke_stop_watchdog(struct target *target) { struct working_area *watchdog_algorithm; struct armv7m_algorithm armv7m_info; diff --git a/src/flash/nor/mrvlqspi.c b/src/flash/nor/mrvlqspi.c index 3293e6129..3f5ce2c66 100644 --- a/src/flash/nor/mrvlqspi.c +++ b/src/flash/nor/mrvlqspi.c @@ -761,7 +761,7 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } -int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, +static int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; @@ -914,7 +914,7 @@ static int mrvlqspi_flash_erase_check(struct flash_bank *bank) return ERROR_OK; } -int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size) +static int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size) { struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 9c2fdf775..b606e18cf 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -139,7 +139,7 @@ struct psoc4_chip_family { uint32_t flags; }; -const struct psoc4_chip_family psoc4_families[] = { +static const struct psoc4_chip_family psoc4_families[] = { { 0x93, "PSoC4100/4200", .flags = PSOC4_FAMILY_FLAG_LEGACY }, { 0x9A, "PSoC4000", .flags = 0 }, { 0x9E, "PSoC/PRoC BLE (119E)", .flags = 0 }, diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index df151c1b5..30bf88501 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -908,7 +908,7 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command) * @param target current target * @return ERROR_OK in case of success, ERROR_XXX code otherwise *************************************************************************************************/ -int handle_reset_halt(struct target *target) +static int handle_reset_halt(struct target *target) { int hr; uint32_t reset_addr; diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index e935b3b4a..386d73e39 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -30,7 +30,7 @@ * Implements Tcl commands used to access NOR flash facilities. */ -COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index, +static COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index, struct flash_bank **bank, bool do_probe) { const char *name = CMD_ARGV[name_index]; diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 29eef2dc3..0cef43b93 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -45,7 +45,7 @@ #define ID_XCF32P 0x05059093 #define ID_MEANINGFUL_MASK 0x0FFFFFFF -const char *xcf_name_list[] = { +static const char * const xcf_name_list[] = { "XCF08P", "XCF16P", "XCF32P", @@ -399,7 +399,7 @@ static void flip_u8(uint8_t *out, const uint8_t *in, int len) * Function presumes need of bit reversing if it can not exactly detects * the opposite. */ -bool need_bit_reverse(const uint8_t *buffer) +static bool need_bit_reverse(const uint8_t *buffer) { const size_t L = 20; uint8_t reference[L]; From d3bff4e5c42b6b3af65e31fbf2409fa3d88d1a03 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 23:39:34 +0100 Subject: [PATCH 035/113] rtos: declare local symbols as static Functions and variables that are not used outside the file should be declared as static. Change-Id: I9731a35496cd1c7421563c8961da5fa0e3cc71c3 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5894 Tested-by: jenkins Reviewed-by: Jonathan McDowell --- src/rtos/ThreadX.c | 2 +- src/rtos/hwthread.c | 4 ++-- src/rtos/linux.c | 34 +++++++++++++++++----------------- src/rtos/nuttx.c | 2 +- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index 302641bae..7d58725c4 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -110,7 +110,7 @@ static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_i { 16, 0x04, 32 }, /* xPSR */ }; -const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { +static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = { { ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */ -1, /* stack_growth_direction */ diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index e0789aa63..850b93223 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -37,7 +37,7 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs); static int hwthread_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); static int hwthread_smp_init(struct target *target); -int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); +static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value); #define HW_THREAD_NAME_STR_SIZE (32) @@ -298,7 +298,7 @@ static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id, return ERROR_OK; } -int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) +static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value) { if (rtos == NULL) return ERROR_FAIL; diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 44e132d36..0cb4b54c8 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -92,7 +92,7 @@ struct cpu_context { uint32_t PC; uint32_t preempt_count; }; -struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, +static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *info_addr); static int insert_into_threadlist(struct target *target, struct threads *t); @@ -144,7 +144,7 @@ static int linux_read_memory(struct target *target, return ERROR_OK; } -int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) +static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) { if ((addr & 0xfffffffc) != addr) @@ -155,7 +155,7 @@ int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) } -uint32_t get_buffer(struct target *target, const uint8_t *buffer) +static uint32_t get_buffer(struct target *target, const uint8_t *buffer) { uint32_t value = 0; const uint8_t *value_ptr = buffer; @@ -293,7 +293,7 @@ int fill_task_pid(struct target *target, struct threads *t) } #endif -int fill_task(struct target *target, struct threads *t) +static int fill_task(struct target *target, struct threads *t) { int retval; uint32_t pid_addr = t->base_addr + PID; @@ -349,7 +349,7 @@ int fill_task(struct target *target, struct threads *t) return retval; } -int get_name(struct target *target, struct threads *t) +static int get_name(struct target *target, struct threads *t) { int retval; uint32_t full_name[4]; @@ -395,7 +395,7 @@ int get_name(struct target *target, struct threads *t) } -int get_current(struct target *target, int create) +static int get_current(struct target *target, int create) { struct target_list *head; head = target->head; @@ -483,7 +483,7 @@ int get_current(struct target *target, int create) return ERROR_OK; } -struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, +static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *thread_info_addr_old) { struct cpu_context *context = calloc(1, sizeof(struct cpu_context)); @@ -579,7 +579,7 @@ retry: return context; } -uint32_t next_task(struct target *target, struct threads *t) +static uint32_t next_task(struct target *target, struct threads *t) { uint8_t *buffer = calloc(1, 4); uint32_t next_addr = t->base_addr + NEXT; @@ -598,7 +598,7 @@ uint32_t next_task(struct target *target, struct threads *t) return 0; } -struct current_thread *add_current_thread(struct current_thread *currents, +static struct current_thread *add_current_thread(struct current_thread *currents, struct current_thread *ct) { ct->next = NULL; @@ -617,7 +617,7 @@ struct current_thread *add_current_thread(struct current_thread *currents, } } -struct threads *liste_del_task(struct threads *task_list, struct threads **t, +static struct threads *liste_del_task(struct threads *task_list, struct threads **t, struct threads *prev) { LOG_INFO("del task %" PRId64, (*t)->threadid); @@ -634,7 +634,7 @@ struct threads *liste_del_task(struct threads *task_list, struct threads **t, return task_list; } -struct threads *liste_add_task(struct threads *task_list, struct threads *t, +static struct threads *liste_add_task(struct threads *task_list, struct threads *t, struct threads **last) { t->next = NULL; @@ -683,7 +683,7 @@ static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr) return 0; } -int linux_get_tasks(struct target *target, int context) +static int linux_get_tasks(struct target *target, int context) { int loop = 0; int retval = 0; @@ -1033,7 +1033,7 @@ static int linux_task_update(struct target *target, int context) return ERROR_OK; } -int linux_gdb_thread_packet(struct target *target, +static int linux_gdb_thread_packet(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1070,7 +1070,7 @@ int linux_gdb_thread_packet(struct target *target, return ERROR_OK; } -int linux_gdb_thread_update(struct target *target, +static int linux_gdb_thread_update(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1117,7 +1117,7 @@ int linux_gdb_thread_update(struct target *target, return ERROR_OK; } -int linux_thread_extra_info(struct target *target, +static int linux_thread_extra_info(struct target *target, struct connection *connection, char const *packet, int packet_size) { @@ -1163,7 +1163,7 @@ int linux_thread_extra_info(struct target *target, return ERROR_OK; } -int linux_gdb_T_packet(struct connection *connection, +static int linux_gdb_T_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { int64_t threadid; @@ -1223,7 +1223,7 @@ int linux_gdb_T_packet(struct connection *connection, return retval; } -int linux_gdb_h_packet(struct connection *connection, +static int linux_gdb_h_packet(struct connection *connection, struct target *target, char const *packet, int packet_size) { struct linux_os *linux_os = (struct linux_os *) diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 3c9062516..19b93bad1 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -72,7 +72,7 @@ struct tcb { uint8_t dat[512]; }; -struct { +static struct { uint32_t addr; uint32_t prio; } g_tasklist[TASK_QUEUE_NUM]; From 5ca23017434d726183c1562a8f12458c87770bfe Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 29 Oct 2020 00:23:13 +0100 Subject: [PATCH 036/113] target: declare local symbols as static Functions and variables that are not used outside the file should be declared as static. Change-Id: I9f97571a528f0cb3c3c26f873577ab16fdec3cdc Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5895 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/arm926ejs.c | 2 +- src/target/arm946e.c | 20 ++++++++++---------- src/target/armv7a.c | 2 +- src/target/armv7a_cache.c | 4 ++-- src/target/armv8.c | 2 +- src/target/avr32_ap7k.c | 8 ++++---- src/target/avr32_jtag.c | 12 ++++++------ src/target/cortex_a.c | 3 ++- src/target/dsp5680xx.c | 15 +++++---------- src/target/mips32_pracc.c | 4 ++-- src/target/mips_ejtag.c | 5 +++-- src/target/nds32_tlb.c | 2 +- src/target/nds32_v3.c | 2 +- src/target/nds32_v3m.c | 2 +- src/target/openrisc/jsp_server.c | 2 +- src/target/openrisc/or1k.c | 2 +- src/target/quark_d20xx.c | 4 ++-- src/target/stm8.c | 2 +- src/target/target.c | 6 +++--- 19 files changed, 48 insertions(+), 51 deletions(-) diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index 95a4f7ca0..21fd6897e 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -723,7 +723,7 @@ static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) return arm926ejs_init_arch_info(target, arm926ejs, target->tap); } -void arm926ejs_deinit_target(struct target *target) +static void arm926ejs_deinit_target(struct target *target) { struct arm *arm = target_to_arm(target); struct arm926ejs_common *arm926ejs = target_to_arm926(target); diff --git a/src/target/arm946e.c b/src/target/arm946e.c index 8754c861c..036e8bad7 100644 --- a/src/target/arm946e.c +++ b/src/target/arm946e.c @@ -51,8 +51,8 @@ */ static uint8_t arm946e_preserve_cache; -int arm946e_post_debug_entry(struct target *target); -void arm946e_pre_restore_context(struct target *target); +static int arm946e_post_debug_entry(struct target *target); +static void arm946e_pre_restore_context(struct target *target); static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value); int arm946e_init_arch_info(struct target *target, @@ -250,7 +250,7 @@ static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel) return csize ? 1 << (12 + (csize-3)) : 0; } -uint32_t arm946e_invalidate_whole_dcache(struct target *target) +static uint32_t arm946e_invalidate_whole_dcache(struct target *target) { uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE); if (csize == 0) @@ -306,7 +306,7 @@ uint32_t arm946e_invalidate_whole_dcache(struct target *target) return ERROR_OK; } -uint32_t arm946e_invalidate_whole_icache(struct target *target) +static uint32_t arm946e_invalidate_whole_icache(struct target *target) { /* Check cache presence before flushing - avoid undefined behavior */ uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE); @@ -327,7 +327,7 @@ uint32_t arm946e_invalidate_whole_icache(struct target *target) return ERROR_OK; } -int arm946e_post_debug_entry(struct target *target) +static int arm946e_post_debug_entry(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval = ERROR_OK; @@ -368,7 +368,7 @@ int arm946e_post_debug_entry(struct target *target) return ERROR_OK; } -void arm946e_pre_restore_context(struct target *target) +static void arm946e_pre_restore_context(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval; @@ -393,7 +393,7 @@ void arm946e_pre_restore_context(struct target *target) } /* if preserve_cache */ } -uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, +static uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; @@ -458,7 +458,7 @@ uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, return ERROR_OK; } -uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, +static uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; @@ -509,7 +509,7 @@ uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, } /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm946e_write_memory(struct target *target, target_addr_t address, +static int arm946e_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; @@ -557,7 +557,7 @@ int arm946e_write_memory(struct target *target, target_addr_t address, } -int arm946e_read_memory(struct target *target, target_addr_t address, +static int arm946e_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; diff --git a/src/target/armv7a.c b/src/target/armv7a.c index c36744ddf..abca3358f 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -589,7 +589,7 @@ static const struct command_registration l2_cache_commands[] = { }; -const struct command_registration l2x_cache_command_handlers[] = { +static const struct command_registration l2x_cache_command_handlers[] = { { .name = "cache_config", .mode = COMMAND_EXEC, diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index e5f1fb060..fa6df2a27 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -572,7 +572,7 @@ static const struct command_registration arm7a_l1_i_cache_commands[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arm7a_l1_di_cache_group_handlers[] = { +static const struct command_registration arm7a_l1_di_cache_group_handlers[] = { { .name = "info", .handler = arm7a_l1_cache_info_cmd, @@ -597,7 +597,7 @@ const struct command_registration arm7a_l1_di_cache_group_handlers[] = { COMMAND_REGISTRATION_DONE }; -const struct command_registration arm7a_cache_group_handlers[] = { +static const struct command_registration arm7a_cache_group_handlers[] = { { .name = "auto", .handler = arm7a_cache_disable_auto_cmd, diff --git a/src/target/armv8.c b/src/target/armv8.c index ab60cd371..95efdc90b 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -1126,7 +1126,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) return ERROR_OK; } -int armv8_aarch64_state(struct target *target) +static int armv8_aarch64_state(struct target *target) { struct arm *arm = target_to_arm(target); diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 622105913..b0c08752d 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -63,7 +63,7 @@ static const struct avr32_core_reg static int avr32_read_core_reg(struct target *target, int num); static int avr32_write_core_reg(struct target *target, int num); -int avr32_ap7k_save_context(struct target *target) +static int avr32_ap7k_save_context(struct target *target) { int retval, i; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); @@ -80,7 +80,7 @@ int avr32_ap7k_save_context(struct target *target) return ERROR_OK; } -int avr32_ap7k_restore_context(struct target *target) +static int avr32_ap7k_restore_context(struct target *target) { int i; @@ -555,7 +555,7 @@ static int avr32_ap7k_examine(struct target *target) return ERROR_OK; } -int avr32_ap7k_arch_state(struct target *target) +static int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); @@ -565,7 +565,7 @@ int avr32_ap7k_arch_state(struct target *target) return ERROR_OK; } -int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], +static int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { #if 0 diff --git a/src/target/avr32_jtag.c b/src/target/avr32_jtag.c index 64ebf12ba..62c8f98ca 100644 --- a/src/target/avr32_jtag.c +++ b/src/target/avr32_jtag.c @@ -55,7 +55,7 @@ static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) return ERROR_OK; } -int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, uint32_t addr, int mode) { struct scan_field fields[2]; @@ -92,7 +92,7 @@ int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, } -int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { @@ -129,7 +129,7 @@ int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, return ERROR_OK; } -int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, uint32_t data) { @@ -184,7 +184,7 @@ int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, return avr32_jtag_nexus_write_data(jtag_info, value); } -int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, +static int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, uint32_t addr, int mode) { struct scan_field fields[2]; @@ -223,7 +223,7 @@ int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, return ERROR_OK; } -int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { @@ -260,7 +260,7 @@ int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, return ERROR_OK; } -int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, +static int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, uint32_t data) { diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index bd8e49fd9..f39fd9b2b 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1115,7 +1115,8 @@ static int cortex_a_post_debug_entry(struct target *target) return ERROR_OK; } -int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) +static int cortex_a_set_dscr_bits(struct target *target, + unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index d6107abc6..ee26d24ac 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -40,7 +40,7 @@ struct dsp5680xx_common dsp5680xx_context; #define CHECK_HALT(target) if (target->state != TARGET_HALTED) HALT_FAIL #define check_halt_and_debug(target) { CHECK_HALT(target); CHECK_DBG; } -int dsp5680xx_execute_queue(void) +static int dsp5680xx_execute_queue(void) { int retval; @@ -892,12 +892,6 @@ static int dsp5680xx_arch_state(struct target *target) return ERROR_OK; } -int dsp5680xx_target_status(struct target *target, uint8_t *jtag_st, - uint16_t *eonce_st) -{ - return target->state; -} - static int dsp5680xx_assert_reset(struct target *target) { target->state = TARGET_RESET; @@ -1555,7 +1549,7 @@ static int perl_crc(const uint8_t *buff8, uint32_t word_count) * * @return */ -int dsp5680xx_f_SIM_reset(struct target *target) +static int dsp5680xx_f_SIM_reset(struct target *target) { int retval = ERROR_OK; @@ -1978,7 +1972,8 @@ int dsp5680xx_f_erase(struct target *target, int first, int last) * 0x0000001E 0xA961 bra *-30 */ -const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, +static const uint16_t pgm_write_pflash[] = { + 0x8A46, 0x0013, 0x807D, 0xE700, 0xE700, 0x8A44, 0xFFFE, 0x017B, 0xE700, 0xF514, 0x8563, 0x8646, 0x0020, 0x0014, 0x8646, 0x0080, @@ -1988,7 +1983,7 @@ const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, 0x0013, 0x0010, 0xA961 }; -const uint32_t pgm_write_pflash_length = 31; +static const uint32_t pgm_write_pflash_length = 31; int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t count, int is_flash_lock) diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index 9bac40eb0..d6bd1c58a 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -120,7 +120,7 @@ static void mips32_pracc_finish(struct mips_ejtag *ejtag_info) mips_ejtag_drscan_32_out(ejtag_info, ctrl); } -int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) +static int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info) { uint32_t jt_code = MIPS32_J(ejtag_info->isa, MIPS32_PRACC_TEXT); pracc_swap16_array(ejtag_info, &jt_code, 1); @@ -453,7 +453,7 @@ exit: return retval; } -int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) +static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) { struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; pracc_queue_init(&ctx); diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 7544afe52..4b049fb4e 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -58,7 +58,7 @@ int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info) return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->idcode); } -int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) +static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info) { mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE); @@ -119,7 +119,8 @@ int mips_ejtag_drscan_64(struct mips_ejtag *ejtag_info, uint64_t *data) return ERROR_OK; } -void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, uint32_t data_out, uint8_t *data_in) +static void mips_ejtag_drscan_32_queued(struct mips_ejtag *ejtag_info, + uint32_t data_out, uint8_t *data_in) { assert(ejtag_info->tap != NULL); struct jtag_tap *tap = ejtag_info->tap; diff --git a/src/target/nds32_tlb.c b/src/target/nds32_tlb.c index c4bce1a6a..93a924109 100644 --- a/src/target/nds32_tlb.c +++ b/src/target/nds32_tlb.c @@ -31,7 +31,7 @@ int nds32_probe_tlb(struct nds32 *nds32, const target_addr_t virtual_address, return aice_read_tlb(aice, virtual_address, physical_address); } -struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = { +static struct page_table_walker_info_s page_table_info[PAGE_SIZE_NUM] = { /* 4K page */ {0xFFC00000, 20, 0x003FF000, 10, 0x00000FFF, 0xFFFFF000, 0xFFFFF000, 0xFFFFF000}, /* 8K page */ diff --git a/src/target/nds32_v3.c b/src/target/nds32_v3.c index e5d146bb6..f9cd47a40 100644 --- a/src/target/nds32_v3.c +++ b/src/target/nds32_v3.c @@ -404,7 +404,7 @@ static int nds32_v3_remove_watchpoint(struct target *target, return ERROR_OK; } -struct nds32_v3_common_callback nds32_v3_common_callback = { +static struct nds32_v3_common_callback nds32_v3_common_callback = { .check_interrupt_stack = nds32_v3_check_interrupt_stack, .restore_interrupt_stack = nds32_v3_restore_interrupt_stack, .activate_hardware_breakpoint = nds32_v3_activate_hardware_breakpoint, diff --git a/src/target/nds32_v3m.c b/src/target/nds32_v3m.c index 86903a51b..952d0ebb4 100644 --- a/src/target/nds32_v3m.c +++ b/src/target/nds32_v3m.c @@ -379,7 +379,7 @@ static int nds32_v3m_remove_watchpoint(struct target *target, return ERROR_OK; } -struct nds32_v3_common_callback nds32_v3m_common_callback = { +static struct nds32_v3_common_callback nds32_v3m_common_callback = { .check_interrupt_stack = nds32_v3m_check_interrupt_stack, .restore_interrupt_stack = nds32_v3m_restore_interrupt_stack, .activate_hardware_breakpoint = nds32_v3m_activate_hardware_breakpoint, diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 1d05944bc..4dbe63527 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -57,7 +57,7 @@ static int telnet_write(struct connection *connection, const void *data, int len return ERROR_SERVER_REMOTE_CLOSED; } -int jsp_poll_read(void *priv) +static int jsp_poll_read(void *priv) { struct jsp_service *jsp_service = (struct jsp_service *)priv; unsigned char out_buffer[10]; diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index d685359be..5b8d7ded7 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -1200,7 +1200,7 @@ static int or1k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], } -int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) +static int or1k_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { return ERROR_FAIL; } diff --git a/src/target/quark_d20xx.c b/src/target/quark_d20xx.c index 42d3b8c73..9169379bb 100644 --- a/src/target/quark_d20xx.c +++ b/src/target/quark_d20xx.c @@ -43,7 +43,7 @@ #include "lakemont.h" #include "x86_32_common.h" -int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) +static int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) { struct x86_32_common *x86_32 = calloc(1, sizeof(struct x86_32_common)); if (x86_32 == NULL) { @@ -56,7 +56,7 @@ int quark_d20xx_target_create(struct target *t, Jim_Interp *interp) return ERROR_OK; } -int quark_d20xx_init_target(struct command_context *cmd_ctx, struct target *t) +static int quark_d20xx_init_target(struct command_context *cmd_ctx, struct target *t) { return lakemont_init_target(cmd_ctx, t); } diff --git a/src/target/stm8.c b/src/target/stm8.c index 78bf6a27a..e99b3c21b 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -1945,7 +1945,7 @@ static int stm8_run_algorithm(struct target *target, int num_mem_params, return ERROR_OK; } -int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) +static int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) { struct stm8_common *stm8 = target_to_stm8(target); jim_wide w; diff --git a/src/target/target.c b/src/target/target.c index e2e614ffa..da0c943bf 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -154,8 +154,8 @@ static struct target_type *target_types[] = { struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; -LIST_HEAD(target_reset_callback_list); -LIST_HEAD(target_trace_callback_list); +static LIST_HEAD(target_reset_callback_list); +static LIST_HEAD(target_trace_callback_list); static const int polling_interval = 100; static const Jim_Nvp nvp_assert[] = { @@ -1319,7 +1319,7 @@ unsigned target_address_bits(struct target *target) return 32; } -int target_profiling(struct target *target, uint32_t *samples, +static int target_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { return target->type->profiling(target, samples, max_num_samples, From 7beb6a4e5b832f376c4bb5b29f86aaee9acd46d7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 29 Oct 2020 00:47:12 +0100 Subject: [PATCH 037/113] jtag: declare local symbols as static Functions and variables that are not used outside the file should be declared as static. Change-Id: I58c9f5557d4809db9ccc34d32182c3797f825da1 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5896 Tested-by: jenkins --- src/jtag/aice/aice_pipe.c | 8 +- src/jtag/aice/aice_usb.c | 36 ++--- src/jtag/core.c | 2 +- src/jtag/drivers/ft232r.c | 2 +- src/jtag/drivers/gw16012.c | 2 +- src/jtag/drivers/opendous.c | 4 +- src/jtag/drivers/stlink_usb.c | 8 +- src/jtag/drivers/ulink.c | 130 +++++++++--------- src/jtag/drivers/usb_blaster/usb_blaster.c | 2 +- .../drivers/versaloon/usbtoxxx/usbtoswd.c | 4 +- .../drivers/versaloon/usbtoxxx/usbtoxxx.c | 10 +- src/jtag/drivers/versaloon/versaloon.c | 24 ++-- src/jtag/drivers/xds110.c | 2 +- src/jtag/hla/hla_interface.c | 4 +- 14 files changed, 119 insertions(+), 119 deletions(-) diff --git a/src/jtag/aice/aice_pipe.c b/src/jtag/aice/aice_pipe.c index bdc8c090a..c0e532c9d 100644 --- a/src/jtag/aice/aice_pipe.c +++ b/src/jtag/aice/aice_pipe.c @@ -35,8 +35,8 @@ #ifdef _WIN32 PROCESS_INFORMATION proc_info; -HANDLE aice_pipe_output[2]; -HANDLE aice_pipe_input[2]; +static HANDLE aice_pipe_output[2]; +static HANDLE aice_pipe_input[2]; static int aice_pipe_write(const void *buffer, int count) { @@ -158,8 +158,8 @@ static int aice_pipe_open(struct aice_port_param_s *param) #else -int aice_pipe_output[2]; -int aice_pipe_input[2]; +static int aice_pipe_output[2]; +static int aice_pipe_input[2]; static int aice_pipe_write(const void *buffer, int count) { diff --git a/src/jtag/aice/aice_usb.c b/src/jtag/aice/aice_usb.c index 7144632df..7688aeaab 100644 --- a/src/jtag/aice/aice_usb.c +++ b/src/jtag/aice/aice_usb.c @@ -683,7 +683,7 @@ int aice_write_ctrl(uint32_t address, uint32_t data) return ERROR_OK; } -int aice_read_dtr(uint8_t target_id, uint32_t *data) +static int aice_read_dtr(uint8_t target_id, uint32_t *data) { int retry_times = 0; @@ -733,7 +733,7 @@ int aice_read_dtr(uint8_t target_id, uint32_t *data) return ERROR_OK; } -int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx) +static int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx) { int retry_times = 0; @@ -784,7 +784,7 @@ int aice_read_dtr_to_buffer(uint8_t target_id, uint32_t buffer_idx) return ERROR_OK; } -int aice_write_dtr(uint8_t target_id, uint32_t data) +static int aice_write_dtr(uint8_t target_id, uint32_t data) { int retry_times = 0; @@ -836,7 +836,7 @@ int aice_write_dtr(uint8_t target_id, uint32_t data) return ERROR_OK; } -int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx) +static int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx) { int retry_times = 0; @@ -887,7 +887,7 @@ int aice_write_dtr_from_buffer(uint8_t target_id, uint32_t buffer_idx) return ERROR_OK; } -int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data) +static int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data) { int retry_times = 0; @@ -936,7 +936,7 @@ int aice_read_misc(uint8_t target_id, uint32_t address, uint32_t *data) return ERROR_OK; } -int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data) +static int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data) { int retry_times = 0; @@ -992,7 +992,7 @@ int aice_write_misc(uint8_t target_id, uint32_t address, uint32_t data) return ERROR_OK; } -int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data) +static int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data) { int retry_times = 0; @@ -1042,7 +1042,7 @@ int aice_read_edmsr(uint8_t target_id, uint32_t address, uint32_t *data) return ERROR_OK; } -int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data) +static int aice_write_edmsr(uint8_t target_id, uint32_t address, uint32_t data) { int retry_times = 0; @@ -1236,7 +1236,7 @@ static int aice_do_execute(uint8_t target_id) return ERROR_OK; } -int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data) +static int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data) { int retry_times = 0; @@ -1290,7 +1290,7 @@ int aice_write_mem_b(uint8_t target_id, uint32_t address, uint32_t data) return ERROR_OK; } -int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data) +static int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data) { int retry_times = 0; @@ -1345,7 +1345,7 @@ int aice_write_mem_h(uint8_t target_id, uint32_t address, uint32_t data) return ERROR_OK; } -int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data) +static int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data) { int retry_times = 0; @@ -1400,7 +1400,7 @@ int aice_write_mem(uint8_t target_id, uint32_t address, uint32_t data) return ERROR_OK; } -int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words) +static int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words) { int retry_times = 0; @@ -1450,7 +1450,7 @@ int aice_fastread_mem(uint8_t target_id, uint8_t *word, uint32_t num_of_words) return ERROR_OK; } -int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_words) +static int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_words) { int retry_times = 0; @@ -1506,7 +1506,7 @@ int aice_fastwrite_mem(uint8_t target_id, const uint8_t *word, uint32_t num_of_w return ERROR_OK; } -int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data) +static int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data) { int retry_times = 0; @@ -1556,7 +1556,7 @@ int aice_read_mem_b(uint8_t target_id, uint32_t address, uint32_t *data) return ERROR_OK; } -int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data) +static int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data) { int retry_times = 0; @@ -1606,7 +1606,7 @@ int aice_read_mem_h(uint8_t target_id, uint32_t address, uint32_t *data) return ERROR_OK; } -int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data) +static int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data) { int retry_times = 0; @@ -1657,7 +1657,7 @@ int aice_read_mem(uint8_t target_id, uint32_t address, uint32_t *data) return ERROR_OK; } -int aice_batch_buffer_read(uint8_t buf_index, uint32_t *word, uint32_t num_of_words) +static int aice_batch_buffer_read(uint8_t buf_index, uint32_t *word, uint32_t num_of_words) { int retry_times = 0; @@ -1760,7 +1760,7 @@ int aice_batch_buffer_write(uint8_t buf_index, const uint8_t *word, uint32_t num typedef int (*read_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t *data); typedef int (*write_mem_func_t)(uint32_t coreid, uint32_t address, uint32_t data); -struct aice_nds32_info core_info[AICE_MAX_NUM_CORE]; +static struct aice_nds32_info core_info[AICE_MAX_NUM_CORE]; static uint8_t total_num_of_core; static char *custom_srst_script; diff --git a/src/jtag/core.c b/src/jtag/core.c index 03a26bec2..f0f74eb80 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -209,7 +209,7 @@ unsigned jtag_tap_count_enabled(void) } /** Append a new TAP to the chain of all taps. */ -void jtag_tap_add(struct jtag_tap *t) +static void jtag_tap_add(struct jtag_tap *t) { unsigned jtag_num_taps = 0; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index d97db56a6..a63480c6e 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -170,7 +170,7 @@ static int ft232r_send_recv(void) return ERROR_OK; } -void ft232r_increase_buf_size(size_t new_buf_size) +static void ft232r_increase_buf_size(size_t new_buf_size) { uint8_t *new_buf_ptr; if (new_buf_size >= ft232r_buf_size) { diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index ef4b5d929..db0a67715 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -63,7 +63,7 @@ #endif /* configuration */ -uint16_t gw16012_port; +static uint16_t gw16012_port; /* interface variables */ diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index f0e4f566d..82fcbc119 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -144,7 +144,7 @@ static int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_lengt static int opendous_usb_read(struct opendous_jtag *opendous_jtag); /* helper functions */ -int opendous_get_version_info(void); +static int opendous_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void opendous_debug_buffer(uint8_t *buffer, int length); @@ -544,7 +544,7 @@ int opendous_get_status(void) return ERROR_OK; } -int opendous_get_version_info(void) +static int opendous_get_version_info(void) { return ERROR_OK; } diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index bfc27f2aa..48db3e611 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -358,7 +358,7 @@ static const struct speed_map stlink_khz_to_speed_map_jtag[] = { static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size); static int stlink_swim_status(void *handle); -void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); +static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size); static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map); static int stlink_speed(void *handle, int khz, bool query); static int stlink_usb_open_ap(void *handle, unsigned short apsel); @@ -2577,7 +2577,7 @@ static int stlink_speed_jtag(void *handle, int khz, bool query) return stlink_khz_to_speed_map_jtag[speed_index].speed; } -void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size) +static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_size) { unsigned int i; @@ -2725,7 +2725,7 @@ static int stlink_usb_close(void *handle) * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial * and then we have just to convert the raw data into printable characters using sprintf */ -char *stlink_usb_get_alternate_serial(libusb_device_handle *device, +static char *stlink_usb_get_alternate_serial(libusb_device_handle *device, struct libusb_device_descriptor *dev_desc) { int usb_retval; @@ -2982,7 +2982,7 @@ static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd) return stlink_usb_open(param, stlink_get_mode(param->transport), fd); } -int stlink_config_trace(void *handle, bool enabled, +static int stlink_config_trace(void *handle, bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 68249dcfe..4bc605171 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -162,34 +162,34 @@ struct ulink { /**************************** Function Prototypes *****************************/ /* USB helper functions */ -int ulink_usb_open(struct ulink **device); -int ulink_usb_close(struct ulink **device); +static int ulink_usb_open(struct ulink **device); +static int ulink_usb_close(struct ulink **device); /* ULINK MCU (Cypress EZ-USB) specific functions */ -int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit); -int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, +static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit); +static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay); -int ulink_load_firmware(struct ulink *device, const char *filename); -int ulink_write_firmware_section(struct ulink *device, +static int ulink_load_firmware(struct ulink *device, const char *filename); +static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index); /* Generic helper functions */ -void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); +static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); /* OpenULINK command generation helper functions */ -int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, +static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction); /* OpenULINK command queue helper functions */ -int ulink_get_queue_size(struct ulink *device, +static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction); -void ulink_clear_queue(struct ulink *device); -int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); -int ulink_execute_queued_commands(struct ulink *device, int timeout); +static void ulink_clear_queue(struct ulink *device); +static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); +static int ulink_execute_queued_commands(struct ulink *device, int timeout); static void ulink_print_queue(struct ulink *device); -int ulink_append_scan_cmd(struct ulink *device, +static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, @@ -201,39 +201,39 @@ int ulink_append_scan_cmd(struct ulink *device, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess); -int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, +static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence); -int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); -int ulink_append_get_signals_cmd(struct ulink *device); -int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, +static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); +static int ulink_append_get_signals_cmd(struct ulink *device); +static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high); -int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); -int ulink_append_configure_tck_cmd(struct ulink *device, +static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); +static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms); -int ulink_append_led_cmd(struct ulink *device, uint8_t led_state); -int ulink_append_test_cmd(struct ulink *device); +static int __attribute__((unused)) ulink_append_led_cmd(struct ulink *device, uint8_t led_state); +static int ulink_append_test_cmd(struct ulink *device); /* OpenULINK TCK frequency helper functions */ -int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); +static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); /* Interface between OpenULINK and OpenOCD */ static void ulink_set_end_state(tap_state_t endstate); -int ulink_queue_statemove(struct ulink *device); +static int ulink_queue_statemove(struct ulink *device); -int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); -int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); +static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); -int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); -int ulink_post_process_queue(struct ulink *device); +static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); +static int ulink_post_process_queue(struct ulink *device); /* adapter driver functions */ static int ulink_execute_queue(void); @@ -245,7 +245,7 @@ static int ulink_quit(void); /****************************** Global Variables ******************************/ -struct ulink *ulink_handle; +static struct ulink *ulink_handle; /**************************** USB helper functions ****************************/ @@ -258,7 +258,7 @@ struct ulink *ulink_handle; * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_usb_open(struct ulink **device) +static int ulink_usb_open(struct ulink **device) { ssize_t num_devices, i; bool found; @@ -304,7 +304,7 @@ int ulink_usb_open(struct ulink **device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_usb_close(struct ulink **device) +static int ulink_usb_close(struct ulink **device) { if (libusb_release_interface((*device)->usb_device_handle, 0) != 0) return ERROR_FAIL; @@ -327,7 +327,7 @@ int ulink_usb_close(struct ulink **device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) +static int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) { int ret; @@ -354,7 +354,7 @@ int ulink_cpu_reset(struct ulink *device, unsigned char reset_bit) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_load_firmware_and_renumerate(struct ulink **device, +static int ulink_load_firmware_and_renumerate(struct ulink **device, const char *filename, uint32_t delay) { int ret; @@ -390,7 +390,7 @@ int ulink_load_firmware_and_renumerate(struct ulink **device, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_load_firmware(struct ulink *device, const char *filename) +static int ulink_load_firmware(struct ulink *device, const char *filename) { struct image ulink_firmware_image; int ret, i; @@ -439,7 +439,7 @@ int ulink_load_firmware(struct ulink *device, const char *filename) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_write_firmware_section(struct ulink *device, +static int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index) { uint16_t addr, size, bytes_remaining, chunk_size; @@ -499,7 +499,7 @@ int ulink_write_firmware_section(struct ulink *device, * @param input_signals input signal states as returned by CMD_GET_SIGNALS * @param output_signals output signal states as returned by CMD_GET_SIGNALS */ -void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) +static void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) { LOG_INFO("ULINK signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i," " SRST: %i", @@ -522,7 +522,7 @@ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, +static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction) { uint8_t *payload; @@ -576,7 +576,7 @@ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, * @return the number of bytes currently stored in the queue for the specified * direction. */ -int ulink_get_queue_size(struct ulink *device, +static int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction) { struct ulink_cmd *current = device->queue_start; @@ -605,7 +605,7 @@ int ulink_get_queue_size(struct ulink *device, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -void ulink_clear_queue(struct ulink *device) +static void ulink_clear_queue(struct ulink *device) { struct ulink_cmd *current = device->queue_start; struct ulink_cmd *next = NULL; @@ -647,7 +647,7 @@ void ulink_clear_queue(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) +static int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) { int newsize_out, newsize_in; int ret = ERROR_OK; @@ -698,7 +698,7 @@ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_execute_queued_commands(struct ulink *device, int timeout) +static int ulink_execute_queued_commands(struct ulink *device, int timeout) { struct ulink_cmd *current; int ret, i, index_out, index_in, count_out, count_in, transferred; @@ -865,7 +865,7 @@ static void ulink_print_queue(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, +static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) @@ -966,7 +966,7 @@ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, +static int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); @@ -1003,7 +1003,7 @@ int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) +static int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; @@ -1036,7 +1036,7 @@ int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_get_signals_cmd(struct ulink *device) +static int ulink_append_get_signals_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; @@ -1075,7 +1075,7 @@ int ulink_append_get_signals_cmd(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, +static int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); @@ -1108,7 +1108,7 @@ int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) +static int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; @@ -1144,7 +1144,7 @@ int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, +static int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); @@ -1206,7 +1206,7 @@ int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) +static int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; @@ -1236,7 +1236,7 @@ int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_append_test_cmd(struct ulink *device) +static int ulink_append_test_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; @@ -1292,7 +1292,7 @@ int ulink_append_test_cmd(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) +static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) { float t, x, x_ceil; @@ -1423,7 +1423,7 @@ static void ulink_set_end_state(tap_state_t endstate) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_statemove(struct ulink *device) +static int ulink_queue_statemove(struct ulink *device) { uint8_t tms_sequence, tms_count; int ret; @@ -1452,7 +1452,7 @@ int ulink_queue_statemove(struct ulink *device) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) { uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; uint32_t scans_max_payload, bytecount; @@ -1631,7 +1631,7 @@ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) { int ret; @@ -1654,7 +1654,7 @@ int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) { int ret; @@ -1685,7 +1685,7 @@ int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) { uint8_t low = 0, high = 0; @@ -1711,7 +1711,7 @@ int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) { int ret, i, num_states, batch_size, state_count; tap_state_t *path; @@ -1770,7 +1770,7 @@ int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) { /* IMPORTANT! Due to the time offset in command execution introduced by * command queueing, this needs to be implemented in the ULINK device */ @@ -1783,7 +1783,7 @@ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. */ -int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) +static int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) { int ret; unsigned num_cycles; @@ -1828,7 +1828,7 @@ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) +static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) { struct jtag_command *cmd = ulink_cmd->cmd_origin; int ret; @@ -1859,7 +1859,7 @@ int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ -int ulink_post_process_queue(struct ulink *device) +static int ulink_post_process_queue(struct ulink *device) { struct ulink_cmd *current; struct jtag_command *openocd_cmd; diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 9648ba2e2..de3b5d58b 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -275,7 +275,7 @@ static void ublast_queue_byte(uint8_t abyte) * * Returns pin value (1 means driven high, 0 mean driven low) */ -bool ublast_compute_pin(enum gpio_steer steer) +static bool ublast_compute_pin(enum gpio_steer steer) { switch (steer) { case FIXED_0: diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c index ef1b675f7..cb4862fbf 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c @@ -28,7 +28,7 @@ #include "usbtoxxx.h" #include "usbtoxxx_internal.h" -RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) +static RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; @@ -38,7 +38,7 @@ RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed) return ERROR_OK; } -RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) +static RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; diff --git a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c index 678b097c9..b46bbe0e0 100644 --- a/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c +++ b/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c @@ -29,7 +29,7 @@ #define N_A "n/a" -const char *types_name[96] = { +static const char *types_name[96] = { "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm", "usbtoadc", "usbtodac", "usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay", @@ -55,8 +55,8 @@ static uint16_t usbtoxxx_buffer_index; static uint16_t usbtoxxx_current_cmd_index; static uint8_t *usbtoxxx_buffer; -uint16_t collect_index; -uint8_t collect_cmd; +static uint16_t collect_index; +static uint8_t collect_cmd; static uint8_t poll_nesting; struct usbtoxxx_context_t { @@ -86,7 +86,7 @@ static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c) versaloon_pending_idx = c->versaloon_pending_idx; } -RESULT usbtoxxx_validate_current_command_type(void) +static RESULT usbtoxxx_validate_current_command_type(void) { if (type_pre > 0) { /* not the first command */ @@ -272,7 +272,7 @@ bool usbtoxxx_interface_supported(uint8_t cmd) return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0; } -RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) +static RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) { /* check free space, commit if not enough */ if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen) diff --git a/src/jtag/drivers/versaloon/versaloon.c b/src/jtag/drivers/versaloon/versaloon.c index 8efe44353..b51779500 100644 --- a/src/jtag/drivers/versaloon/versaloon.c +++ b/src/jtag/drivers/versaloon/versaloon.c @@ -38,12 +38,12 @@ uint16_t versaloon_pending_idx; libusb_device_handle *versaloon_usb_device_handle; static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT; -RESULT versaloon_init(void); -RESULT versaloon_fini(void); -RESULT versaloon_get_target_voltage(uint16_t *voltage); -RESULT versaloon_set_target_voltage(uint16_t voltage); -RESULT versaloon_delay_ms(uint16_t ms); -RESULT versaloon_delay_us(uint16_t us); +static RESULT versaloon_init(void); +static RESULT versaloon_fini(void); +static RESULT versaloon_get_target_voltage(uint16_t *voltage); +static RESULT versaloon_set_target_voltage(uint16_t voltage); +static RESULT versaloon_delay_ms(uint16_t ms); +static RESULT versaloon_delay_us(uint16_t us); struct versaloon_interface_t versaloon_interface = { .init = versaloon_init, @@ -233,7 +233,7 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) } #define VERSALOON_RETRY_CNT 10 -RESULT versaloon_init(void) +static RESULT versaloon_init(void) { uint16_t ret = 0; uint8_t retry; @@ -291,7 +291,7 @@ RESULT versaloon_init(void) return versaloon_get_target_voltage(&ret); } -RESULT versaloon_fini(void) +static RESULT versaloon_fini(void) { if (versaloon_usb_device_handle != NULL) { usbtoxxx_fini(); @@ -309,7 +309,7 @@ RESULT versaloon_fini(void) return ERROR_OK; } -RESULT versaloon_set_target_voltage(uint16_t voltage) +static RESULT versaloon_set_target_voltage(uint16_t voltage) { usbtopwr_init(0); usbtopwr_config(0); @@ -319,7 +319,7 @@ RESULT versaloon_set_target_voltage(uint16_t voltage) return usbtoxxx_execute_command(); } -RESULT versaloon_get_target_voltage(uint16_t *voltage) +static RESULT versaloon_get_target_voltage(uint16_t *voltage) { uint16_t inlen; @@ -345,12 +345,12 @@ RESULT versaloon_get_target_voltage(uint16_t *voltage) } } -RESULT versaloon_delay_ms(uint16_t ms) +static RESULT versaloon_delay_ms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } -RESULT versaloon_delay_us(uint16_t us) +static RESULT versaloon_delay_us(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index fb04d51a4..df1ab6529 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -186,7 +186,7 @@ #define CMD_STABLECLOCKS 4 /* Array to convert from OpenOCD tap_state_t to XDS JTAG state */ -const uint32_t xds_jtag_state[] = { +static const uint32_t xds_jtag_state[] = { XDS_JTAG_STATE_EXIT2_DR, /* TAP_DREXIT2 = 0x0 */ XDS_JTAG_STATE_EXIT1_DR, /* TAP_DREXIT1 = 0x1 */ XDS_JTAG_STATE_SHIFT_DR, /* TAP_DRSHIFT = 0x2 */ diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 490eb9f4d..6691a9a32 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -188,7 +188,7 @@ int hl_interface_override_target(const char **targetname) return ERROR_FAIL; } -int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, +static int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, uint16_t *prescaler) { @@ -203,7 +203,7 @@ int hl_interface_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, return ERROR_OK; } -int hl_interface_poll_trace(uint8_t *buf, size_t *size) +static int hl_interface_poll_trace(uint8_t *buf, size_t *size) { if (hl_if.layout->api->poll_trace) return hl_if.layout->api->poll_trace(hl_if.handle, buf, size); From f3db7f173ecad8aa78367d8995c8b1fe7f2c4332 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 29 Oct 2020 00:49:06 +0100 Subject: [PATCH 038/113] server: declare local functions as static Functions that are not used outside the file should be declared as static. Change-Id: I57b2fa6e49e87e14604bd34c4f1d2f037f401507 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5897 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/server/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server.c b/src/server/server.c index 3b55d0d7c..e53f37d0b 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -595,7 +595,7 @@ int server_loop(struct command_context *command_context) return shutdown_openocd == SHUTDOWN_WITH_ERROR_CODE ? ERROR_FAIL : ERROR_OK; } -void sig_handler(int sig) +static void sig_handler(int sig) { /* store only first signal that hits us */ if (shutdown_openocd == CONTINUE_MAIN_LOOP) { From a8b436c511dc39e0785af4c9256b7723692ba60e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 23:20:42 +0100 Subject: [PATCH 039/113] transport: remove unused function transports_are_declared() The only use of this function has been removed with commit 159f11fefc19 ("jtag: set default "jtag_only" to uninitialized transports"). Get rid of the unused function. Change-Id: I79dd1d55bd54ed8edc39ed3443e6c3c01794f063 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5898 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/transport/transport.c | 10 ---------- src/transport/transport.h | 2 -- 2 files changed, 12 deletions(-) diff --git a/src/transport/transport.c b/src/transport/transport.c index 9214dcd77..cb000ab11 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -121,16 +121,6 @@ int allow_transports(struct command_context *ctx, const char * const *vector) return ERROR_OK; } -/** - * Used to verify correct adapter driver initialization. - * - * @returns true if the adapter declares one or more transports. - */ -bool transports_are_declared(void) -{ - return allowed_transports != NULL; -} - /** * Registers a transport. There are general purpose transports * (such as JTAG), as well as relatively proprietary ones which are diff --git a/src/transport/transport.h b/src/transport/transport.h index 809564e78..e04f78063 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -92,8 +92,6 @@ COMMAND_HELPER(transport_list_parse, char ***vector); int allow_transports(struct command_context *ctx, const char * const *vector); -bool transports_are_declared(void); - bool transport_is_jtag(void); bool transport_is_swd(void); bool transport_is_dapdirect_jtag(void); From 61f872311c6051c5aab2834195bceb7482caf2e9 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 23:44:07 +0100 Subject: [PATCH 040/113] rtos: make private the API rtos_try_next() The function rtos_try_next() is only used internally. Make it private. Change-Id: I68c6b8d8e6bbf3d674b0e0199e63bc02d358c04e Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5899 Tested-by: jenkins --- src/rtos/rtos.c | 4 +++- src/rtos/rtos.h | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index 62b65aae1..d9ba735f2 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -57,6 +57,8 @@ static struct rtos_type *rtos_types[] = { NULL }; +static int rtos_try_next(struct target *target); + int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size); int rtos_smp_init(struct target *target) @@ -629,7 +631,7 @@ int rtos_generic_stack_read(struct target *target, return ERROR_OK; } -int rtos_try_next(struct target *target) +static int rtos_try_next(struct target *target) { struct rtos *os = target->rtos; struct rtos_type **type = rtos_types; diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index c755eec29..b437be0dd 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -119,7 +119,6 @@ int rtos_generic_stack_read(struct target *target, int64_t stack_ptr, struct rtos_reg **reg_list, int *num_regs); -int rtos_try_next(struct target *target); int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size); int rtos_get_gdb_reg(struct connection *connection, int reg_num); int rtos_get_gdb_reg_list(struct connection *connection); From 9d50f3f3afe1df4457602407c46fc158e7f8f64f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 28 Oct 2020 23:48:57 +0100 Subject: [PATCH 041/113] cortex_m: declare local functions as static Functions that are not used outside the file should be declared as static. Change-Id: Ie81f6bdce91e2a1456364b47f30aa4d35c7ee7bc Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5900 Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI Tested-by: jenkins --- src/target/cortex_m.c | 6 +++--- src/target/cortex_m.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 503995a5d..08b3661ea 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1413,7 +1413,7 @@ int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpo return cortex_m_unset_breakpoint(target, breakpoint); } -int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) +static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int dwt_num = 0; struct cortex_m_common *cortex_m = target_to_cm(target); @@ -1496,7 +1496,7 @@ int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint return ERROR_OK; } -int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) +static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m_common *cortex_m = target_to_cm(target); struct cortex_m_dwt_comparator *comparator; @@ -1989,7 +1989,7 @@ static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dw r->type = &dwt_reg_type; } -void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) +static void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target) { uint32_t dwtcr; struct reg_cache *cache; diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 415a6c22f..b470fbd70 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -233,13 +233,10 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); -int cortex_m_set_watchpoint(struct target *target, struct watchpoint *watchpoint); -int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void cortex_m_enable_breakpoints(struct target *target); void cortex_m_enable_watchpoints(struct target *target); -void cortex_m_dwt_setup(struct cortex_m_common *cm, struct target *target); void cortex_m_deinit_target(struct target *target); int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); From c8628541ae64e954bd72628666b22660d61c5335 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 29 Oct 2020 01:34:37 +0100 Subject: [PATCH 042/113] target/adi_v5_jtag: remove unused global variable Change-Id: Ia4e8b90359c23f4be1d3677b44b0ebd063bb8dcc Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5901 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/adi_v5_jtag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index c2100eb47..6dede972c 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -145,7 +145,7 @@ struct dap_cmd { struct dap_cmd_pool { struct list_head lh; struct dap_cmd cmd; -} dap_cmd_pool; +}; static void log_dap_cmd(const char *header, struct dap_cmd *el) { From 72a1010c9f60c75faa051cf2033c62b11fa42fcf Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 29 Oct 2020 14:51:33 +0100 Subject: [PATCH 043/113] openocd: convert function setup_command_handler() to static The function setup_command_handler() was used in the eCos build of OpenOCD, thus it was exported and a comment was added to remark it should remain not-static. Unfortunately the comment was missing the relevant information of the special build that requires so. Also unusual is that there is no include file that declares the prototype of the function. The comment above the function was added in two steps, in commit ea3e49f4e22d ("fix embedded builds") and commit fb96b8607a0c ("openocd: setup_command_handler() must not be static"), again without info about the special build. Also the mailing list archive does not report any further detail. The only hint is in the first commit above that also adds a test on BUILD_ECOSBOARD in a #if. Commit 39650e2273bc ("ecosboard: delete bit-rotted eCos code") removes all the eCos code, that effectively includes the both the prototype and the call to the function setup_command_handler(), http://openocd.zylin.com/#/c/503/2/src/ecosboard.c@a1092 but did not reverted the function to static. With all the 'external' uses of this function being dropped, set the function setup_command_handler() to static and remove the obsoleted and misleading comment. Change-Id: I4d6b83dec2a838119821189fc67949bfca070035 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5902 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/openocd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/openocd.c b/src/openocd.c index 886228425..604b36d21 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -230,10 +230,7 @@ static int openocd_register_commands(struct command_context *cmd_ctx) struct command_context *global_cmd_ctx; -/* NB! this fn can be invoked outside this file for non PC hosted builds - * NB! do not change to 'static'!!!! - */ -struct command_context *setup_command_handler(Jim_Interp *interp) +static struct command_context *setup_command_handler(Jim_Interp *interp) { log_init(); LOG_DEBUG("log_init: complete"); From 7e6556b3cad8c82d4670a68cd49756dabb8c4729 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Tue, 9 Jun 2020 00:15:49 +0100 Subject: [PATCH 044/113] server: permit the add_service function to return the created service returning the created service seems useful: as the only method to get the freshly created service is by getting the last item in the services linked list, and this seems to be like an intrusion to service internal mechanism. possibly, we could get the service from a connection but this is possible only from [new_connection|input|connection_closed]_handler_t, but this is not always practical: example: armv7m: add a TCP channel to stream captured trace http://openocd.zylin.com/#/c/5345/ here we poll for trace and broadcast to all connections outside of these xxx_handler_t functions also, storing one of the connections in new_connection_handler_t and get the service from it is possible, but this will make the code less readable. Change-Id: I5fef1baecec1e054953c6faf5b99d864ecc97f02 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5717 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/server/gdb_server.c | 2 +- src/server/server.c | 7 ++++++- src/server/server.h | 2 +- src/server/tcl_server.c | 2 +- src/server/telnet_server.c | 2 +- src/target/openrisc/jsp_server.c | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c96be1034..bb4c1317d 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -3509,7 +3509,7 @@ static int gdb_target_start(struct target *target, const char *port) ret = add_service("gdb", port, target->gdb_max_connections, &gdb_new_connection, &gdb_input, - &gdb_connection_closed, gdb_service); + &gdb_connection_closed, gdb_service, NULL); /* initialize all targets gdb service with the same pointer */ { struct target_list *head; diff --git a/src/server/server.c b/src/server/server.c index e53f37d0b..114af7632 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -210,7 +210,8 @@ int add_service(char *name, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, - void *priv) + void *priv, + struct service **new_service) { struct service *c, **p; struct hostent *hp; @@ -346,6 +347,10 @@ int add_service(char *name, ; *p = c; + /* if new_service is not NULL, return the created service into it */ + if (new_service) + *new_service = c; + return ERROR_OK; } diff --git a/src/server/server.h b/src/server/server.h index ff2ada9cb..99f5fe2ed 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -77,7 +77,7 @@ struct service { int add_service(char *name, const char *port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t in_handler, connection_closed_handler_t close_handler, - void *priv); + void *priv, struct service **new_service); int remove_service(const char *name, const char *port); int server_host_os_entry(void); diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c index 1ecb827a1..07213ae79 100644 --- a/src/server/tcl_server.c +++ b/src/server/tcl_server.c @@ -285,7 +285,7 @@ int tcl_init(void) return add_service("tcl", tcl_port, CONNECTION_LIMIT_UNLIMITED, &tcl_new_connection, &tcl_input, - &tcl_closed, NULL); + &tcl_closed, NULL, NULL); } COMMAND_HANDLER(handle_tcl_port_command) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 407ab68ae..4f88d3a54 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -694,7 +694,7 @@ int telnet_init(char *banner) int ret = add_service("telnet", telnet_port, CONNECTION_LIMIT_UNLIMITED, telnet_new_connection, telnet_input, telnet_connection_closed, - telnet_service); + telnet_service, NULL); if (ret != ERROR_OK) { free(telnet_service); diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 4dbe63527..b4b25665d 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -207,7 +207,8 @@ int jsp_init(struct or1k_jtag *jtag_info, char *banner) jsp_new_connection, jsp_input, jsp_connection_closed, - jsp_service); + jsp_service, + NULL); } COMMAND_HANDLER(handle_jsp_port_command) From 9cce6b3c763e883faea545b9ffbda19ec8164804 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 8 Jun 2020 23:47:46 +0100 Subject: [PATCH 045/113] armv7m: add a TCP channel to stream captured trace When trace capturing the trace is enabled using 'tpiu_config internal' (via the internal mode), OpenOCD can collect the trace buffers then append it to a specified file or named pipe and propagate the trace to 'tcl_trace' command. This change is allowing OpenOCD to stream the captured trace over TCP. When using this configuration OpenOCD acts like a server and multiple clients can connect and receive the captured trace. Example on STM32F7 running at 216MHz: itm port 0 on tpiu config internal :3344 uart off 216000000 Change-Id: Idea43e7e26e87b98a33da7fb9acf7ea50fe3b345 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5345 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Antonio Borneo --- doc/openocd.texi | 29 +++++---- src/target/armv7m_trace.c | 123 ++++++++++++++++++++++++++++++++------ src/target/armv7m_trace.h | 16 ++++- 3 files changed, 137 insertions(+), 31 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index e6a14673f..b01e5a6c1 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9206,7 +9206,7 @@ Selects whether interrupts will be processed when single stepping @cindex ITM @cindex ETM -@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | -)}) @ +@deffn Command {tpiu config} (@option{disable} | ((@option{external} | @option{internal (@var{filename} | @var{:port} | -)}) @ (@option{sync @var{port_width}} | ((@option{manchester} | @option{uart}) @var{formatter_enable})) @ @var{TRACECLKIN_freq} [@var{trace_freq}])) @@ -9226,23 +9226,28 @@ Command options: @itemize @minus @item @option{disable} disable TPIU handling; @item @option{external} configure TPIU to let user capture trace -output externally (with an additional UART or logic analyzer hardware); -@item @option{internal @var{filename}} configure TPIU and debug adapter to -gather trace data and append it to @var{filename} (which can be -either a regular file or a named pipe); -@item @option{internal -} configure TPIU and debug adapter to -gather trace data, but not write to any file. Useful in conjunction with the @command{tcl_trace} command; +output externally (with an additional UART or logic analyzer hardware). +@item @option{internal (@var{filename} | @var{:port} | -)} configure TPIU and debug adapter to +gather trace data then: + +@itemize @minus +@item append it to a regular file or a named pipe if @var{filename} is specified. +@item listen to a TCP/IP port if @var{:port} is specified, then broadcast the trace data over this port. +@item if '-' is specified, OpenOCD will forward trace data to @command{tcl_trace} command. +@*@b{Note:} while broadcasting to file or TCP, the forwarding to @command{tcl_trace} will remain active. +@end itemize + @item @option{sync @var{port_width}} use synchronous parallel trace output -mode, and set port width to @var{port_width}; +mode, and set port width to @var{port_width}. @item @option{manchester} use asynchronous SWO mode with Manchester -coding; +coding. @item @option{uart} use asynchronous SWO mode with NRZ (same as -regular UART 8N1) coding; +regular UART 8N1) coding. @item @var{formatter_enable} is @option{on} or @option{off} to enable or disable TPIU formatter which needs to be used when both ITM and ETM -data is to be output via SWO; +data is to be output via SWO. @item @var{TRACECLKIN_freq} this should be specified to match target's -current TRACECLKIN frequency (usually the same as HCLK); +current TRACECLKIN frequency (usually the same as HCLK). @item @var{trace_freq} trace port frequency. Can be omitted in internal mode to let the adapter driver select the maximum supported rate automatically. diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 6b368f7a0..916d1a164 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -40,13 +40,43 @@ static int armv7m_poll_trace(void *target) target_call_trace_callbacks(target, size, buf); - if (armv7m->trace_config.trace_file != NULL) { - if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size) - fflush(armv7m->trace_config.trace_file); - else { - LOG_ERROR("Error writing to the trace destination file"); - return ERROR_FAIL; + switch (armv7m->trace_config.internal_channel) { + case TRACE_INTERNAL_CHANNEL_FILE: + if (armv7m->trace_config.trace_file != NULL) { + if (fwrite(buf, 1, size, armv7m->trace_config.trace_file) == size) + fflush(armv7m->trace_config.trace_file); + else { + LOG_ERROR("Error writing to the trace destination file"); + return ERROR_FAIL; + } } + break; + case TRACE_INTERNAL_CHANNEL_TCP: + if (armv7m->trace_config.trace_service != NULL) { + /* broadcast to all service connections */ + struct connection *connection = armv7m->trace_config.trace_service->connections; + retval = ERROR_OK; + while (connection) { + if (connection_write(connection, buf, size) != (int) size) + retval = ERROR_FAIL; + + connection = connection->next; + } + + if (retval != ERROR_OK) { + LOG_ERROR("Error streaming the trace to TCP/IP port"); + return ERROR_FAIL; + } + } + break; + case TRACE_INTERNAL_CHANNEL_TCL_ONLY: + /* nothing to do : + * the trace data is sent to TCL by calling the target_call_trace_callbacks + **/ + break; + default: + LOG_ERROR("unsupported trace internal channel"); + return ERROR_FAIL; } return ERROR_OK; @@ -152,11 +182,56 @@ int armv7m_trace_itm_config(struct target *target) return ERROR_OK; } -static void close_trace_file(struct armv7m_common *armv7m) +static void close_trace_channel(struct armv7m_common *armv7m) { - if (armv7m->trace_config.trace_file) - fclose(armv7m->trace_config.trace_file); - armv7m->trace_config.trace_file = NULL; + switch (armv7m->trace_config.internal_channel) { + case TRACE_INTERNAL_CHANNEL_FILE: + if (armv7m->trace_config.trace_file) + fclose(armv7m->trace_config.trace_file); + armv7m->trace_config.trace_file = NULL; + break; + case TRACE_INTERNAL_CHANNEL_TCP: + if (armv7m->trace_config.trace_service) + remove_service(armv7m->trace_config.trace_service->name, armv7m->trace_config.trace_service->port); + armv7m->trace_config.trace_service = NULL; + break; + case TRACE_INTERNAL_CHANNEL_TCL_ONLY: + /* nothing to do: + * the trace polling is disabled in the beginning of armv7m_trace_tpiu_config + **/ + break; + default: + LOG_ERROR("unsupported trace internal channel"); + } +} + +static int trace_new_connection(struct connection *connection) +{ + /* nothing to do */ + return ERROR_OK; +} + +static int trace_input(struct connection *connection) +{ + /* create a dummy buffer to check if the connection is still active */ + const int buf_len = 100; + unsigned char buf[buf_len]; + int bytes_read = connection_read(connection, buf, buf_len); + + if (bytes_read == 0) + return ERROR_SERVER_REMOTE_CLOSED; + else if (bytes_read == -1) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + return ERROR_OK; +} + +static int trace_connection_closed(struct connection *connection) +{ + /* nothing to do, no connection->priv to free */ + return ERROR_OK; } COMMAND_HANDLER(handle_tpiu_config_command) @@ -170,7 +245,7 @@ COMMAND_HANDLER(handle_tpiu_config_command) return ERROR_COMMAND_SYNTAX_ERROR; if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { if (CMD_ARGC == cmd_idx + 1) { - close_trace_file(armv7m); + close_trace_channel(armv7m); armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; if (CMD_CTX->mode == COMMAND_EXEC) @@ -180,7 +255,7 @@ COMMAND_HANDLER(handle_tpiu_config_command) } } else if (!strcmp(CMD_ARGV[cmd_idx], "external") || !strcmp(CMD_ARGV[cmd_idx], "internal")) { - close_trace_file(armv7m); + close_trace_channel(armv7m); armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_EXTERNAL; if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { @@ -189,12 +264,26 @@ COMMAND_HANDLER(handle_tpiu_config_command) return ERROR_COMMAND_SYNTAX_ERROR; armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_INTERNAL; + armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCL_ONLY; if (strcmp(CMD_ARGV[cmd_idx], "-") != 0) { - armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); - if (!armv7m->trace_config.trace_file) { - LOG_ERROR("Can't open trace destination file"); - return ERROR_FAIL; + if (CMD_ARGV[cmd_idx][0] == ':') { + armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_TCP; + + int ret = add_service("armv7m_trace", &(CMD_ARGV[cmd_idx][1]), + CONNECTION_LIMIT_UNLIMITED, trace_new_connection, trace_input, + trace_connection_closed, NULL, &armv7m->trace_config.trace_service); + if (ret != ERROR_OK) { + LOG_ERROR("Can't configure trace TCP port"); + return ERROR_FAIL; + } + } else { + armv7m->trace_config.internal_channel = TRACE_INTERNAL_CHANNEL_FILE; + armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); + if (!armv7m->trace_config.trace_file) { + LOG_ERROR("Can't open trace destination file"); + return ERROR_FAIL; + } } } } @@ -306,7 +395,7 @@ static const struct command_registration tpiu_command_handlers[] = { .mode = COMMAND_ANY, .help = "Configure TPIU features", .usage = "(disable | " - "((external | internal ) " + "((external | internal ( | <:port> | -)) " "(sync | ((manchester | uart) )) " " []))", }, diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index e5879fb08..076f9d582 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -18,6 +18,7 @@ #ifndef OPENOCD_TARGET_ARMV7M_TRACE_H #define OPENOCD_TARGET_ARMV7M_TRACE_H +#include #include #include @@ -32,8 +33,14 @@ enum trace_config_type { TRACE_CONFIG_TYPE_INTERNAL /**< trace output is handled by OpenOCD adapter driver */ }; +enum trace_internal_channel { + TRACE_INTERNAL_CHANNEL_TCL_ONLY, /** trace data is sent only to 'tcl_trace' */ + TRACE_INTERNAL_CHANNEL_FILE, /** trace data is appended to a file */ + TRACE_INTERNAL_CHANNEL_TCP /** trace data is appended to a TCP/IP port*/ +}; + enum tpiu_pin_protocol { - TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */ + TPIU_PIN_PROTOCOL_SYNC, /**< synchronous trace output */ TPIU_PIN_PROTOCOL_ASYNC_MANCHESTER, /**< asynchronous output with Manchester coding */ TPIU_PIN_PROTOCOL_ASYNC_UART /**< asynchronous output with NRZ coding */ }; @@ -49,6 +56,9 @@ struct armv7m_trace_config { /** Currently active trace capture mode */ enum trace_config_type config_type; + /** The used channel when internal mode is selected */ + enum trace_internal_channel internal_channel; + /** Currently active trace output mode */ enum tpiu_pin_protocol pin_protocol; /** TPIU formatter enable/disable (in async mode) */ @@ -73,8 +83,10 @@ struct armv7m_trace_config { unsigned int traceclkin_freq; /** Current frequency of trace port */ unsigned int trace_freq; - /** Handle to output trace data in INTERNAL capture mode */ + /** Handle to output trace data in INTERNAL capture mode via file */ FILE *trace_file; + /** Handle to output trace data in INTERNAL capture mode via tcp */ + struct service *trace_service; }; extern const struct command_registration armv7m_trace_command_handlers[]; From 850e85fa6fec275cb9f2bc76faefee51136e878e Mon Sep 17 00:00:00 2001 From: Adrian Negreanu Date: Thu, 5 Nov 2020 11:56:16 +0200 Subject: [PATCH 046/113] semihosting: print the semihosting operation id Change-Id: If5c3568bd1c99a48ac492137f48da0d9764efe14 Signed-off-by: Adrian Negreanu Reviewed-on: http://openocd.zylin.com/5923 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Jonathan McDowell Reviewed-by: Tim Newsome --- src/target/arm_semihosting.c | 2 +- src/target/riscv/riscv_semihosting.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 61f1e7801..723be577e 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -315,7 +315,7 @@ int arm_semihosting(struct target *target, int *retval) if (0 <= semihosting->op && semihosting->op <= 0x31) { *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation"); + LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); return 0; } } else { diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 99d6c7713..c0e81eae4 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -140,7 +140,7 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) if (0 <= semihosting->op && semihosting->op <= 0x31) { *retval = semihosting_common(target); if (*retval != ERROR_OK) { - LOG_ERROR("Failed semihosting operation"); + LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); return SEMI_ERROR; } } else { From 8e281b76ea26f5da79875ad927c4660fb7b1502b Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 3 Nov 2020 13:38:59 +0100 Subject: [PATCH 047/113] doc: Improve 'jlink usb' description Change-Id: Ica44980ac0ba8a4f0ff03b42ce37d1de861d4fb5 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/5918 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index b01e5a6c1..ee7186746 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2881,8 +2881,8 @@ The following example shows how to read 4 bytes from the EMUCOM channel 0x0: @deffn {Config} {jlink usb} <@option{0} to @option{3}> Set the USB address of the interface, in case more than one adapter is connected to the host. If not specified, USB addresses are not considered. Device -selection via USB address is deprecated and the serial number should be used -instead. +selection via USB address is not always unambiguous. It is recommended to use +the serial number instead, if possible. As a configuration command, it can be used only before 'init'. @end deffn From 990a01b70203a512b120e562dd991c29ee9201b2 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 1 Nov 2020 12:10:23 +0000 Subject: [PATCH 048/113] tcl/interface/ftdi: Add HIE JTAG Debugger config Change-Id: Ibb7a2bb8807c442394982e89258874557a2baaad Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/5910 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/interface/ftdi/hie-jtag.cfg | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tcl/interface/ftdi/hie-jtag.cfg diff --git a/tcl/interface/ftdi/hie-jtag.cfg b/tcl/interface/ftdi/hie-jtag.cfg new file mode 100644 index 000000000..39af87d89 --- /dev/null +++ b/tcl/interface/ftdi/hie-jtag.cfg @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Hofstädtler Industrie-Electronic (HIE) JTAG Debugger +# +# https://www.hofstaedtler.com/jtag +# + +adapter driver ftdi +ftdi_channel 0 +ftdi_vid_pid 0x0403 0x6014 +ftdi_device_desc "HIE JTAG Debugger" + +ftdi_layout_init 0x0c08 0x4f1b + +# define both Reset signals +ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400 +ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800 + +# Toggle USB LED +ftdi_layout_signal LED -ndata 0x4000 From 25e1c0f4c054eef25d1b9ad2507ee33faa05b345 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 2 Nov 2020 16:12:11 +0100 Subject: [PATCH 049/113] contrib/cross-build.sh: build capstone from source tested with capstone 4.0.2, with the following options CAPSTONE_CONFIG="CAPSTONE_ARCHS=arm,aarch64 CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" Change-Id: I40297772664e85c3d0f9358c85bfd901b5eba8b1 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5914 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/cross-build.sh | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/contrib/cross-build.sh b/contrib/cross-build.sh index 821d48ec7..8b31a3f00 100755 --- a/contrib/cross-build.sh +++ b/contrib/cross-build.sh @@ -14,8 +14,8 @@ # paths refer to the build file system. # # This script is probably more useful as a reference than as a complete build -# tool but for some configurations it may be usable as-is. It only cross- -# builds libusb-1.0, hidapi and libftdi from source, but the script can be +# tool but for some configurations it may be usable as-is. It only cross-builds +# libusb-1.0, hidapi, libftdi and capstone from source, but the script can be # extended to build other prerequisites in a similar manner. # # Usage: @@ -39,17 +39,20 @@ WORK_DIR=$PWD : ${LIBUSB1_SRC:=/path/to/libusb1} : ${HIDAPI_SRC:=/path/to/hidapi} : ${LIBFTDI_SRC:=/path/to/libftdi} +: ${CAPSTONE_SRC:=/path/to/capstone} OPENOCD_SRC=`readlink -m $OPENOCD_SRC` LIBUSB1_SRC=`readlink -m $LIBUSB1_SRC` HIDAPI_SRC=`readlink -m $HIDAPI_SRC` LIBFTDI_SRC=`readlink -m $LIBFTDI_SRC` +CAPSTONE_SRC=`readlink -m $CAPSTONE_SRC` HOST_TRIPLET=$1 BUILD_DIR=$WORK_DIR/$HOST_TRIPLET-build LIBUSB1_BUILD_DIR=$BUILD_DIR/libusb1 HIDAPI_BUILD_DIR=$BUILD_DIR/hidapi LIBFTDI_BUILD_DIR=$BUILD_DIR/libftdi +CAPSTONE_BUILD_DIR=$BUILD_DIR/capstone OPENOCD_BUILD_DIR=$BUILD_DIR/openocd ## Root of host file tree @@ -129,6 +132,26 @@ if [ -d $LIBFTDI_SRC ] ; then make install DESTDIR=$SYSROOT fi +# capstone build & install into sysroot +if [ -d $CAPSTONE_SRC ] ; then + mkdir -p $CAPSTONE_BUILD_DIR + cd $CAPSTONE_BUILD_DIR + cp -r $CAPSTONE_SRC/* . + make install DESTDIR=$SYSROOT PREFIX=$PREFIX \ + CROSS="${HOST_TRIPLET}-" \ + $CAPSTONE_CONFIG + # fix the generated capstone.pc + CAPSTONE_PC_FILE=${SYSROOT}${PREFIX}/lib/pkgconfig/capstone.pc + sed -i '/^libdir=/d' $CAPSTONE_PC_FILE + sed -i '/^includedir=/d' $CAPSTONE_PC_FILE + sed -i '/^archive=/d' $CAPSTONE_PC_FILE + sed -i '1s;^;prefix=/usr \ +exec_prefix=${prefix} \ +libdir=${exec_prefix}/lib \ +includedir=${prefix}/include\n\n;' $CAPSTONE_PC_FILE +fi + + # OpenOCD build & install into sysroot mkdir -p $OPENOCD_BUILD_DIR cd $OPENOCD_BUILD_DIR From 2edcb065d45b7f0ee8adf260c792e0c2f3829a60 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 2 Nov 2020 12:58:15 +0100 Subject: [PATCH 050/113] Github: add capstone in windows snapshots Change-Id: I402c18ff72de715ce4012bce3df72aaed7159d50 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5915 Tested-by: jenkins Reviewed-by: Antonio Borneo --- .github/workflows/snapshot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 2b73f9c8c..123ee66bd 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -43,6 +43,16 @@ jobs: wget "http://www.intra2net.com/en/developer/libftdi/download/libftdi1-${LIBFTDI_VER}.tar.bz2" tar -xjf libftdi1-${LIBFTDI_VER}.tar.bz2 echo "::set-env name=LIBFTDI_SRC::$PWD/libftdi1-${LIBFTDI_VER}" + - name: Prepare capstone + env: + CAPSTONE_VER: 4.0.2 + run: | + mkdir -p $DL_DIR && cd $DL_DIR + CAPSTONE_NAME=${CAPSTONE_VER} + CAPSTONE_FOLDER=capstone-${CAPSTONE_VER} + wget "https://github.com/aquynh/capstone/archive/${CAPSTONE_VER}.tar.gz" + tar -xzf ${CAPSTONE_VER}.tar.gz + echo "CAPSTONE_SRC=$PWD/capstone-${CAPSTONE_VER}" >> $GITHUB_ENV - name: Package OpenOCD for windows env: MAKE_JOBS: 2 @@ -50,6 +60,7 @@ jobs: LIBUSB1_CONFIG: --enable-shared --enable-static HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui LIBFTDI_CONFIG: "-DCMAKE_TOOLCHAIN_FILE='${{ env.LIBFTDI_SRC }}/cmake/Toolchain-i686-w64-mingw32.cmake' -DBUILD_TESTS:BOOL=off -DFTDIPP:BOOL=off -DPYTHON_BINDINGS:BOOL=off -DEXAMPLES:BOOL=off -DDOCUMENTATION:BOOL=off -DFTDI_EEPROM:BOOL=off" + CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" run: | # set snapshot tag OPENOCD_TAG="`git tag --points-at HEAD`" From 6dbfdcd00f190b79f24a7c231137fb5eea52bc95 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Mon, 2 Nov 2020 16:31:27 +0100 Subject: [PATCH 051/113] GitHub/WorkFlow: fix for CVE-2020-15228 According the CVE-2020-15228 documented in: - https://github.com/advisories/GHSA-mfwh-5m23-j46w - https://nvd.nist.gov/vuln/detail/CVE-2020-15228 the `set-env` commands will be disabled in the near future and should be replaced by: echo "FOO=BAR" >> $GITHUB_ENV idem for `add-path`, should be replaced by: echo "/path/to/add" >> $GITHUB_PATH Change-Id: I725c9ccd861a0d1580ac22491b6d716ec65973d1 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5866 Tested-by: jenkins Reviewed-by: Antonio Borneo --- .github/workflows/snapshot.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 123ee66bd..e9a95ffb5 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -24,7 +24,7 @@ jobs: mkdir -p $DL_DIR && cd $DL_DIR wget "https://github.com/libusb/libusb/releases/download/v${LIBUSB1_VER}/libusb-${LIBUSB1_VER}.tar.bz2" tar -xjf libusb-${LIBUSB1_VER}.tar.bz2 - echo "::set-env name=LIBUSB1_SRC::$PWD/libusb-${LIBUSB1_VER}" + echo "LIBUSB1_SRC=$PWD/libusb-${LIBUSB1_VER}" >> $GITHUB_ENV - name: Prepare hidapi env: HIDAPI_VER: 0.9.0 @@ -34,7 +34,7 @@ jobs: tar -xzf hidapi-${HIDAPI_VER}.tar.gz cd hidapi-hidapi-${HIDAPI_VER} ./bootstrap - echo "::set-env name=HIDAPI_SRC::$PWD" + echo "HIDAPI_SRC=$PWD" >> $GITHUB_ENV - name: Prepare libftdi env: LIBFTDI_VER: 1.4 @@ -42,7 +42,7 @@ jobs: mkdir -p $DL_DIR && cd $DL_DIR wget "http://www.intra2net.com/en/developer/libftdi/download/libftdi1-${LIBFTDI_VER}.tar.bz2" tar -xjf libftdi1-${LIBFTDI_VER}.tar.bz2 - echo "::set-env name=LIBFTDI_SRC::$PWD/libftdi1-${LIBFTDI_VER}" + echo "LIBFTDI_SRC=$PWD/libftdi1-${LIBFTDI_VER}" >> $GITHUB_ENV - name: Prepare capstone env: CAPSTONE_VER: 4.0.2 @@ -78,8 +78,8 @@ jobs: # prepare the artifact ARTIFACT="openocd-${OPENOCD_TAG}-${HOST}.tar.gz" tar -czf $ARTIFACT * - echo "::set-env name=ARTIFACT_NAME::$ARTIFACT" - echo "::set-env name=ARTIFACT_PATH::$PWD/$ARTIFACT" + echo "ARTIFACT_NAME=$ARTIFACT" >> $GITHUB_ENV + echo "ARTIFACT_PATH=$PWD/$ARTIFACT" >> $GITHUB_ENV - name: Publish OpenOCD packaged for windows uses: actions/upload-artifact@v1 with: From 73746d78b7bd582bab26cebdcf78299b8da99a62 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Tue, 3 Nov 2020 16:11:48 +0100 Subject: [PATCH 052/113] target/image: Use proper data types While at it, fix some coding style issues. Change-Id: Id521394d89e0bf787a6f812701c2cc0fe7e4e63f Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/5919 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/core.c | 8 +++--- src/flash/nor/lpc2900.c | 4 +-- src/flash/nor/tcl.c | 6 ++--- src/jtag/drivers/ulink.c | 6 ++--- .../usb_blaster/ublast2_access_libusb.c | 4 +-- src/target/etm.c | 11 ++++---- src/target/image.c | 21 ++++++---------- src/target/image.h | 6 ++--- src/target/target.c | 25 ++++++++----------- src/target/xscale.c | 11 ++++---- 10 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index d56301351..6182a5f82 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -702,7 +702,7 @@ int flash_write_unlock(struct target *target, struct image *image, { int retval = ERROR_OK; - int section; + unsigned int section; uint32_t section_offset; struct flash_bank *c; int *padding; @@ -727,8 +727,8 @@ int flash_write_unlock(struct target *target, struct image *image, * whereas an image can have sections out of order. */ struct imagesection **sections = malloc(sizeof(struct imagesection *) * image->num_sections); - int i; - for (i = 0; i < image->num_sections; i++) + + for (unsigned int i = 0; i < image->num_sections; i++) sections[i] = &image->sections[i]; qsort(sections, image->num_sections, sizeof(struct imagesection *), @@ -738,7 +738,7 @@ int flash_write_unlock(struct target *target, struct image *image, while (section < image->num_sections) { uint32_t buffer_idx; uint8_t *buffer; - int section_last; + unsigned int section_last; target_addr_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; diff --git a/src/flash/nor/lpc2900.c b/src/flash/nor/lpc2900.c index c8e885aba..6596cde94 100644 --- a/src/flash/nor/lpc2900.c +++ b/src/flash/nor/lpc2900.c @@ -635,9 +635,9 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command) /* The image will always start at offset 0 */ struct image image; - image.base_address_set = 1; + image.base_address_set = true; image.base_address = 0; - image.start_address_set = 0; + image.start_address_set = false; const char *filename = CMD_ARGV[1]; const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL; diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 386d73e39..87c8cede7 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -441,14 +441,14 @@ COMMAND_HANDLER(handle_flash_write_image_command) duration_start(&bench); if (CMD_ARGC >= 2) { - image.base_address_set = 1; + image.base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); } else { - image.base_address_set = 0; + image.base_address_set = false; image.base_address = 0x0; } - image.start_address_set = 0; + image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 4bc605171..fd08c1661 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -393,7 +393,7 @@ static int ulink_load_firmware_and_renumerate(struct ulink **device, static int ulink_load_firmware(struct ulink *device, const char *filename) { struct image ulink_firmware_image; - int ret, i; + int ret; ret = ulink_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { @@ -402,7 +402,7 @@ static int ulink_load_firmware(struct ulink *device, const char *filename) } ulink_firmware_image.base_address = 0; - ulink_firmware_image.base_address_set = 0; + ulink_firmware_image.base_address_set = false; ret = image_open(&ulink_firmware_image, filename, "ihex"); if (ret != ERROR_OK) { @@ -411,7 +411,7 @@ static int ulink_load_firmware(struct ulink *device, const char *filename) } /* Download all sections in the image to ULINK */ - for (i = 0; i < ulink_firmware_image.num_sections; i++) { + for (unsigned int i = 0; i < ulink_firmware_image.num_sections; i++) { ret = ulink_write_firmware_section(device, &ulink_firmware_image, i); if (ret != ERROR_OK) return ret; diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index f8ff66e2f..6f15fa70a 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -134,7 +134,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, } ublast2_firmware_image.base_address = 0; - ublast2_firmware_image.base_address_set = 0; + ublast2_firmware_image.base_address_set = false; int ret = image_open(&ublast2_firmware_image, low->firmware_path, "ihex"); if (ret != ERROR_OK) { @@ -162,7 +162,7 @@ static int load_usb_blaster_firmware(struct libusb_device_handle *libusb_dev, 100); /* Download all sections in the image to ULINK */ - for (int i = 0; i < ublast2_firmware_image.num_sections; i++) { + for (unsigned int i = 0; i < ublast2_firmware_image.num_sections; i++) { ret = ublast2_write_firmware_section(libusb_dev, &ublast2_firmware_image, i); if (ret != ERROR_OK) { diff --git a/src/target/etm.c b/src/target/etm.c index 5d079ffa8..93dbd2948 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -650,7 +650,6 @@ static struct etm_capture_driver *etm_capture_drivers[] = { static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction *instruction) { - int i; int section = -1; size_t size_read; uint32_t opcode; @@ -660,7 +659,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ - for (i = 0; i < ctx->image->num_sections; i++) { + for (unsigned int i = 0; i < ctx->image->num_sections; i++) { if ((ctx->image->sections[i].base_address <= ctx->current_pc) && (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) { @@ -1683,15 +1682,15 @@ COMMAND_HANDLER(handle_etm_image_command) } etm_ctx->image = malloc(sizeof(struct image)); - etm_ctx->image->base_address_set = 0; - etm_ctx->image->start_address_set = 0; + etm_ctx->image->base_address_set = false; + etm_ctx->image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - etm_ctx->image->base_address_set = 1; + etm_ctx->image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], etm_ctx->image->base_address); } else - etm_ctx->image->base_address_set = 0; + etm_ctx->image->base_address_set = false; if (image_open(etm_ctx->image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { diff --git a/src/target/image.c b/src/target/image.c index 8160e5f92..0b7debaef 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -124,7 +124,6 @@ static int image_ihex_buffer_complete_inner(struct image *image, uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; - int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ @@ -207,7 +206,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; @@ -294,7 +293,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, cal_checksum += (uint8_t)start_address; bytes_read += 8; - image->start_address_set = 1; + image->start_address_set = true; image->start_address = be_to_h_u32((uint8_t *)&start_address); } else { LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); @@ -471,7 +470,7 @@ static int image_elf_read_headers(struct image *image) } } - image->start_address_set = 1; + image->start_address_set = true; image->start_address = field32(elf, elf->header->e_entry); return ERROR_OK; @@ -529,7 +528,6 @@ static int image_mot_buffer_complete_inner(struct image *image, uint32_t full_address; uint32_t cooked_bytes; bool end_rec = false; - int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ @@ -658,7 +656,7 @@ static int image_mot_buffer_complete_inner(struct image *image, /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; @@ -821,21 +819,20 @@ int image_open(struct image *image, const char *url, const char *type_string) } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; - image->base_address_set = 0; + image->base_address_set = false; image->sections = NULL; image->type_private = NULL; } if (image->base_address_set) { /* relocate */ - int section; - for (section = 0; section < image->num_sections; section++) + for (unsigned int section = 0; section < image->num_sections; section++) image->sections[section].base_address += image->base_address; /* we're done relocating. The two statements below are mainly * for documentation purposes: stop anyone from empirically * thinking they should use these values henceforth. */ image->base_address = 0; - image->base_address_set = 0; + image->base_address_set = false; } return retval; @@ -1009,9 +1006,7 @@ void image_close(struct image *image) free(image_mot->buffer); image_mot->buffer = NULL; } else if (image->type == IMAGE_BUILDER) { - int i; - - for (i = 0; i < image->num_sections; i++) { + for (unsigned int i = 0; i < image->num_sections; i++) { free(image->sections[i].private); image->sections[i].private = NULL; } diff --git a/src/target/image.h b/src/target/image.h index 9907a5f3f..765d29022 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -55,11 +55,11 @@ struct imagesection { struct image { enum image_type type; /* image type (plain, ihex, ...) */ void *type_private; /* type private data */ - int num_sections; /* number of sections contained in the image */ + unsigned int num_sections; /* number of sections contained in the image */ struct imagesection *sections; /* array of sections */ - int base_address_set; /* whether the image has a base address set (for relocation purposes) */ + bool base_address_set; /* whether the image has a base address set (for relocation purposes) */ long long base_address; /* base address, if one is set */ - int start_address_set; /* whether the image has a start address (entry point) associated */ + bool start_address_set; /* whether the image has a start address (entry point) associated */ uint32_t start_address; /* start address, if one is set */ }; diff --git a/src/target/target.c b/src/target/target.c index da0c943bf..39575b01c 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3404,11 +3404,11 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image->base_address = addr; - image->base_address_set = 1; + image->base_address_set = true; } else - image->base_address_set = 0; + image->base_address_set = false; - image->start_address_set = 0; + image->start_address_set = false; if (CMD_ARGC >= 4) COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address); @@ -3431,7 +3431,6 @@ COMMAND_HANDLER(handle_load_image_command) uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; - int i; struct image image; int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV, @@ -3449,7 +3448,7 @@ COMMAND_HANDLER(handle_load_image_command) image_size = 0x0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) { + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD, @@ -3582,7 +3581,6 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - int i; int retval; uint32_t checksum = 0; uint32_t mem_checksum = 0; @@ -3606,13 +3604,13 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver target_addr_t addr; COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image.base_address = addr; - image.base_address_set = 1; + image.base_address_set = true; } else { - image.base_address_set = 0; + image.base_address_set = false; image.base_address = 0x0; } - image.start_address_set = 0; + image.start_address_set = false; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) @@ -3621,12 +3619,12 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver image_size = 0x0; int diffs = 0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) { + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD, - "error allocating buffer for section (%d bytes)", - (int)(image.sections[i].size)); + "error allocating buffer for section (%" PRIu32 " bytes)", + image.sections[i].size); break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); @@ -5871,7 +5869,6 @@ COMMAND_HANDLER(handle_fast_load_image_command) uint32_t image_size; target_addr_t min_address = 0; target_addr_t max_address = -1; - int i; struct image image; @@ -5897,7 +5894,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) return ERROR_FAIL; } memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections); - for (i = 0; i < image.num_sections; i++) { + for (unsigned int i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD, "error allocating buffer for section (%d bytes)", diff --git a/src/target/xscale.c b/src/target/xscale.c index 6d1d426d5..aaaed0ebb 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -2582,7 +2582,6 @@ static int xscale_read_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction) { struct xscale_common *const xscale = target_to_xscale(target); - int i; int section = -1; size_t size_read; uint32_t opcode; @@ -2592,7 +2591,7 @@ static int xscale_read_instruction(struct target *target, uint32_t pc, return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ - for (i = 0; i < xscale->trace.image->num_sections; i++) { + for (unsigned int i = 0; i < xscale->trace.image->num_sections; i++) { if ((xscale->trace.image->sections[i].base_address <= pc) && (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > pc)) { @@ -3428,15 +3427,15 @@ COMMAND_HANDLER(xscale_handle_trace_image_command) } xscale->trace.image = malloc(sizeof(struct image)); - xscale->trace.image->base_address_set = 0; - xscale->trace.image->start_address_set = 0; + xscale->trace.image->base_address_set = false; + xscale->trace.image->start_address_set = false; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - xscale->trace.image->base_address_set = 1; + xscale->trace.image->base_address_set = true; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], xscale->trace.image->base_address); } else - xscale->trace.image->base_address_set = 0; + xscale->trace.image->base_address_set = false; if (image_open(xscale->trace.image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { From 92ea7e41b9261d4d7a88d96cc3ef0a727d1059f0 Mon Sep 17 00:00:00 2001 From: Kevin Yang Date: Mon, 12 Oct 2020 15:33:47 -0700 Subject: [PATCH 053/113] target: Examine subsequent targets after failure When a target examination fails, continue to examine subsequent targets. Return the number of targets that failed to examine. Change-Id: I883a0c445edc7eb00f496b79271d773771ec6b66 Signed-off-by: Kevin Yang Reviewed-on: http://openocd.zylin.com/5855 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/target.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 39575b01c..3b1c666e5 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -766,9 +766,11 @@ int target_examine(void) if (target->defer_examine) continue; - retval = target_examine_one(target); - if (retval != ERROR_OK) - return retval; + int retval2 = target_examine_one(target); + if (retval2 != ERROR_OK) { + LOG_WARNING("target %s examination failed", target_name(target)); + retval = retval2; + } } return retval; } From 535f5309ba1277479d44f471655bf722e32fbb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Garci=CC=81a=20Hierro?= Date: Tue, 20 Oct 2020 16:13:17 +0100 Subject: [PATCH 054/113] stm32h7x: Fix reset with non-HLA interfaces on macOS regsub doesn't work correctly on macOS Catalina, which results in an incorrect CHIPNAME derived from the current target. Since regsub is only used by this target, replace it with a simple string search for '.' followed by a substring. This is funcionally equivalent to what the regular expression was doing, but instead relies in simpler string operations that should have little to no differences between systems. Also, refactor CHIPNAME detection into proc stm32h7x_chipname, so it's always retrieved in the same way without duplicating the code. Change-Id: Ia9f63f56b508688e74278b022eaec47e503916e7 Signed-off-by: Alberto Garcia Hierro Reviewed-on: http://openocd.zylin.com/5872 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Christopher Head Reviewed-by: Antonio Borneo --- tcl/target/stm32h7x.cfg | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 4a04929aa..763a7857a 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -175,10 +175,19 @@ $_CHIPNAME.cpu0 configure -event reset-init { adapter speed 4000 } +# get _CHIPNAME from current target +proc stm32h7x_get_chipname {} { + set t [target current] + set sep [string last "." $t] + if {$sep == -1} { + return $t + } + return [string range $t 0 [expr $sep - 1]] +} + if {[set $_CHIPNAME.DUAL_CORE]} { $_CHIPNAME.cpu1 configure -event examine-end { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] global $_CHIPNAME.USE_CTI # Stop watchdog counters during halt @@ -214,8 +223,7 @@ proc stm32h7x_mmw {used_target reg setbits clearbits} { proc stm32h7x_dbgmcu_mmw {reg_offset setbits clearbits} { # use $_CHIPNAME.ap2 if possible, and use the proper dbgmcu base address if {![using_hla]} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".(cpu|ap)\\d*$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] set used_target $_CHIPNAME.ap2 set reg_addr [expr 0xE00E1000 + $reg_offset] } { @@ -238,8 +246,7 @@ if {[set $_CHIPNAME.USE_CTI]} { $_CHIPNAME.cpu1 configure -event debug-halted { stm32h7x_cti_prepare_restart_all } proc stm32h7x_cti_start {} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] # Configure Cores' CTIs to halt each other # TRIGIN0 (DBGTRIGGER) and TRIGOUT0 (EDBGRQ) at CTM_CHANNEL_0 @@ -254,8 +261,7 @@ if {[set $_CHIPNAME.USE_CTI]} { } proc stm32h7x_cti_stop {} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] $_CHIPNAME.cti0 enable off $_CHIPNAME.cti1 enable off @@ -267,8 +273,7 @@ if {[set $_CHIPNAME.USE_CTI]} { } proc stm32h7x_cti_prepare_restart {cti} { - # get _CHIPNAME from the current target - set _CHIPNAME [regsub ".cpu\\d$" [target current] ""] + set _CHIPNAME [stm32h7x_get_chipname] # Acknowlodge EDBGRQ at TRIGOUT0 $_CHIPNAME.$cti write INACK 0x01 From c2311cc18f0c432781c0c7d51252b2f5459e1d79 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 5 Nov 2020 09:54:11 +0100 Subject: [PATCH 055/113] configure.ac: add libutil to the dependency list Jimtcl 0.80 (2020-10-29) adds dependency to libutil, which is part of the GNU libc. The library is searched and used by jimtcl build, but still has to be linked in by OpenOCD as indirect dependency. While OpenOCD is still using jimtcl 0.79, let's prepare to switch to the next version. Add libutil search in configure.ac. Change-Id: I5a8952161b0e5b93fc00d23be256b5274d31e08c Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5922 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 055833a7f..3e49213cc 100644 --- a/configure.ac +++ b/configure.ac @@ -44,6 +44,7 @@ AC_TYPE_LONG_LONG_INT AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([dlopen], [dl]) +AC_SEARCH_LIBS([openpty], [util]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([elf.h]) From 3cf95a9d026ec901008e6290eb0ad45557e45680 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 1 Nov 2020 22:06:03 +0100 Subject: [PATCH 056/113] doc: remove reference to already dropped tftp support The only code dealing with tftp in OpenOCD was in eCos build, code already dropped in commit 39650e2273bc ("ecosboard: delete bit-rotted eCos code") almost 8 years ago. Drop tftp related documentation too. Change-Id: I0defc8f844e74c90894dca04a652dcc497a520e1 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5913 Tested-by: jenkins Reviewed-by: Jonathan McDowell --- doc/openocd.texi | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ee7186746..9903b70df 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -79,7 +79,6 @@ Free Documentation License''. * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * Utility Commands:: Utility Commands -* TFTP:: TFTP * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions @@ -10371,28 +10370,6 @@ For quickstart instructions run: openocd -f tools/firmware-recovery.tcl -c firmware_help @end example -@node TFTP -@chapter TFTP -@cindex TFTP -If OpenOCD runs on an embedded host (as ZY1000 does), then TFTP can -be used to access files on PCs (either the developer's PC or some other PC). - -The way this works on the ZY1000 is to prefix a filename by -"/tftp/ip/" and append the TFTP path on the TFTP -server (tftpd). For example, - -@example -load_image /tftp/10.0.0.96/c:\temp\abc.elf -@end example - -will load c:\temp\abc.elf from the developer pc (10.0.0.96) into memory as -if the file was hosted on the embedded host. - -In order to achieve decent performance, you must choose a TFTP server -that supports a packet size bigger than the default packet size (512 bytes). There -are numerous TFTP servers out there (free and commercial) and you will have to do -a bit of googling to find something that fits your requirements. - @node GDB and OpenOCD @chapter GDB and OpenOCD @cindex GDB From ad06fba6f07ceaaf88845658c47a8f50888e413e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 1 Nov 2020 01:03:44 +0100 Subject: [PATCH 057/113] target/arm7tdmi: remove unused/deprecated function parameter The function arm7tdmi_clock_out() has one unused 'deprecated' parameter. Drop the unused 'deprecated' parameter and the FIXME above it. Change-Id: Ia8de41f5b8258825faccc737bba622e44c81a7ea Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5912 Tested-by: jenkins --- src/target/arm7tdmi.c | 159 +++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 81 deletions(-) diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 01685ab6a..10263f40a 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -115,11 +115,9 @@ static inline int arm7tdmi_clock_out_inner(struct arm_jtag *jtag_info, uint32_t /* put an instruction in the ARM7TDMI pipeline or write the data bus, * and optionally read data - * - * FIXME remove the unused "deprecated" parameter */ static inline int arm7tdmi_clock_out(struct arm_jtag *jtag_info, - uint32_t out, uint32_t *deprecated, int breakpoint) + uint32_t out, int breakpoint) { int retval; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); @@ -246,35 +244,35 @@ static void arm7tdmi_change_to_arm(struct target *target, * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, r0); /* MOV r0, r15 fetched, STR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, pc); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, data for LDR r0, [PC, #0] */ - arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); + arm7tdmi_clock_out(jtag_info, 0x0, 0); /* nothing fetched, data from previous cycle is written to register */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch BX */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0); /* NOP fetched, BX in Decode, MOV in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* NOP fetched, BX in Execute (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); jtag_execute_queue(); @@ -301,12 +299,12 @@ static void arm7tdmi_read_core_regs(struct target *target, /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) @@ -329,12 +327,12 @@ static void arm7tdmi_read_core_regs_target_buffer(struct target *target, /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, STM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ @@ -360,14 +358,14 @@ static void arm7tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0); /* STR r0, [r15] */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0); /* fetch NOP, STR in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, STR still in EXECUTE (2nd cycle) */ arm7tdmi_clock_data_in(jtag_info, xpsr); } @@ -380,25 +378,25 @@ static void arm7tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0); /* MSR2 fetched, MSR1 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0); /* nothing fetched, MSR1 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0); /* nothing fetched, MSR2 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR4 in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_xpsr_im8(struct target *target, @@ -410,13 +408,13 @@ static void arm7tdmi_write_xpsr_im8(struct target *target, LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0); /* NOP fetched, MSR in DECODE */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* NOP fetched, MSR in EXECUTE (1) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, MSR in EXECUTE (2) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_write_core_regs(struct target *target, @@ -429,7 +427,7 @@ static void arm7tdmi_write_core_regs(struct target *target, /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); @@ -450,9 +448,9 @@ static void arm7tdmi_load_word_regs(struct target *target, uint32_t mask) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0); } static void arm7tdmi_load_hword_reg(struct target *target, int num) @@ -461,9 +459,9 @@ static void arm7tdmi_load_hword_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0); } static void arm7tdmi_load_byte_reg(struct target *target, int num) @@ -472,9 +470,9 @@ static void arm7tdmi_load_byte_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0); } static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) @@ -483,9 +481,9 @@ static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0); } static void arm7tdmi_store_hword_reg(struct target *target, int num) @@ -494,9 +492,9 @@ static void arm7tdmi_store_hword_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0); } static void arm7tdmi_store_byte_reg(struct target *target, int num) @@ -505,9 +503,9 @@ static void arm7tdmi_store_byte_reg(struct target *target, int num) struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0); } static void arm7tdmi_write_pc(struct target *target, uint32_t pc) @@ -518,7 +516,7 @@ static void arm7tdmi_write_pc(struct target *target, uint32_t pc) /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ @@ -540,7 +538,7 @@ static void arm7tdmi_branch_resume(struct target *target) struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 1); arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0); } @@ -556,53 +554,52 @@ static void arm7tdmi_branch_resume_thumb(struct target *target) /* LDMIA r0, [r0] at debug speed * register values will start to appear on 4th DCLK */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0); /* fetch NOP, LDM in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, - buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0); + arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->pc->value, 0, 32) | 1, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* Branch and eXchange */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0); /* fetch NOP, LDR in Decode */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* fetch NOP, LDR in Execute */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ - arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0); + arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0); embeddedice_read_reg(dbg_stat); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); - arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 1); + arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), 0); } static void arm7tdmi_build_reg_cache(struct target *target) From 384e90b06b5005aa04d695b8a67c81a0af646082 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 1 Nov 2020 15:39:23 +0100 Subject: [PATCH 058/113] build: fix build with --enable-minidriver-dummy Commit 462c01206692 ("Add complete JTAG debug logging.") breaks the build for minidriver, that is enabled either on zy1000 build and on minidriver-dummy build. The check on BUILD_ZY1000 was added to pass the auto-build in jenkins. While the build issue with minidriver-dummy was known, as reported in the comment, it was not addressed and got ignored for slightly more than one year. Use the macro HAVE_JTAG_MINIDRIVER_H in place of BUILD_ZY1000 to take in account both builds that require the minidriver. Fix also the build in case configure enables the HLA drivers due to autodetection of libusb. The HLA drivers would not be in the build and the function transport_is_hla() would be missing. Change-Id: I1d85c5fa247bf4a85aba29b233c0b573b46665bc Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5911 Tested-by: jenkins --- src/jtag/core.c | 4 ++-- src/transport/transport.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index f0f74eb80..5abf832f8 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -953,12 +953,12 @@ int default_interface_jtag_execute_queue(void) int result = jtag->jtag_ops->execute_queue(); -#if !BUILD_ZY1000 +#if !HAVE_JTAG_MINIDRIVER_H /* Only build this if we use a regular driver with a command queue. * Otherwise jtag_command_queue won't be found at compile/link time. Its * definition is in jtag/commands.c, which is only built/linked by * jtag/Makefile.am if MINIDRIVER_DUMMY || !MINIDRIVER, but those variables - * aren't accessible here. */ + * aren't accessible here. Use HAVE_JTAG_MINIDRIVER_H */ struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { switch (cmd->type) { diff --git a/src/transport/transport.h b/src/transport/transport.h index e04f78063..6bf6aaced 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -98,7 +98,7 @@ bool transport_is_dapdirect_jtag(void); bool transport_is_dapdirect_swd(void); bool transport_is_swim(void); -#if BUILD_HLADAPTER +#if BUILD_HLADAPTER && !HAVE_JTAG_MINIDRIVER_H bool transport_is_hla(void); #else static inline bool transport_is_hla(void) From ba564bda6694769b95e22808982d087c779e6dd9 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 31 Oct 2020 14:49:23 +0100 Subject: [PATCH 059/113] drivers/jlink: fix check for max prescaler The value stored in TPIU ACPR is the prescaler value decremented by one. Thus, the test should verify that prescaler does not exceed the maximum ACPR value plus one. Also, zero value is not allowed for prescaler. Change-Id: I1817f04f2a310b2f413bad726f0cb9dd6a4172e2 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5907 Tested-by: jenkins Reviewed-by: Adrian M Negreanu --- src/jtag/drivers/jlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index ae8ce49c6..b915707ec 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -1270,7 +1270,7 @@ static bool calculate_swo_prescaler(unsigned int traceclkin_freq, uint32_t trace_freq, uint16_t *prescaler) { unsigned int presc = (traceclkin_freq + trace_freq / 2) / trace_freq; - if (presc > TPIU_ACPR_MAX_SWOSCALER) + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) return false; /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ @@ -1296,7 +1296,7 @@ static bool detect_swo_freq_and_prescaler(struct jaylink_swo_speed speed, *trace_freq = speed.freq / divider; presc = ((1.0 - SWO_MAX_FREQ_DEV) * traceclkin_freq) / *trace_freq + 1; - if (presc > TPIU_ACPR_MAX_SWOSCALER) + if (presc > TPIU_ACPR_MAX_SWOSCALER + 1) break; deviation = fabs(1.0 - ((double)*trace_freq * presc / traceclkin_freq)); From 1f6efaada0686f7e9e6164919eb739892855d327 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Fri, 30 Oct 2020 15:03:37 +0100 Subject: [PATCH 060/113] stlink: fix max SWV baudrate on stlink v3 While stlink v2 anly accept till to 2 MHz for SWV baudrate, stlink v3 accepts up to 24 MHz. Check the stlink version and use the respective max value. Change-Id: I911207a35983b6acf0b901059076dd31f70e6290 Signed-off-by: Antonio Borneo Reported-by: Pawel Fixes: https://sourceforge.net/p/openocd/tickets/283/ Reviewed-on: http://openocd.zylin.com/5908 Tested-by: jenkins --- src/jtag/drivers/stlink_usb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 48db3e611..8ab73cd12 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -299,6 +299,7 @@ struct stlink_usb_handle_s { #define STLINK_TRACE_SIZE 4096 #define STLINK_TRACE_MAX_HZ 2000000 +#define STLINK_V3_TRACE_MAX_HZ 24000000 #define STLINK_V3_MAX_FREQ_NB 10 @@ -2996,17 +2997,20 @@ static int stlink_config_trace(void *handle, bool enabled, return ERROR_FAIL; } + unsigned int max_trace_freq = (h->version.stlink == 3) ? + STLINK_V3_TRACE_MAX_HZ : STLINK_TRACE_MAX_HZ; + /* Only concern ourselves with the frequency if the STlink is processing it. */ - if (enabled && *trace_freq > STLINK_TRACE_MAX_HZ) { + if (enabled && *trace_freq > max_trace_freq) { LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u", - STLINK_TRACE_MAX_HZ); + max_trace_freq); return ERROR_FAIL; } stlink_usb_trace_disable(h); if (!*trace_freq) - *trace_freq = STLINK_TRACE_MAX_HZ; + *trace_freq = max_trace_freq; presc = traceclkin_freq / *trace_freq; From 475f42051e13d64bc4d1960306ad1d2ea3c7962a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 31 Oct 2020 14:55:10 +0100 Subject: [PATCH 061/113] stlink: fix computation of trace prescaler Use integer rounding for the computation of prescaler. Improve the test of prescaler range, knowing its value would be decremented before being written in TPIU ACPR. Change-Id: I041dde1dca41323904e36a6b6975028a6de902b3 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5909 Tested-by: jenkins --- src/jtag/drivers/stlink_usb.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 8ab73cd12..c54e2cc19 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -2989,7 +2989,6 @@ static int stlink_config_trace(void *handle, bool enabled, uint16_t *prescaler) { struct stlink_usb_handle_s *h = handle; - uint16_t presc; if (enabled && (!(h->version.flags & STLINK_F_HAS_TRACE) || pin_protocol != TPIU_PIN_PROTOCOL_ASYNC_UART)) { @@ -3012,12 +3011,17 @@ static int stlink_config_trace(void *handle, bool enabled, if (!*trace_freq) *trace_freq = max_trace_freq; - presc = traceclkin_freq / *trace_freq; + unsigned int presc = (traceclkin_freq + *trace_freq / 2) / *trace_freq; + if (presc == 0 || presc > TPIU_ACPR_MAX_SWOSCALER + 1) { + LOG_ERROR("SWO frequency is not suitable. Please choose a different " + "frequency."); + return ERROR_FAIL; + } - if (traceclkin_freq % *trace_freq > 0) - presc++; - - if (presc > TPIU_ACPR_MAX_SWOSCALER) { + /* Probe's UART speed must be within 3% of the TPIU's SWO baud rate. */ + unsigned int max_deviation = (traceclkin_freq * 3) / 100; + if (presc * *trace_freq < traceclkin_freq - max_deviation || + presc * *trace_freq > traceclkin_freq + max_deviation) { LOG_ERROR("SWO frequency is not suitable. Please choose a different " "frequency."); return ERROR_FAIL; From e44539d66c8929679321704768125df9ba7d5f67 Mon Sep 17 00:00:00 2001 From: Andreas Bolsch Date: Wed, 21 Dec 2016 10:35:58 +0100 Subject: [PATCH 062/113] Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface - write speed up to 150 kByte/s on STM32F469I-disco (due to SWD clock and USB connection), up to 1 MByte/s on Nucleo-F767ZI with external STLink-V3 or Nucleo-G474RE with two W25Q256FV in dual 4-line mode or STM32H73BI-Disco in octal mode - tested with STM32L476G-disco (64MBit flash, 3-byte addr), STM32F412G-Disco, STM32F469I-Disco, STM32F746G-Disco, and STM32L476G-Disco (all 128Mbit flash, 3-byte addr), STM32F723E-Disco, STM32F769I-Disco (512Mbit flash, 4-byte addr) STM32L4R9I-Disco, STM32L4P5G-Disco (512MBit octo-flash, DTR, 4-byte addr) STM32H745I-Disco, STM32H747I-Disco (two 512MBit flash, 4-byte addr) STM32H73BI-Disco, STM32H735G-Disco (512MBit octo-flash, DTR, 4-byte addr) - suitable cfg for Discovery boards included - limited parsing of SFDP data if flash device not hardcoded (tested only in single/quad mode as most devices either don't support SFDP at all or have empty(!) SFDP memory) - 'set' command for auto detection override (e. g. for EEPROMs) - 'cmd' command for arbitrary SPI commands (reconfiguration, testing etc.) - makefile for creation of binary loader files - tcl/board/stm32f469discovery.cfg superseded by stm32f469i-disco.cfg - tcl/board/stm32f7discovery.cfg removed as name is ambiguous (superseded by stm32f746g-disco.cfg vs. stm32f769i-disco.cfg) - dual 4-line mode tested on Nucleo-F767ZI, Nucleo-H743ZI and Nucleo-H7A3ZI-Q with two W25Q256FV, and on Nucleo-L496ZP-P and Nucleo-L4R5ZI with two W25Q128FV, sample cfg files included and on STM32H745I-Disco, STM32H747I-Disco, STM32H750B-Disco - read/verify/erase_check uses indirect read mode to work around silicon bug in H7, L4+ and MP1 memory mapped mode (last bytes not readable, accessing last bytes causes debug interface to hang) - octospi supported only in single/dual 1-line, 2-line, 4-line and single 8-line modes, (not in hyper flash mode) Requirements: GPIOs must be initialized appropriately, and SPI flash chip be configured appropriately (1-line ..., QPI, 4-byte addresses ...). This is board/chip specific, cf. included cfg files. The driver infers most parameters from current setting in CR, CCR, ... registers. Change-Id: I54858fbbe8758c3a5fe58812e93f5f39514704f8 Signed-off-by: Andreas Bolsch Reviewed-on: http://openocd.zylin.com/4321 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Tomas Vanek Reviewed-by: Christopher Head --- contrib/loaders/flash/stmqspi/Makefile | 34 + .../loaders/flash/stmqspi/gpio_conf_stm32.pl | 679 +++++ .../loaders/flash/stmqspi/stmoctospi_crc32.S | 123 + .../flash/stmqspi/stmoctospi_crc32.inc | 13 + .../flash/stmqspi/stmoctospi_erase_check.S | 108 + .../flash/stmqspi/stmoctospi_erase_check.inc | 8 + .../loaders/flash/stmqspi/stmoctospi_read.S | 142 + .../loaders/flash/stmqspi/stmoctospi_read.inc | 12 + .../loaders/flash/stmqspi/stmoctospi_write.S | 219 ++ .../flash/stmqspi/stmoctospi_write.inc | 21 + contrib/loaders/flash/stmqspi/stmqspi_crc32.S | 108 + .../loaders/flash/stmqspi/stmqspi_crc32.inc | 12 + .../flash/stmqspi/stmqspi_erase_check.S | 91 + .../flash/stmqspi/stmqspi_erase_check.inc | 7 + contrib/loaders/flash/stmqspi/stmqspi_read.S | 127 + .../loaders/flash/stmqspi/stmqspi_read.inc | 11 + contrib/loaders/flash/stmqspi/stmqspi_write.S | 177 ++ .../loaders/flash/stmqspi/stmqspi_write.inc | 18 + doc/openocd.texi | 123 + src/flash/nor/Makefile.am | 4 + src/flash/nor/core.c | 58 +- src/flash/nor/core.h | 14 +- src/flash/nor/driver.h | 14 + src/flash/nor/drivers.c | 2 + src/flash/nor/imp.h | 8 +- src/flash/nor/sfdp.c | 263 ++ src/flash/nor/sfdp.h | 34 + src/flash/nor/spi.h | 6 +- src/flash/nor/stmqspi.c | 2452 +++++++++++++++++ src/flash/nor/stmqspi.h | 125 + src/flash/nor/stmsmi.c | 28 +- src/flash/nor/tcl.c | 65 +- src/target/image.c | 2 +- src/target/image.h | 2 +- src/target/target.c | 158 +- src/target/target.h | 12 + tcl/board/b-l475e-iot01a.cfg | 56 + tcl/board/stm32f412g-disco.cfg | 70 + tcl/board/stm32f413h-disco.cfg | 83 + tcl/board/stm32f469i-disco.cfg | 65 + tcl/board/stm32f723e-disco.cfg | 74 + tcl/board/stm32f746g-disco.cfg | 69 + tcl/board/stm32f769i-disco.cfg | 79 + tcl/board/stm32h735g-disco.cfg | 122 + tcl/board/stm32h745i-disco.cfg | 45 + tcl/board/stm32h747i-disco.cfg | 136 + tcl/board/stm32h750b-disco.cfg | 45 + tcl/board/stm32h7b3i-disco.cfg | 128 + tcl/board/stm32h7x_dual_qspi.cfg | 90 + tcl/board/stm32l476g-disco.cfg | 56 + tcl/board/stm32l496g-disco.cfg | 66 + tcl/board/stm32l4p5g-disco.cfg | 130 + tcl/board/stm32l4r9i-disco.cfg | 100 + tcl/target/stm32f4x.cfg | 6 + tcl/target/stm32f7x.cfg | 8 +- tcl/target/stm32h7x.cfg | 17 + tcl/target/stm32l4x.cfg | 17 + 57 files changed, 6709 insertions(+), 33 deletions(-) create mode 100644 contrib/loaders/flash/stmqspi/Makefile create mode 100755 contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_crc32.S create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_erase_check.inc create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_read.S create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_read.inc create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_write.S create mode 100644 contrib/loaders/flash/stmqspi/stmoctospi_write.inc create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_crc32.S create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_crc32.inc create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_erase_check.S create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_erase_check.inc create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_read.S create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_read.inc create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_write.S create mode 100644 contrib/loaders/flash/stmqspi/stmqspi_write.inc create mode 100644 src/flash/nor/sfdp.c create mode 100644 src/flash/nor/sfdp.h create mode 100644 src/flash/nor/stmqspi.c create mode 100644 src/flash/nor/stmqspi.h create mode 100644 tcl/board/b-l475e-iot01a.cfg create mode 100644 tcl/board/stm32f412g-disco.cfg create mode 100644 tcl/board/stm32f413h-disco.cfg create mode 100644 tcl/board/stm32f469i-disco.cfg create mode 100644 tcl/board/stm32f723e-disco.cfg create mode 100644 tcl/board/stm32f746g-disco.cfg create mode 100644 tcl/board/stm32f769i-disco.cfg create mode 100644 tcl/board/stm32h735g-disco.cfg create mode 100644 tcl/board/stm32h745i-disco.cfg create mode 100644 tcl/board/stm32h747i-disco.cfg create mode 100644 tcl/board/stm32h750b-disco.cfg create mode 100644 tcl/board/stm32h7b3i-disco.cfg create mode 100644 tcl/board/stm32h7x_dual_qspi.cfg create mode 100644 tcl/board/stm32l476g-disco.cfg create mode 100644 tcl/board/stm32l496g-disco.cfg create mode 100644 tcl/board/stm32l4p5g-disco.cfg create mode 100644 tcl/board/stm32l4r9i-disco.cfg diff --git a/contrib/loaders/flash/stmqspi/Makefile b/contrib/loaders/flash/stmqspi/Makefile new file mode 100644 index 000000000..810c7e87c --- /dev/null +++ b/contrib/loaders/flash/stmqspi/Makefile @@ -0,0 +1,34 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +SRCS=stmqspi_erase_check.S stmqspi_crc32.S stmqspi_read.S stmqspi_write.S \ + stmoctospi_erase_check.S stmoctospi_crc32.S stmoctospi_read.S stmoctospi_write.S +OBJS=$(patsubst %.S,%.inc,$(SRCS)) + +CROSS_COMPILE ?= arm-none-eabi- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump +LD=$(CROSS_COMPILE)ld + +all: $(OBJS) + +%.o: %.S Makefile + $(CC) -Wall -Werror -Wa,-adhlmn -o $@ -c $< > $(@:.o=.lst) + @enscript -Easm -T 4 -G -o - $(@:.o=.lst) | ps2pdf - $(@:.o=.pdf) || true + +%.elf: %.o + $(LD) -s -defsym=_start=0 -o $@ $< + +%.bin: %.elf + $(OBJCOPY) -S -O binary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.o *.elf *.lst *.pdf *.bin *.inc + +.PHONY: all clean + +.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS)) diff --git a/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl new file mode 100755 index 000000000..b7538640e --- /dev/null +++ b/contrib/loaders/flash/stmqspi/gpio_conf_stm32.pl @@ -0,0 +1,679 @@ +#!/usr/bin/perl +# +# Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+ +# and F1 (for 'stmqspi' and 'cmspi' drivers). +# +# Each pin is configured by "PortAndBit:Conf:Speed" +# 'PortAndBit' specifies Port and bit number +# 'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input), +# (each optionally by 'P' (push-pull) or 'O' (open-drain)), +# (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down)) +# 'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high) +# +# Port configuration can be given on command line as a single string (pins separated by commas) +# or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the +# corresponding header. The precise spelling in these files doesn't seem to be consistent, though ... +# +# Pins have to be ordered this way: +# - I2C: SDA, SCL +# - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI +# - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI +# - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI +# For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2 +# For octal flash: NCS, CLK, DQS, IO7 down to IO0 + +use strict; +use Getopt::Std; + +my $GPIO_BASE; +my $Conf; +my $STM32F1 = 0; + +# "Blue-Pill stm32f103cbt6 board w/ cmspi +#$STM32F1 = 1; +#$GPIO_BASE = 0x40010800; +#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V"; +#$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V"; + +#$STM32F1 = 1; +#$GPIO_BASE = 0x40010800; +#$Conf = "PB07:INUP:V, PB06:INUP:V"; + +# mini-stm32f030f4p6 board w/ cmspi +#$GPIO_BASE = 0x48000000; +#$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V"; + +# stm32f407vet6 board w/ cmspi +#$GPIO_BASE = 0x40020000; +#$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V"; + +# stm32f412g-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V"; + +# stm32f413h-disco +#$GPIO_BASE = 0x40020000; +#$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V"; + +# stm32f469i-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V"; + +# stm32f723e-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; + +# stm32f746g-disco quad +#$GPIO_BASE = 0x40020000; +#Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V"; + +# stm32f769i-disco quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V"; +# w/ cmspi +#$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, "; + +# b-l475e-iot01a quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; + +# stm32l476g-disco quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V"; + +# stm32l496g-disco quad +#$GPIO_BASE = 0x48000000; +#$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V"; + +# stm32l4r9i-disco octal +#$GPIO_BASE = 0x48000000; +#$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, " +# . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V"; + +# stm32l4p5g-disco octal/octal +#$GPIO_BASE = 0x48000000; +#$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V"; +#$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, " +# . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V"; + +# nucleo-f767zi dual quad +#$GPIO_BASE = 0x40020000; +#$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " +# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-h743zi dual quad +#$GPIO_BASE = 0x58020000; +#$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, " +# . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-h7a3zi dual quad +#$GPIO_BASE = 0x58020000; +#$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, " +# . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V"; +# w/ cmspi +#$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V"; +#$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V"; + +# nucleo-l4r5zi one dual quad single NCS +#$GPIO_BASE = 0x48000000; +#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; +# w/ cmspi +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; + +# nucleo-l552ze-q dual quad with single NCS +#$GPIO_BASE = 0x42020000; +#$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, " +# . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V"; +# w/ cmspi +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V"; +#$Conf = "PA02:PPUP:M, PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V"; + +# nucleo-g071rb dual quad +#$GPIO_BASE = 0x50000000; +#$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H"; +#$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V"; + +# nucleo-g474re dual quad with single NCS +#$GPIO_BASE = 0x48000000; +#$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, " +# . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V"; +# w/ cmspi +#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V"; +#$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V"; + +# stm32h745i-disco dual quad with single NCS +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " +# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; + +# stm32h747i-disco dual quad with single NCS +#GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, " +# . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V"; + +# stm32h7b3i-disco octal +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, " +# . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V"; + +# stm32h735g-disco octal +#$GPIO_BASE = 0x58020000; +#$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, " +# . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V"; + +# stm32l562e-disco octal +#$GPIO_BASE = 0x42020000; +#$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, " +# . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V"; + +&getopts('b:c:f:t'); +if ($Getopt::Std::opt_b eq '') +{ + if ($GPIO_BASE eq '') + { + die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]"); + } +} +else +{ + $GPIO_BASE = eval $Getopt::Std::opt_b; +} + +if ($Getopt::Std::opt_c eq '') +{ + if (($Conf eq '') && ($Getopt::Std::opt_f eq '')) + { + die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )"); + } +}# +else +{ + $Conf = $Getopt::Std::opt_c . ','; +} + +$STM32F1 = $Getopt::Std::opt_t; + +my $Sep = "\t"; +my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# "; + +my $GPIO_OFFS; +my $GPIO_CRL; +my $GPIO_CRH; +my $GPIO_MODER; +my $GPIO_OTYPER; +my $GPIO_OSPEEDR; +my $GPIO_PUPDR; +my $GPIO_IDR; +my $GPIO_ODR; +my $GPIO_AFRL; +my $GPIO_AFRH; + +if ($STM32F1) +{ + # offsets for F1 devices + $GPIO_OFFS = 0x400; + $GPIO_CRL = 0x00; + $GPIO_CRH = 0x04; + $GPIO_IDR = 0x08; + $GPIO_ODR = 0x0C; +} +else +{ + # these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now + $GPIO_OFFS = 0x400; + $GPIO_MODER = 0x00; + $GPIO_OTYPER = 0x04; + $GPIO_OSPEEDR = 0x08; + $GPIO_PUPDR = 0x0C; + $GPIO_IDR = 0x10; + $GPIO_ODR = 0x14; + $GPIO_AFRL = 0x20; + $GPIO_AFRH = 0x24; +} + +my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } ); +my @Port = ( ); +my $Exor; +my %Conf; +my $Pins = "${Sep}#"; + +my $pins; +my $altn; +my %defs; + +if ($Getopt::Std::opt_f ne '') +{ + open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f"); + while (my $line = ) + { + if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/) + { + if ($line =~ /#define\s+(\w+)\s+(\w+)/) + { + $defs{$1} = $2; + } + else + { + die($line); + } + } + elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/) + { + $Conf{$4} = sprintf("%s%02d", $1, $2); + } + elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/) + { + $pins = $1; + while ($line !~ /;/) + { + $line = ; + $line =~ /^\s*([^;]+\w)/; + $pins .= $1; + } + } + elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/) + { + $altn = $1; + } + elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/) + { + my $port = $1; + if ($port =~ /GPIO([A-Z])/) + { + $port = $1; + } + elsif (exists($defs{$port})) + { + $defs{$port} =~ /GPIO([A-Z])/; + $port = $1; + } + else + { + printf("\n"); + next; + } + my @pin = split(/\s*\|\s*/, $pins); + foreach my $pin (@pin) + { + my $bit; + if (exists($defs{$pin})) + { + $defs{$pin} =~ /GPIO_PIN_([0-9]+)/; + $bit = $1; + } + else + { + $pin =~ /GPIO_PIN_([0-9]+)/; + $bit = $1; + } + $Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn); + } + $pins = ''; + $altn = 0; + } + } + close(CONF_FILE); +} +else +{ + my @names = ( ); + my @conf = split(/\s*,\s*/, $Conf); + + if (@conf == 2) + { + push(@names, 'SDA', 'SCL'); + } else { + if (@conf == 3) + { + push(@names, 'NCS', 'CLK', 'IO0/DIO'); + } + elsif (@conf == 4) + { + push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI'); + } + elsif (@conf == 6) + { + push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI'); + } + elsif (@conf == 10) + { + push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); + push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); + } + elsif (@conf == 11) + { + push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI'); + push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI'); + } + else + { + die("invalid config"); + } + } + + for (my $index = 0; $index < @conf; $index++) + { + uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; + $Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2); + } + chop($Pins); +} + +if (exists $Conf{'BK1_IO0'}) +{ + # QuadSPI on F4, F7, H7 + my $line; + for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'BK2_IO0'}) +{ + # QuadSPI on F4, F7, H7 + my $line; + for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'P1_IO0'}) +{ + # OctoSPI on L4+, L5, H7 + my $line; + for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4', + 'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +if (exists $Conf{'P2_IO0'}) +{ + # OctoSPI on L4+, H7 + my $line; + for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4', + 'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0') + { + (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i)); + } +} + +my @Col = ( ); +my @conf = split(/\s*,\s*/, $Conf); + +if (@conf == 3) +{ + splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE'); +} +elsif (@conf == 4) +{ + splice(@conf, 2, 0, 'NONE', 'NONE'); +} + +foreach my $line (@conf) +{ + $line = uc($line); + $line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/; + my $port = $1; + my $pin = $2; + my $conf = $3; + my $speed = $4; + + my $MODER = 0x0; + my $OTYPER = 0x0; + my $OSPEEDR = 0x0; + my $PUPDR = 0x0; + my $AFR = 0x0; + my $num = ord(${port}) - ord('A'); + my $out = $Out[$num]; + + (exists $$out{'DEF'}) || ($$out{'DEF'} = 0); + + if ($conf eq '') + { + if ($line ne 'NONE') + { + printf(STDERR "invalid conf %s\n", $line); + } + next; + } + elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + printf(STDERR "no alternate %s for F1 family\n", $line); + next; + } + if (($1 < 0) || ($1 > 15)) + { + printf(STDERR "invalid alternate %s\n", $line); + next; + } + $MODER = 0x2; + $AFR = $1; + if ($pin <= 7) + { + $$out{'AFRL_H'} |= ($AFR << (${pin} << 2)); + $$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2)); + } + else + { + $$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2)); + $$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2)); + } + if ($2 ne '') { + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + } + $PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); + $conf = sprintf("AF%02d%s%s", $AFR, $2, $3); + } + elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + $MODER = ($1 eq '') ? 0x4 : 0x8; + ($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin})); + } + else + { + $MODER = 0x0; + if ($1 ne '') + { + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + } + $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1)); + } + ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); + } + elsif ($conf =~ /^P(P|O)(|UP|DO)$/) + { + if ($STM32F1) + { + $MODER = ($1 eq 'O') ? 0x4 : 0x0; + $MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1)); + if ($2 ne '') + { + printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line); + } + } + else + { + $MODER = 0x1; + $OTYPER = ($1 eq 'O') ? 0x1 : 0x0; + $$out{'OTYPER_H'} |= ($OTYPER << $pin); + $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin); + $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0); + $$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1)); + $$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1)); + } + ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin})); + ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin})); + } + else + { + printf(STDERR "invalid conf %s\n", $line); + next; + } + + if ($$out{'DEF'} & (1<< ${pin})) + { + printf(STDERR "redefinition: %s\n", $line); + } + + if ($STM32F1) + { + if ($pin >= 8) + { + $$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2)); + $$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); + } + else + { + $$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2)); + $$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2)); + } + + $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); + my $exor = 0xB << (($pin & 0x7) << 2); + (($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", + ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, + ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor)); + } + else + { + $$out{'DEF'} |= (1 << ${pin}); + $$out{'MODER_H'} |= ($MODER << (${pin} << 1)); + $$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1)); + + $OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0))); + $$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1)); + $$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1)); + + $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port) - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin); + my $exor = (0x1 << ($pin << 1)); + ($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, + (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor)); + } + + push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed)); + push(@Col, $Exor); +} + +my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF); +for (my $i = 0; $i < @Col; $i++) +{ + if (($i != 0) && (($i % 2) == 0)) + { + (($i + 1) < @Col) && ($Col .= "\\\n${Sep}"); + } + $Col .= sprintf("%s ", $Col[$i]); +} +printf("%s\n", $Col); + +my @Col = ( ); +my $Set; +for (my $i = 0; $i < @Out; $i++) +{ + my $out = $Out[$i]; + my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS}; + my $count = 0; + + if ($STM32F1) + { + if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} | + $$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) + { + push(@Col, sort({ $b cmp $a } @{$Port[$i]})); + + $Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), + join(", ", sort({ $b cmp $a } @{$Port[$i]}))); + + (($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) && + ($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'})); + + (($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) && + ($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'})); + + (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && + ($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); + } + } + else + { + if (($$out{'MODER_H'} | $$out{'MODER_L'} | + $$out{'OTYPER_H'} | $$out{'OTYPER_L'} | + $$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} | + $$out{'PUPDR_H'} | $$out{'PUPDR_L'} | + $$out{'ODR_H'} | $$out{'ODR_L'} | + $$out{'AFRL_H'} | $$out{'AFRL_L'} | + $$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) + { + push(@Col, sort({ $b cmp $a } @{$Port[$i]})); + + $Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')), + join(", ", sort({ $b cmp $a } @{$Port[$i]}))); + + (($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) && + ($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'})); + + (($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) && + ($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'})); + + (($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) && + ($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'})); + + (($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) && + ($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'})); + + (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) && + ($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'})); + + (($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) && + ($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'})); + + (($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) && + ($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'})); + } + } +} + +my $Col = ''; +for (my $i = 0; $i < @Col; $i++) +{ + if (($i % 6) == 0) + { + chop($Col); + (($i + 1) < @Col) && ($Col .= "\n${Sep}#"); + } + $Col .= sprintf(" %s,", $Col[$i]); +} +chop($Col); +#printf("\n%s\n", $Pins); +printf("%s\n", $Col); +printf("%s\n", $Set); diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S new file mode 100644 index 000000000..941ea42c6 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.S @@ -0,0 +1,123 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), crc32 (out) + * r1 - flash page size + * r2 - address offset into flash + * r3 - OCTOSPI io_base + + * Clobbered: + * r4 - tmp + * r5 - address of OCTOSPI_DR + * r6 - address of OCTOSPI_CCR + * r7 - tmp + */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1< CRC32XOR, pos. -> 0x0 */ + lsls r4, r4, #1 /* shift result */ + eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ + .endr + adds r2, r2, #1 /* increment address */ + subs r0, r0, #1 /* decrement (count-1) */ + bmi exit /* stop if no data left */ + tst r2, r1 /* page end ? */ + bne read_loop /* if not, then next byte */ +page_end: + bal start_read /* then next page */ + .pool + +exit: + mvns r0, r4 /* invert to get final result */ + octospi_abort /* to idle state */ + .align 2 /* align to word, bkpt is 4 words */ + bkpt #0 /* before code end for exit_point */ + .align 2 /* align to word */ + +cr_page_read: + .space 4 /* OCTOSPI_CR value for read command */ +ccr_page_read: + .space 4 /* OCTOSPI_CCR value for read command */ +tcr_page_read: + .space 4 /* OCTOSPI_TCR value for read command */ +ir_page_read: + .space 4 /* OCTOSPI_IR value for read command */ diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc new file mode 100644 index 000000000..afc616883 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc @@ -0,0 +1,13 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, +0x50,0x25,0xed,0x18,0xb0,0x26,0x76,0x19,0x1f,0x6a,0xbf,0x09,0xfc,0xd2,0x02,0x27, +0x5f,0x62,0x22,0x4f,0x1f,0x60,0x17,0x46,0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9, +0x07,0x46,0x1f,0x64,0x1e,0x4f,0x37,0x60,0x1e,0x4f,0xb7,0x60,0x1e,0x4f,0x37,0x61, +0x9a,0x64,0x15,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00, +0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38,0x05,0xd4, +0x0a,0x42,0xd7,0xd1,0xb8,0xe7,0x00,0x00,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, +0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S new file mode 100644 index 000000000..3af82d4d8 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmoctospi_erase_check.S @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - sector count + * r1 - QSPI io_base + + * Clobbered: + * r2 - r7 tmp */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1<. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), remaining bytes (out, 0 means successful) + * r1 - flash page size + * r2 - address offset into flash + * r3 - OCTOSPI io_base + * r8 - fifo start + * r9 - fifo end + 1 + + * Clobbered: + * r4 - wp + * r5 - address of OCTOSPI_DR + * r6 - address of OCTOSPI_CCR + * r7 - tmp + */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1<. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), remaining bytes (out, 0 means successful) + * r1 - flash page size + * r2 - address offset into flash + * r3 - OCTOSPI io_base + * r8 - fifo start + * r9 - fifo end + 1 + + * Clobbered: + * r4 - rp + * r5 - address of OCTOSPI_DR + * r6 - address of OCTOSPI_CCR + * r7 - tmp + * r10 - single 0x0 / dual 0x1 + */ + +#include "../../../../src/flash/nor/stmqspi.h" + +#define OCTOSPI_CCR_CCR (OCTOSPI_CCR - OCTOSPI_CCR) +#define OCTOSPI_TCR_CCR (OCTOSPI_TCR - OCTOSPI_CCR) +#define OCTOSPI_IR_CCR (OCTOSPI_IR - OCTOSPI_CCR) + + .macro octospi_abort + movs r5, #(1<. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), crc32 (out) + * r1 - flash page size + * r2 - address offset into flash + * r3 - QSPI io_base + + * Clobbered: + * r4 - rp + * r5 - address of QSPI_DR + * r7 - tmp + */ + +#include "../../../../src/flash/nor/stmqspi.h" + + .macro qspi_abort + movs r5, #(1< CRC32XOR, pos. -> 0x0 */ + lsls r4, r4, #1 /* shift result */ + eors r4, r4, r7 /* eor by CRC32XOR or 0x0 */ + .endr + adds r2, r2, #1 /* increment address */ + subs r0, r0, #1 /* decrement (count-1) */ + bmi exit /* stop if no data left */ + tst r2, r1 /* page end ? */ + bne read_loop /* if not, then next byte */ +page_end: + bal start_read /* then next page */ + .pool + +exit: + mvns r0, r4 /* invert to get final result */ + qspi_abort /* to idle state */ + .align 2 /* align to word, bkpt is 4 words */ + bkpt #0 /* before code end for exit_point */ + .align 2 /* align to word */ + + .space 4 /* not used */ +ccr_page_read: + .space 4 /* QSPI_CCR value for read command */ + .space 4 /* not used */ + .space 4 /* not used */ diff --git a/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc b/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc new file mode 100644 index 000000000..b532a48b9 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmqspi_crc32.inc @@ -0,0 +1,12 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x01,0x38,0x01,0x39,0x00,0x24,0xe4,0x43,0x02,0x25,0x1f,0x68,0x2f,0x43,0x1f,0x60, +0x20,0x25,0xed,0x18,0x9f,0x68,0xbf,0x09,0xfc,0xd2,0x02,0x27,0xdf,0x60,0x17,0x46, +0x0f,0x43,0xbf,0x1a,0x87,0x42,0x00,0xd9,0x07,0x46,0x1f,0x61,0x1c,0x4f,0x5f,0x61, +0x9a,0x61,0x9f,0x68,0x14,0x4e,0x2f,0x78,0x3f,0x06,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40, +0x64,0x00,0x7c,0x40,0xe7,0x17,0x37,0x40,0x64,0x00,0x7c,0x40,0x01,0x32,0x01,0x38, +0x04,0xd4,0x0a,0x42,0xd7,0xd1,0xbf,0xe7,0xb7,0x1d,0xc1,0x04,0xe0,0x43,0x02,0x25, +0x1f,0x68,0x2f,0x43,0x1f,0x60,0xc0,0x46,0x00,0xbe,0xc0,0x46,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, diff --git a/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S new file mode 100644 index 000000000..d011103a2 --- /dev/null +++ b/contrib/loaders/flash/stmqspi/stmqspi_erase_check.S @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - sector count + * r1 - QSPI io_base + + * Clobbered: + * r2 - r7 tmp */ + +#include "../../../../src/flash/nor/stmqspi.h" + + .macro qspi_abort + movs r4, #(1<. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), remaining bytes (out, 0 means successful) + * r1 - flash page size + * r2 - address offset into flash + * r3 - QSPI io_base + * r8 - fifo start + * r9 - fifo end + 1 + + * Clobbered: + * r4 - wp + * r5 - address of QSPI_DR + * r7 - tmp + */ + +#include "../../../../src/flash/nor/stmqspi.h" + + .macro qspi_abort + movs r5, #(1<. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m0 + .thumb + .thumb_func + +/* Params: + * r0 - total count (bytes), remaining bytes (out, 0 means successful) + * r1 - flash page size + * r2 - address offset into flash + * r3 - QSPI io_base + * r8 - fifo start + * r9 - fifo end + 1 + + * Clobbered: + * r4 - rp + * r5 - address of QSPI_DR + * r7 - tmp + * r10 - single 0x0 / dual 0x1 + */ + +#include "../../../../src/flash/nor/stmqspi.h" + + .macro qspi_abort + movs r5, #(1<target, offset + bank->base, count, buffer); } +int flash_driver_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + int retval; + + retval = bank->driver->verify ? bank->driver->verify(bank, buffer, offset, count) : + default_flash_verify(bank, buffer, offset, count); + if (retval != ERROR_OK) { + LOG_ERROR("verify failed in bank at " TARGET_ADDR_FMT " starting at 0x%8.8" PRIx32, + bank->base, offset); + } + + return retval; +} + +int default_flash_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + uint32_t target_crc, image_crc; + int retval; + + retval = image_calculate_checksum(buffer, count, &image_crc); + if (retval != ERROR_OK) + return retval; + + retval = target_checksum_memory(bank->target, offset + bank->base, count, &target_crc); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, + offset + bank->base, count, ~image_crc, ~target_crc); + if (target_crc == image_crc) + return ERROR_OK; + else + return ERROR_FAIL; +} + void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ @@ -697,8 +734,8 @@ static bool flash_write_check_gap(struct flash_bank *bank, } -int flash_write_unlock(struct target *target, struct image *image, - uint32_t *written, bool erase, bool unlock) +int flash_write_unlock_verify(struct target *target, struct image *image, + uint32_t *written, bool erase, bool unlock, bool write, bool verify) { int retval = ERROR_OK; @@ -932,8 +969,17 @@ int flash_write_unlock(struct target *target, struct image *image, } if (retval == ERROR_OK) { - /* write flash sectors */ - retval = flash_driver_write(c, buffer, run_address - c->base, run_size); + if (write) { + /* write flash sectors */ + retval = flash_driver_write(c, buffer, run_address - c->base, run_size); + } + } + + if (retval == ERROR_OK) { + if (verify) { + /* verify flash sectors */ + retval = flash_driver_verify(c, buffer, run_address - c->base, run_size); + } } free(buffer); @@ -957,7 +1003,7 @@ done: int flash_write(struct target *target, struct image *image, uint32_t *written, bool erase) { - return flash_write_unlock(target, image, written, erase, false); + return flash_write_unlock_verify(target, image, written, erase, false, true, false); } struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 163e57878..107a1c56e 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -200,6 +200,7 @@ void default_flash_free_driver_priv(struct flash_bank *bank); /** Deallocates all flash banks */ void flash_free_all_banks(void); + /** * Provides default read implementation for flash memory. * @param bank The bank to read. @@ -210,6 +211,18 @@ void flash_free_all_banks(void); */ int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); + +/** + * Provides default verify implementation for flash memory. + * @param bank The bank to verify. + * @param buffer The data bytes to verify. + * @param offset The offset into the chip to verify. + * @param count The number of bytes to verify. + * @returns ERROR_OK if successful; otherwise, an error code. + */ +int default_flash_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); + /** * Provides default erased-bank check handling. Checks to see if * the flash driver knows they are erased; if things look uncertain, @@ -217,7 +230,6 @@ int default_flash_read(struct flash_bank *bank, * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_blank_check(struct flash_bank *bank); - /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 7f66047fe..e29d4f528 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -155,6 +155,20 @@ struct flash_driver { int (*read)(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); + /** + * Verify data in flash. Note CPU address will be + * "bank->base + offset", while the physical address is + * dependent upon current target MMU mappings. + * + * @param bank The bank to verify + * @param buffer The data bytes to verify against. + * @param offset The offset into the chip to verify. + * @param count The number of bytes to verify. + * @returns ERROR_OK if successful; otherwise, an error code. + */ + int (*verify)(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); + /** * Probe to determine what kind of flash is present. * This is invoked by the "probe" script command. diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index d52e072ee..570861ec5 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -75,6 +75,7 @@ extern const struct flash_driver stm32f2x_flash; extern const struct flash_driver stm32lx_flash; extern const struct flash_driver stm32l4x_flash; extern const struct flash_driver stm32h7x_flash; +extern const struct flash_driver stmqspi_flash; extern const struct flash_driver stmsmi_flash; extern const struct flash_driver str7x_flash; extern const struct flash_driver str9x_flash; @@ -148,6 +149,7 @@ static const struct flash_driver * const flash_drivers[] = { &stm32l4x_flash, &stm32h7x_flash, &stmsmi_flash, + &stmqspi_flash, &str7x_flash, &str9x_flash, &str9xpec_flash, diff --git a/src/flash/nor/imp.h b/src/flash/nor/imp.h index 06fb2a2b6..f66cf0329 100644 --- a/src/flash/nor/imp.h +++ b/src/flash/nor/imp.h @@ -42,12 +42,14 @@ int flash_driver_erase(struct flash_bank *bank, unsigned int first, int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first, unsigned int last); int flash_driver_write(struct flash_bank *bank, - uint8_t *buffer, uint32_t offset, uint32_t count); + const uint8_t *buffer, uint32_t offset, uint32_t count); int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); +int flash_driver_verify(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count); /* write (optional verify) an image to flash memory of the given target */ -int flash_write_unlock(struct target *target, struct image *image, - uint32_t *written, bool erase, bool unlock); +int flash_write_unlock_verify(struct target *target, struct image *image, + uint32_t *written, bool erase, bool unlock, bool write, bool verify); #endif /* OPENOCD_FLASH_NOR_IMP_H */ diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c new file mode 100644 index 000000000..02b4cedec --- /dev/null +++ b/src/flash/nor/sfdp.c @@ -0,0 +1,263 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include "spi.h" +#include "sfdp.h" + +#define SFDP_MAGIC 0x50444653 +#define SFDP_ACCESS_PROT 0xFF +#define SFDP_BASIC_FLASH 0xFF00 +#define SFDP_4BYTE_ADDR 0xFF84 + +static const char *sfdp_name = "sfdp"; + +struct sfdp_hdr { + uint32_t signature; + uint32_t revision; +}; + +struct sfdp_phdr { + uint32_t revision; + uint32_t ptr; +}; + +struct sfdp_basic_flash_param { + uint32_t fast_addr; /* 01: fast read and 3/4 address bytes */ + uint32_t density; /* 02: memory density */ + uint32_t fast_1x4; /* 03: 1-1-4 and 1-4-4 fast read */ + uint32_t fast_1x2; /* 04: 1-2-2 and 1-1-2 fast read */ + uint32_t fast_444; /* 05: 4-4-4 and 2-2-2 fast read */ + uint32_t read_222; /* 06: 2-2-2 fast read instr and dummy */ + uint32_t read_444; /* 07: 4-4-4 fast read instr and dummy */ + uint32_t erase_t12; /* 08: erase types 1, 2 */ + uint32_t erase_t34; /* 09: erase types 3, 4 */ + uint32_t erase_time; /* 10: erase times for types 1 - 4 */ + uint32_t chip_byte; /* 11: chip erase time, byte prog time, page prog */ + uint32_t susp_time; /* 12: suspend and resume times */ + uint32_t susp_instr; /* 13: suspend and resume instr */ + uint32_t pwrd_instr; /* 14: powerdown instr */ + uint32_t quad_req; /* 15: quad enable requirements */ + uint32_t addr_reset; /* 16: 3-/4-byte addressing and reset */ + uint32_t read_1x8; /* 17: 1-1-8 and 1-8-8 fast read instr and dummy */ + uint32_t dtr_drive; /* 18: dtr modes and drive strength */ + uint32_t octal_req; /* 19: octal enable requirements */ + uint32_t speed_888; /* 20: speed in 8-8-8 modes */ +}; + +struct sfdp_4byte_addr_param { + uint32_t flags; /* 01: various flags */ + uint32_t erase_t1234; /* 02: erase commands */ +}; + +/* Try to get parameters from flash via SFDP */ +int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, + read_sfdp_block_t read_sfdp_block) +{ + struct sfdp_hdr header; + struct sfdp_phdr *pheaders = NULL; + uint32_t *ptable = NULL; + unsigned int j, k, nph; + int retval, erase_type = 0; + + memset(dev, 0, sizeof(struct flash_device)); + + /* retrieve SFDP header */ + memset(&header, 0, sizeof(header)); + retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *) &header); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision); + if (header.signature != SFDP_MAGIC) { + LOG_INFO("no SDFP found"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) { + LOG_ERROR("access protocol 0x%02" PRIx8 " not implemented", + (header.revision >> 24) & 0xFF); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + /* retrieve table of parameter headers */ + nph = ((header.revision >> 16) & 0xFF) + 1; + LOG_DEBUG("parameter headers: %d", nph); + pheaders = malloc(sizeof(struct sfdp_phdr) * nph); + if (pheaders == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph); + retval = read_sfdp_block(bank, sizeof(header), + (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *) pheaders); + if (retval != ERROR_OK) + goto err; + + for (k = 0; k < nph; k++) { + uint8_t words = (pheaders[k].revision >> 24) & 0xFF; + uint16_t id = (((pheaders[k].ptr) >> 16) & 0xFF00) | (pheaders[k].revision & 0xFF); + uint32_t ptr = pheaders[k].ptr & 0xFFFFFF; + + LOG_DEBUG("pheader %d len=0x%02" PRIx8 " id=0x%04" PRIx16 + " ptr=0x%06" PRIx32, k, words, id, ptr); + + /* retrieve parameter table */ + ptable = malloc(words << 2); + if (ptable == NULL) { + LOG_ERROR("not enough memory"); + retval = ERROR_FAIL; + goto err; + } + retval = read_sfdp_block(bank, ptr, words, ptable); + if (retval != ERROR_OK) + goto err; + + for (j = 0; j < words; j++) + LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]); + + if (id == SFDP_BASIC_FLASH) { + struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *) ptable; + uint16_t erase; + + if (words < 9) { + LOG_ERROR("id=0x%04" PRIx16 " invalid length %d", id, words); + retval = ERROR_FLASH_BANK_NOT_PROBED; + goto err; + } + + LOG_DEBUG("basic flash parameter table"); + /* dummy device name */ + dev->name = sfdp_name; + + /* default instructions */ + dev->read_cmd = SPIFLASH_READ; + dev->pprog_cmd = SPIFLASH_PAGE_PROGRAM; + dev->chip_erase_cmd = SPIFLASH_MASS_ERASE; + + /* get device size */ + if (table->density & (1UL << 31)) + dev->size_in_bytes = 1UL << ((table->density & ~(1UL << 31)) - 3); + else + dev->size_in_bytes = (table->density + 1) >> 3; + + /* 2-2-2 read instruction, not used */ + if (table->fast_444 & (1UL << 0)) + dev->qread_cmd = (table->read_222 >> 24) & 0xFF; + + /* 4-4-4 read instruction */ + if (table->fast_444 & (1UL << 4)) + dev->qread_cmd = (table->read_444 >> 24) & 0xFF; + + /* find the largest erase block size and instruction */ + erase = (table->erase_t12 >> 0) & 0xFFFF; + erase_type = 1; + if (((table->erase_t12 >> 16) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t12 >> 16) & 0xFFFF; + erase_type = 2; + } + if (((table->erase_t34 >> 0) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t34 >> 0) & 0xFFFF; + erase_type = 3; + } + if (((table->erase_t34 >> 16) & 0xFF) > (erase & 0xFF)) { + erase = (table->erase_t34 >> 16) & 0xFFFF; + erase_type = 4; + } + dev->erase_cmd = (erase >> 8) & 0xFF; + dev->sectorsize = 1UL << (erase & 0xFF); + + if ((offsetof(struct sfdp_basic_flash_param, chip_byte) >> 2) < words) { + /* get Program Page Size, if chip_byte present, that's optional */ + dev->pagesize = 1UL << ((table->chip_byte >> 4) & 0x0F); + } else { + /* no explicit page size specified ... */ + if (table->fast_addr & (1UL << 2)) { + /* Write Granularity = 1, use 64 bytes */ + dev->pagesize = 1UL << 6; + } else { + /* Write Granularity = 0, use 16 bytes */ + dev->pagesize = 1UL << 4; + } + } + + if (dev->size_in_bytes > (1UL << 24)) { + if (((table->fast_addr >> 17) & 0x3) == 0x0) + LOG_ERROR("device needs paging - not implemented"); + + /* 4-byte addresses needed if more than 16 MBytes */ + if (((offsetof(struct sfdp_basic_flash_param, addr_reset) >> 2) < words) && + (table->addr_reset & (1UL << 29))) { + /* dedicated 4-byte-address instructions, hopefully these ... + * this entry is unfortunately optional as well + * a subsequent 4-byte address table may overwrite this */ + dev->read_cmd = 0x13; + dev->pprog_cmd = 0x12; + dev->erase_cmd = 0xDC; + if (dev->qread_cmd != 0) + dev->qread_cmd = 0xEC; + } else if (((table->fast_addr >> 17) & 0x3) == 0x1) + LOG_INFO("device has to be switched to 4-byte addresses"); + } + } else if (id == SFDP_4BYTE_ADDR) { + struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *) ptable; + + if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234) + + sizeof(table->erase_t1234)) >> 2) { + LOG_INFO("4-byte address parameter table"); + + /* read and page program instructions */ + if (table->flags & (1UL << 0)) + dev->read_cmd = 0x13; + if (table->flags & (1UL << 5)) + dev->qread_cmd = 0xEC; + if (table->flags & (1UL << 6)) + dev->pprog_cmd = 0x12; + + /* erase instructions */ + if ((erase_type == 1) && (table->flags & (1UL << 9))) + dev->erase_cmd = (table->erase_t1234 >> 0) & 0xFF; + else if ((erase_type == 2) && (table->flags & (1UL << 10))) + dev->erase_cmd = (table->erase_t1234 >> 8) & 0xFF; + else if ((erase_type == 3) && (table->flags & (1UL << 11))) + dev->erase_cmd = (table->erase_t1234 >> 16) & 0xFF; + else if ((erase_type == 4) && (table->flags & (1UL << 12))) + dev->erase_cmd = (table->erase_t1234 >> 24) & 0xFF; + } else + LOG_ERROR("parameter table id=0x%04" PRIx16 " invalid length %d", id, words); + } else + LOG_DEBUG("unimplemented parameter table id=0x%04" PRIx16, id); + + free(ptable); + ptable = NULL; + } + + if (erase_type != 0) { + LOG_INFO("valid SFDP detected"); + retval = ERROR_OK; + } else { + LOG_ERROR("incomplete/invalid SFDP"); + retval = ERROR_FLASH_BANK_NOT_PROBED; + } + +err: + free(pheaders); + free(ptable); + + return retval; +} diff --git a/src/flash/nor/sfdp.h b/src/flash/nor/sfdp.h new file mode 100644 index 000000000..f924a4e55 --- /dev/null +++ b/src/flash/nor/sfdp.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (C) 2019 by Andreas Bolsch . * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_SFDP_H +#define OPENOCD_FLASH_NOR_SFDP_H + +/* per JESD216D 'addr' is *byte* based but must be word aligned, + * 'buffer' is word based, word aligned and always little-endian encoded, + * in the flash, 'addr_len' is 3 or 4, 'dummy' ***usually*** 8 + * + * the actual number of dummy clocks should be worked out by this function + * dynamically, i.e. by scanning the first few bytes for the SFDP signature + * + * buffer contents is supposed to be returned in ***host*** endianness */ +typedef int (*read_sfdp_block_t)(struct flash_bank *bank, uint32_t addr, + uint32_t words, uint32_t *buffer); + +extern int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, + read_sfdp_block_t read_sfdp_block); + +#endif /* OPENOCD_FLASH_NOR_SFDP_H */ diff --git a/src/flash/nor/spi.h b/src/flash/nor/spi.h index 11c381fbd..f8a0a6580 100644 --- a/src/flash/nor/spi.h +++ b/src/flash/nor/spi.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2018 by Andreas Bolsch * + * Copyright (C) 2018-2019 by Andreas Bolsch * * andreas.bolsch@mni.thm.de * * * * Copyright (C) 2012 by George Harris * @@ -29,7 +29,7 @@ /* data structure to maintain flash ids from different vendors */ struct flash_device { - char *name; + const char *name; uint8_t read_cmd; uint8_t qread_cmd; uint8_t pprog_cmd; @@ -87,6 +87,8 @@ extern const struct flash_device flash_devices[]; #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ #define SPIFLASH_FAST_READ 0x0B /* Fast Read */ #define SPIFLASH_READ 0x03 /* Normal Read */ +#define SPIFLASH_MASS_ERASE 0xC7 /* Mass Erase */ +#define SPIFLASH_READ_SFDP 0x5A /* Read Serial Flash Discoverable Parameters */ #define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */ diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c new file mode 100644 index 000000000..486ee53ce --- /dev/null +++ b/src/flash/nor/stmqspi.c @@ -0,0 +1,2452 @@ +/*************************************************************************** + * Copyright (C) 2016 - 2019 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * + * Copyright (C) 2010 by Antonio Borneo * + * borneo.antonio@gmail.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +/* STM QuadSPI (QSPI) and OctoSPI (OCTOSPI) controller are SPI bus controllers + * specifically designed for SPI memories. + * Two working modes are available: + * - indirect mode: the SPI is controlled by SW. Any custom commands can be sent + * on the bus. + * - memory mapped mode: the SPI is under QSPI/OCTOSPI control. Memory content + * is directly accessible in CPU memory space. CPU can read and execute from + * memory (but not write to) */ + +/* ATTENTION: + * To have flash mapped in CPU memory space, the QSPI/OCTOSPI controller + * has to be in "memory mapped mode". This requires following constraints: + * 1) The command "reset init" has to initialize QSPI/OCTOSPI controller and put + * it in memory mapped mode; + * 2) every command in this file has to return to prompt in memory mapped mode. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include +#include +#include "stmqspi.h" +#include "sfdp.h" + +/* deprecated */ +#undef SPIFLASH_READ +#undef SPIFLASH_PAGE_PROGRAM + +#define READ_REG(a) \ +({ \ + uint32_t _result; \ + \ + retval = target_read_u32(target, io_base + (a), &_result); \ + (retval == ERROR_OK) ? _result : 0x0; \ +}) + +/* saved mode settings */ +#define QSPI_MODE (stmqspi_info->saved_ccr & \ + (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4)) + +/* saved read mode settings but indirect read instead of memory mapped + * in particular, use the dummy cycle setting from this saved setting */ +#define QSPI_CCR_READ (QSPI_READ_MODE | (stmqspi_info->saved_ccr & \ + (0xF0000000U | QSPI_DCYC_MASK | QSPI_4LINE_MODE | QSPI_ALTB_MODE | QSPI_ADDR4 | 0xFF))) + +/* QSPI_CCR for various other commands, these never use dummy cycles nor alternate bytes */ +#define QSPI_CCR_READ_STATUS \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_STATUS)) + +#define QSPI_CCR_READ_ID \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_ID)) + +#define QSPI_CCR_READ_MID \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | SPIFLASH_READ_MID)) + +/* always use 3-byte addresses for read SFDP */ +#define QSPI_CCR_READ_SFDP \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & ~QSPI_ADDR4 & QSPI_NO_ALTB) | \ + (QSPI_READ_MODE | QSPI_ADDR3 | SPIFLASH_READ_SFDP)) + +#define QSPI_CCR_WRITE_ENABLE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | SPIFLASH_WRITE_ENABLE)) + +#define QSPI_CCR_SECTOR_ERASE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.erase_cmd)) + +#define QSPI_CCR_MASS_ERASE \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ADDR & QSPI_NO_ALTB & QSPI_NO_DATA) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.chip_erase_cmd)) + +#define QSPI_CCR_PAGE_PROG \ + ((QSPI_MODE & ~QSPI_DCYC_MASK & QSPI_NO_ALTB) | \ + (QSPI_WRITE_MODE | stmqspi_info->dev.pprog_cmd)) + +/* saved mode settings */ +#define OCTOSPI_MODE (stmqspi_info->saved_cr & 0xCFFFFFFF) + +#define OPI_MODE ((stmqspi_info->saved_ccr & OCTOSPI_ISIZE_MASK) != 0) + +#define OCTOSPI_MODE_CCR (stmqspi_info->saved_ccr & \ + (0xF0000000U | OCTOSPI_8LINE_MODE | OCTOSPI_ALTB_MODE | OCTOSPI_ADDR4)) + +/* use saved ccr for read */ +#define OCTOSPI_CCR_READ OCTOSPI_MODE_CCR + +/* OCTOSPI_CCR for various other commands, these never use alternate bytes * + * for READ_STATUS and READ_ID, 4-byte address 0 * + * 4 dummy cycles must sent in OPI mode when DQS is disabled. However, when * + * DQS is enabled, some STM32 devices need at least 6 dummy cycles for * + * proper operation, but otherwise the actual number has no effect! * + * E.g. RM0432 Rev. 7 is incorrect regarding this: L4R9 works well with 4 * + * dummy clocks whereas L4P5 not at all. * + */ +#define OPI_DUMMY \ + ((stmqspi_info->saved_ccr & OCTOSPI_DQSEN) ? 6U : 4U) + +#define OCTOSPI_CCR_READ_STATUS \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ + (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) + +#define OCTOSPI_CCR_READ_ID \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & \ + (OPI_MODE ? ~0U : OCTOSPI_NO_ADDR) & OCTOSPI_NO_ALTB)) + +#define OCTOSPI_CCR_READ_MID OCTOSPI_CCR_READ_ID + +/* 4-byte address in octo mode, else 3-byte address for read SFDP */ +#define OCTOSPI_CCR_READ_SFDP(len) \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & ~OCTOSPI_ADDR4 & OCTOSPI_NO_ALTB) | \ + ((len < 4) ? OCTOSPI_ADDR3 : OCTOSPI_ADDR4)) + +#define OCTOSPI_CCR_WRITE_ENABLE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_SECTOR_ERASE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_MASS_ERASE \ + ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) + +#define OCTOSPI_CCR_PAGE_PROG \ + ((OCTOSPI_MODE_CCR & QSPI_NO_ALTB)) + +#define SPI_ADSIZE (((stmqspi_info->saved_ccr >> SPI_ADSIZE_POS) & 0x3) + 1) + +#define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t) cmd)<<8) | (~cmd & 0xFFU)) : cmd)) + +#define OCTOSPI_CMD(mode, ccr, ir) \ +({ \ + retval = target_write_u32(target, io_base + OCTOSPI_CR, \ + OCTOSPI_MODE | mode); \ + if (retval == ERROR_OK) \ + retval = target_write_u32(target, io_base + OCTOSPI_TCR, \ + (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | \ + ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ? \ + (OPI_DUMMY<driver_priv = stmqspi_info; + stmqspi_info->sfdp_dummy1 = 0; + stmqspi_info->sfdp_dummy2 = 0; + stmqspi_info->probed = false; + stmqspi_info->io_base = io_base; + + return ERROR_OK; +} + +/* Poll busy flag */ +/* timeout in ms */ +static int poll_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint32_t spi_sr; + int retval; + long long endtime; + + endtime = timeval_ms() + timeout; + do { + spi_sr = READ_REG(SPI_SR); + if ((spi_sr & (1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + int retval; + + /* Reset Address register bits 0 and 1, see various errata sheets */ + retval = target_write_u32(target, io_base + SPI_AR, 0x0); + if (retval != ERROR_OK) + return retval; + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<saved_ccr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + OCTOSPI_TCR, + stmqspi_info->saved_tcr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + OCTOSPI_IR, + stmqspi_info->saved_ir); + } else { + retval = target_write_u32(target, io_base + QSPI_CR, + stmqspi_info->saved_cr); + if (retval == ERROR_OK) + retval = target_write_u32(target, io_base + QSPI_CCR, + stmqspi_info->saved_ccr); + } + return retval; +} + +/* Read the status register of the external SPI flash chip(s). */ +static int read_status_reg(struct flash_bank *bank, uint16_t *status) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t data; + int count, retval; + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<saved_cr & (1U< 0; --count) { + if ((stmqspi_info->saved_cr & ((1U<saved_cr & ((1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint16_t status; + int retval; + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<saved_cr & ((1U<>= 8; + if (((stmqspi_info->saved_cr & ((1U<driver_priv; + target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (stmqspi_info->dev.chip_erase_cmd == 0x00) { + LOG_ERROR("Mass erase not available for this device"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + for (sector = 0; sector < bank->num_sectors; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + io_base = stmqspi_info->io_base; + duration_start(&bench); + + retval = qspi_write_enable(bank); + if (retval != ERROR_OK) + goto err; + + /* Send Mass Erase command */ + if (IS_OCTOSPI) + retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_MASS_ERASE, + stmqspi_info->dev.chip_erase_cmd); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_MASS_ERASE); + if (retval != ERROR_OK) + goto err; + + /* Wait for transmit of command completed */ + poll_busy(bank, SPI_CMD_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read flash status register(s) */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + goto err; + + /* Check for command in progress for flash 1 */ + if (((stmqspi_info->saved_cr & ((1U<>= 8; + if (((stmqspi_info->saved_cr & ((1U<num_sectors; sector++) + bank->sectors[sector].is_erased = 1; + + command_print(CMD, "stmqspi mass erase completed in %fs (%0.3f KiB/s)", + duration_elapsed(&bench), + duration_kbps(&bench, bank->size)); + } else { + command_print(CMD, "stmqspi mass erase not completed even after %fs", + duration_elapsed(&bench)); + } + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int log2u(uint32_t word) +{ + int result; + + for (result = 0; (unsigned int) result < sizeof(uint32_t) * CHAR_BIT; result++) + if (word == (1UL<saved_cr & (1U< 10)) + return ERROR_COMMAND_SYNTAX_ERROR; + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, index++, &bank); + if (ERROR_OK != retval) + return retval; + + target = bank->target; + stmqspi_info = bank->driver_priv; + + /* invalidate all old info */ + if (stmqspi_info->probed) + free(bank->sectors); + bank->size = 0; + bank->num_sectors = 0; + bank->sectors = NULL; + stmqspi_info->sfdp_dummy1 = 0; + stmqspi_info->sfdp_dummy2 = 0; + stmqspi_info->probed = false; + memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); + stmqspi_info->dev.name = "unknown"; + + strncpy(stmqspi_info->devname, CMD_ARGV[index++], sizeof(stmqspi_info->devname) - 1); + stmqspi_info->devname[sizeof(stmqspi_info->devname) - 1] = '\0'; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.size_in_bytes); + if (log2u(stmqspi_info->dev.size_in_bytes) < 8) { + command_print(CMD, "stmqspi: device size must be 2^n with n >= 8"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.pagesize); + if (stmqspi_info->dev.pagesize > stmqspi_info->dev.size_in_bytes || + (log2u(stmqspi_info->dev.pagesize) < 0)) { + command_print(CMD, "stmqspi: page size must be 2^n and <= device size"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.read_cmd); + if ((stmqspi_info->dev.read_cmd != 0x03) && + (stmqspi_info->dev.read_cmd != 0x13)) { + command_print(CMD, "stmqspi: only 0x03/0x13 READ cmd allowed"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.qread_cmd); + if ((stmqspi_info->dev.qread_cmd != 0x00) && + (stmqspi_info->dev.qread_cmd != 0x0B) && + (stmqspi_info->dev.qread_cmd != 0x0C) && + (stmqspi_info->dev.qread_cmd != 0x3B) && + (stmqspi_info->dev.qread_cmd != 0x3C) && + (stmqspi_info->dev.qread_cmd != 0x6B) && + (stmqspi_info->dev.qread_cmd != 0x6C) && + (stmqspi_info->dev.qread_cmd != 0xBB) && + (stmqspi_info->dev.qread_cmd != 0xBC) && + (stmqspi_info->dev.qread_cmd != 0xEB) && + (stmqspi_info->dev.qread_cmd != 0xEC) && + (stmqspi_info->dev.qread_cmd != 0xEE)) { + command_print(CMD, "stmqspi: only 0x0B/0x0C/0x3B/0x3C/" + "0x6B/0x6C/0xBB/0xBC/0xEB/0xEC/0xEE QREAD allowed"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.pprog_cmd); + if ((stmqspi_info->dev.pprog_cmd != 0x02) && + (stmqspi_info->dev.pprog_cmd != 0x12) && + (stmqspi_info->dev.pprog_cmd != 0x32)) { + command_print(CMD, "stmqspi: only 0x02/0x12/0x32 PPRG cmd allowed"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.chip_erase_cmd); + else + stmqspi_info->dev.chip_erase_cmd = 0x00; + + if (index < CMD_ARGC) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], stmqspi_info->dev.sectorsize); + if ((stmqspi_info->dev.sectorsize > stmqspi_info->dev.size_in_bytes) || + (stmqspi_info->dev.sectorsize < stmqspi_info->dev.pagesize) || + (log2u(stmqspi_info->dev.sectorsize) < 0)) { + command_print(CMD, "stmqspi: sector size must be 2^n and <= device size"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (index < CMD_ARGC) + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], stmqspi_info->dev.erase_cmd); + else + return ERROR_COMMAND_SYNTAX_ERROR; + } else { + /* no sector size / sector erase cmd given, treat whole bank as a single sector */ + stmqspi_info->dev.erase_cmd = 0x00; + stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; + } + + /* set correct size value */ + bank->size = stmqspi_info->dev.size_in_bytes << dual; + + io_base = stmqspi_info->io_base; + fsize = (READ_REG(SPI_DCR)>>SPI_FSIZE_POS) & ((1U<size == (1U<<(fsize + 1))) + LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); + else if (bank->size == (1U<<(fsize + 0))) + LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); + else + LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); + + /* create and fill sectors array */ + bank->num_sectors = + stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (sectors == NULL) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); + sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + stmqspi_info->dev.name = stmqspi_info->devname; + if (stmqspi_info->dev.size_in_bytes / 4096) + LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 "kbytes," + " bank size = %" PRIu32 "kbytes", stmqspi_info->dev.name, + stmqspi_info->dev.size_in_bytes / 1024, + (stmqspi_info->dev.size_in_bytes / 1024)<dev.name, + stmqspi_info->dev.size_in_bytes, + stmqspi_info->dev.size_in_bytes<probed = true; + + return ERROR_OK; +} + +COMMAND_HANDLER(stmqspi_handle_cmd) +{ + struct target *target = NULL; + struct flash_bank *bank; + struct stmqspi_flash_bank *stmqspi_info = NULL; + uint32_t io_base, addr; + uint8_t num_write, num_read, cmd_byte, data; + unsigned int count; + const int max = 21; + char temp[4], output[(2 + max + 256) * 3 + 8]; + int retval; + + LOG_DEBUG("%s", __func__); + + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + num_write = CMD_ARGC - 2; + if (num_write > max) { + LOG_ERROR("at most %d bytes may be sent", max); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + target = bank->target; + stmqspi_info = bank->driver_priv; + io_base = stmqspi_info->io_base; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], num_read); + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[2], cmd_byte); + + if (num_read == 0) { + /* nothing to read, then one command byte and for dual flash + * an *even* number of data bytes to follow */ + if (stmqspi_info->saved_cr & (1U<saved_cr & (1U< 5)) { + LOG_ERROR("one cmd and up to four addr bytes must be send when reading"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U< ", sizeof(output) - strlen(output) - 1); + } else { + /* read, pack additional bytes into address */ + addr = 0; + for (count = 3; count < CMD_ARGC; count++) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[count], data); + snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); + addr = (addr << 8) | data; + strncat(output, temp, sizeof(output) - strlen(output) - 1); + } + strncat(output, "-> ", sizeof(output) - strlen(output) - 1); + + /* send cmd byte, if ADMODE indicates no address, this already triggers command */ + retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t) num_read) - 1); + if (retval != ERROR_OK) + goto err; + if (IS_OCTOSPI) + retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, + (OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 & + ((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) | + (((num_write - 2) & 0x3U)< 1) { + /* if ADMODE indicates address required, only the write to AR triggers command */ + retval = target_write_u32(target, io_base + SPI_AR, addr); + if (retval != ERROR_OK) + goto err; + } + + /* read response bytes */ + for ( ; num_read > 0; num_read--) { + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data); + strncat(output, temp, sizeof(output) - strlen(output) - 1); + } + } + command_print(CMD, "%s", output); + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint16_t status; + int retval; + + retval = qspi_write_enable(bank); + if (retval != ERROR_OK) + goto err; + + /* Send Sector Erase command */ + if (IS_OCTOSPI) + retval = OCTOSPI_CMD(OCTOSPI_WRITE_MODE, OCTOSPI_CCR_SECTOR_ERASE, + stmqspi_info->dev.erase_cmd); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_SECTOR_ERASE); + if (retval != ERROR_OK) + goto err; + + /* Address is sector offset, this write initiates command transmission */ + retval = target_write_u32(target, io_base + SPI_AR, bank->sectors[sector].offset); + if (retval != ERROR_OK) + goto err; + + /* Wait for transmit of command completed */ + poll_busy(bank, SPI_CMD_TIMEOUT); + if (retval != ERROR_OK) + goto err; + + /* Read flash status register(s) */ + retval = read_status_reg(bank, &status); + if (retval != ERROR_OK) + goto err; + + LOG_DEBUG("erase status regs: 0x%04" PRIx16, status); + + /* Check for command in progress for flash 1 */ + /* If BSY and WE are already cleared the erase did probably complete already */ + if (((stmqspi_info->saved_cr & ((1U<>= 8; + if (((stmqspi_info->saved_cr & ((1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + unsigned int sector; + int retval = ERROR_OK; + + LOG_DEBUG("%s: from sector %u to sector %u", __func__, first, last); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (stmqspi_info->dev.erase_cmd == 0x00) { + LOG_ERROR("Sector erase not available for this device"); + return ERROR_FLASH_OPER_UNSUPPORTED; + } + + if ((last < first) || (last >= bank->num_sectors)) { + LOG_ERROR("Flash sector invalid"); + return ERROR_FLASH_SECTOR_INVALID; + } + + for (sector = first; sector <= last; sector++) { + if (bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + for (sector = first; sector <= last; sector++) { + retval = qspi_erase_sector(bank, sector); + if (retval != ERROR_OK) + break; + alive_sleep(10); + keep_alive(); + } + + if (retval != ERROR_OK) + LOG_ERROR("Flash sector_erase failed on sector %u", sector); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_protect(struct flash_bank *bank, int set, + unsigned int first, unsigned int last) +{ + unsigned int sector; + + for (sector = first; sector <= last; sector++) + bank->sectors[sector].is_protected = set; + + if (set) + LOG_WARNING("setting soft protection only, not related to flash's hardware write protection"); + + return ERROR_OK; +} + +/* Check whether flash is blank */ +static int stmqspi_blank_check(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + struct duration bench; + struct reg_param reg_params[2]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + const uint8_t *code; + struct sector_info erase_check_info; + uint32_t codesize, maxsize, result, exit_point; + unsigned int count, index, num_sectors, sector; + int retval; + const uint32_t erased = 0x00FF; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<saved_tcr), + h_to_le_32(stmqspi_info->saved_ir), + }, + }; + + maxsize = target_get_working_area_avail(target); + if (maxsize < codesize + sizeof(erase_check_info)) { + LOG_ERROR("Not enough working area, can't do QSPI blank check"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + num_sectors = (maxsize - codesize) / sizeof(erase_check_info); + num_sectors = (bank->num_sectors < num_sectors) ? bank->num_sectors : num_sectors; + + if (target_alloc_working_area_try(target, + codesize + num_sectors * sizeof(erase_check_info), &algorithm) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare blank check code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + if (retval != ERROR_OK) + goto err; + + duration_start(&bench); + + /* after breakpoint instruction (halfword), one nop (halfword) and + * port_buffer till end of code */ + exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); + + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* sector count */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + + sector = 0; + while (sector < bank->num_sectors) { + /* at most num_sectors sectors to handle in one run */ + count = bank->num_sectors - sector; + if (count > num_sectors) + count = num_sectors; + + for (index = 0; index < count; index++) { + erase_check_info.offset = h_to_le_32(bank->sectors[sector + index].offset); + erase_check_info.size = h_to_le_32(bank->sectors[sector + index].size); + erase_check_info.result = h_to_le_32(erased); + + retval = target_write_buffer(target, algorithm->address + + codesize + index * sizeof(erase_check_info), + sizeof(erase_check_info), (uint8_t *) &erase_check_info); + if (retval != ERROR_OK) + goto err; + } + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, stmqspi_info->io_base); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + LOG_DEBUG("checking sectors %u to %u", sector, sector + count - 1); + /* check a block of sectors */ + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address, exit_point, + count * ((bank->sectors[sector].size >> 6) + 1) + 1000, + &armv7m_info); + if (retval != ERROR_OK) + break; + + for (index = 0; index < count; index++) { + retval = target_read_buffer(target, algorithm->address + + codesize + index * sizeof(erase_check_info), + sizeof(erase_check_info), (uint8_t *) &erase_check_info); + if (retval != ERROR_OK) + goto err; + + if ((erase_check_info.offset != h_to_le_32(bank->sectors[sector + index].offset)) || + (erase_check_info.size != 0)) { + LOG_ERROR("corrupted blank check info"); + goto err; + } + + /* we need le_32_to_h, but that's the same as h_to_le_32 */ + result = h_to_le_32(erase_check_info.result); + bank->sectors[sector + index].is_erased = ((result & 0xFF) == 0xFF); + LOG_DEBUG("Flash sector %u checked: 0x%04" PRIx16, sector + index, result & 0xFFFF); + } + keep_alive(); + sector += count; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + + duration_measure(&bench); + LOG_INFO("stmqspi blank checked in %fs (%0.3f KiB/s)", duration_elapsed(&bench), + duration_kbps(&bench, bank->size)); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +/* Verify checksum */ +static int qspi_verify(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + struct reg_param reg_params[4]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + const uint8_t *code; + uint32_t pagesize, codesize, crc32, result, exit_point; + int retval; + + /* see contrib/loaders/flash/stmqspi/stmqspi_crc32.S for src */ + static const uint8_t stmqspi_crc32_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmqspi_crc32.inc" + }; + + /* see contrib/loaders/flash/stmqspi/stmoctospi_crc32.S for src */ + static const uint8_t stmoctospi_crc32_code[] = { + #include "../../../contrib/loaders/flash/stmqspi/stmoctospi_crc32.inc" + }; + + if (IS_OCTOSPI) { + code = stmoctospi_crc32_code; + codesize = sizeof(stmoctospi_crc32_code); + } else { + code = stmqspi_crc32_code; + codesize = sizeof(stmqspi_crc32_code); + } + + /* block size doesn't matter that much here */ + pagesize = stmqspi_info->dev.sectorsize; + if (pagesize == 0) + pagesize = stmqspi_info->dev.pagesize; + if (pagesize == 0) + pagesize = SPIFLASH_DEF_PAGESIZE; + + /* adjust size according to dual flash mode */ + pagesize = (stmqspi_info->saved_cr & (1U<saved_tcr), + h_to_le_32(stmqspi_info->saved_ir), + }, + }; + + if (target_alloc_working_area_try(target, codesize, &algorithm) != ERROR_OK) { + LOG_ERROR("Not enough working area, can't do QSPI verify"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare verify code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + if (retval != ERROR_OK) + goto err; + + /* after breakpoint instruction (halfword), one nop (halfword) and + * port_buffer till end of code */ + exit_point = algorithm->address + codesize - sizeof(uint32_t) - sizeof(ccr_buffer); + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), crc32 (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* offset into flash address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, pagesize); + buf_set_u32(reg_params[2].value, 0, 32, offset); + buf_set_u32(reg_params[3].value, 0, 32, stmqspi_info->io_base); + + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address, exit_point, + (count >> 5) + 1000, + &armv7m_info); + keep_alive(); + + image_calculate_checksum(buffer, count, &crc32); + + if (retval == ERROR_OK) { + result = buf_get_u32(reg_params[0].value, 0, 32); + LOG_DEBUG("addr " TARGET_ADDR_FMT ", len 0x%08" PRIx32 ", crc 0x%08" PRIx32 " 0x%08" PRIx32, + offset + bank->base, count, ~crc32, result); + if (~crc32 != result) + retval = ERROR_FAIL; + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int qspi_read_write_block(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count, bool write) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + struct reg_param reg_params[6]; + struct armv7m_algorithm armv7m_info; + struct working_area *algorithm; + uint32_t pagesize, fifo_start, fifosize, remaining; + uint32_t maxsize, codesize, exit_point; + const uint8_t *code = NULL; + unsigned int dual; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " len=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & (1U<saved_tcr & ~OCTOSPI_DCYC_MASK) | + (OPI_MODE ? (OPI_DUMMY<saved_tcr & ~OCTOSPI_DCYC_MASK), + h_to_le_32(OPI_CMD(SPIFLASH_WRITE_ENABLE)), + }, + { + h_to_le_32(OCTOSPI_MODE | (write ? OCTOSPI_WRITE_MODE : OCTOSPI_READ_MODE)), + h_to_le_32(write ? (IS_OCTOSPI ? OCTOSPI_CCR_PAGE_PROG : QSPI_CCR_PAGE_PROG) : + (IS_OCTOSPI ? OCTOSPI_CCR_READ : QSPI_CCR_READ)), + h_to_le_32(write ? (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) : + stmqspi_info->saved_tcr), + h_to_le_32(write ? OPI_CMD(stmqspi_info->dev.pprog_cmd) : stmqspi_info->saved_ir), + }, + }; + + /* force reasonable defaults */ + fifosize = stmqspi_info->dev.sectorsize ? + stmqspi_info->dev.sectorsize : stmqspi_info->dev.size_in_bytes; + + if (write) { + if (IS_OCTOSPI) { + code = stmoctospi_write_code; + codesize = sizeof(stmoctospi_write_code); + } else { + code = stmqspi_write_code; + codesize = sizeof(stmqspi_write_code); + } + } else { + if (IS_OCTOSPI) { + code = stmoctospi_read_code; + codesize = sizeof(stmoctospi_read_code); + } else { + code = stmqspi_read_code; + codesize = sizeof(stmqspi_read_code); + } + } + + /* for write, pagesize must be taken into account */ + /* for read, the page size doesn't matter that much */ + pagesize = stmqspi_info->dev.pagesize; + if (pagesize == 0) + pagesize = (fifosize <= SPIFLASH_DEF_PAGESIZE) ? + fifosize : SPIFLASH_DEF_PAGESIZE; + + /* adjust sizes according to dual flash mode */ + pagesize <<= dual; + fifosize <<= dual; + + /* memory buffer, we assume sectorsize to be a power of 2 times pagesize */ + maxsize = target_get_working_area_avail(target); + if (maxsize < codesize + 2 * sizeof(uint32_t) + pagesize) { + LOG_ERROR("not enough working area, can't do QSPI page reads/writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* fifo size at most sector size, and multiple of page size */ + maxsize -= (codesize + 2 * sizeof(uint32_t)); + fifosize = ((maxsize < fifosize) ? maxsize : fifosize) & ~(pagesize - 1); + + if (target_alloc_working_area_try(target, + codesize + 2 * sizeof(uint32_t) + fifosize, &algorithm) != ERROR_OK) { + LOG_ERROR("allocating working area failed"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + }; + + /* prepare flash write code, excluding ccr_buffer */ + retval = target_write_buffer(target, algorithm->address, + codesize - sizeof(ccr_buffer), code); + if (retval != ERROR_OK) + goto err; + + /* prepare QSPI/OCTOSPI_CCR register values */ + retval = target_write_buffer(target, algorithm->address + + codesize - sizeof(ccr_buffer), + sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + if (retval != ERROR_OK) + goto err; + + /* target buffer starts right after flash_write_code, i.e. + * wp and rp are implicitly included in buffer!!! */ + fifo_start = algorithm->address + codesize + 2 * sizeof(uint32_t); + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* count (in), status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* pagesize */ + init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); /* offset into flash address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* QSPI/OCTOSPI io_base */ + init_reg_param(®_params[4], "r8", 32, PARAM_OUT); /* fifo start */ + init_reg_param(®_params[5], "r9", 32, PARAM_OUT); /* fifo end + 1 */ + + buf_set_u32(reg_params[0].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, pagesize); + buf_set_u32(reg_params[2].value, 0, 32, offset); + buf_set_u32(reg_params[3].value, 0, 32, io_base); + buf_set_u32(reg_params[4].value, 0, 32, fifo_start); + buf_set_u32(reg_params[5].value, 0, 32, fifo_start + fifosize); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + /* after breakpoint instruction (halfword), one nop (halfword) and + * ccr_buffer follow till end of code */ + exit_point = algorithm->address + codesize + - (sizeof(ccr_buffer) + sizeof(uint32_t)); + + if (write) { + retval = target_run_flash_async_algorithm(target, buffer, count, 1, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address + codesize, + fifosize + 2 * sizeof(uint32_t), + algorithm->address, exit_point, + &armv7m_info); + } else { + retval = target_run_read_async_algorithm(target, buffer, count, 1, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + algorithm->address + codesize, + fifosize + 2 * sizeof(uint32_t), + algorithm->address, exit_point, + &armv7m_info); + } + + remaining = buf_get_u32(reg_params[0].value, 0, 32); + if ((retval == ERROR_OK) && remaining) + retval = ERROR_FLASH_OPERATION_FAILED; + + if (retval != ERROR_OK) { + offset = buf_get_u32(reg_params[2].value, 0, 32); + LOG_ERROR("flash %s failed at address 0x%" PRIx32 ", remaining 0x%" PRIx32, + write ? "write" : "read", offset, remaining); + } + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + destroy_reg_param(®_params[5]); + +err: + target_free_working_area(target, algorithm); + + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Read beyond end of flash. Extra data to be ignored."); + count = bank->size - offset; + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + unsigned int dual, sector; + bool octal_dtr; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & (1U<saved_ccr & (1U<state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Write beyond end of flash. Extra data discarded."); + count = bank->size - offset; + } + + /* Check sector protection */ + for (sector = 0; sector < bank->num_sectors; sector++) { + /* Start offset in or before this sector? */ + /* End offset in or behind this sector? */ + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) + && ((offset + count - 1) >= bank->sectors[sector].offset) + && bank->sectors[sector].is_protected) { + LOG_ERROR("Flash sector %u protected", sector); + return ERROR_FLASH_PROTECTED; + } + } + + if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { + LOG_ERROR("In dual-QSPI and octal-DTR modes writes must be two byte aligned: " + "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + unsigned int dual; + bool octal_dtr; + int retval; + + LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, + __func__, offset, count); + + dual = (stmqspi_info->saved_cr & (1U<saved_ccr & (1U<state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!(stmqspi_info->probed)) { + LOG_ERROR("Flash bank not probed"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Verify beyond end of flash. Extra data ignored."); + count = bank->size - offset; + } + + if ((dual || octal_dtr) && ((offset & 1) != 0 || (count & 1) != 0)) { + LOG_ERROR("In dual-QSPI and octal-DTR modes reads must be two byte aligned: " + "%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t data; + unsigned int dual, count; + bool flash1 = !(stmqspi_info->saved_cr & (1U<saved_cr & (1U<saved_cr | (1U<saved_cr); + if (retval != ERROR_OK) + goto err; + + /* Read at most that many bytes */ + retval = target_write_u32(target, io_base + SPI_DLR, (max_bytes << dual) - 1); + if (retval != ERROR_OK) + return retval; + + /* Read SFDP block */ + if (IS_OCTOSPI) + retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), + SPIFLASH_READ_SFDP); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); + if (retval != ERROR_OK) + goto err; + + /* Read from start of sfdp block */ + retval = target_write_u32(target, io_base + SPI_AR, 0); + if (retval != ERROR_OK) + goto err; + + for (count = 0 ; count < max_bytes; count++) { + if ((dual != 0) && !flash1) { + /* discard even byte in dual flash-mode if flash2 */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + } + + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + + if (data == 0x53) { + LOG_DEBUG("start of SFDP header for flash%c after %u dummy bytes", + flash1 ? '1' : '2', count); + if (flash1) + stmqspi_info->sfdp_dummy1 = count; + else + stmqspi_info->sfdp_dummy2 = count; + return ERROR_OK; + } + + if ((dual != 0) && flash1) { + /* discard odd byte in dual flash-mode if flash1 */ + retval = target_read_u8(target, io_base + SPI_DR, &data); + if (retval != ERROR_OK) + goto err; + } + } + + retval = ERROR_FAIL; + LOG_DEBUG("no start of SFDP header even after %u dummy bytes", count); + +err: + /* Abort operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + bool flash1 = !(stmqspi_info->saved_cr & (1U<saved_cr & (1U<saved_ccr >> SPI_DMODE_POS) & 0x7) > 3)) { + /* in OCTO mode 4-byte address and (yet) unknown number of dummy clocks */ + len = 4; + + /* in octo mode, use sfdp_dummy1 only */ + dummy = &stmqspi_info->sfdp_dummy1; + if (*dummy == 0) { + retval = find_sfdp_dummy(bank, len); + if (retval != ERROR_OK) + return retval; + } + } else { + /* in all other modes 3-byte-address and 8(?) dummy clocks */ + len = 3; + + /* use sfdp_dummy1/2 according to currently selected flash */ + dummy = (stmqspi_info->saved_cr & (1U<sfdp_dummy2 : &stmqspi_info->sfdp_dummy1; + + /* according to SFDP standard, there should always be 8 dummy *CLOCKS* + * giving 1, 2 or 4 dummy *BYTES*, however, this is apparently not + * always implemented correctly, so determine the number of dummy bytes + * dynamically */ + if (*dummy == 0) { + retval = find_sfdp_dummy(bank, len); + if (retval != ERROR_OK) + return retval; + } + } + + LOG_DEBUG("%s: addr=0x%08" PRIx32 " words=0x%08" PRIx32 " dummy=%u", + __func__, addr, words, *dummy); + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + stmqspi_info->saved_cr | (1U<saved_cr); + if (retval != ERROR_OK) + goto err; + + /* Read that many words plus dummy bytes */ + retval = target_write_u32(target, io_base + SPI_DLR, + ((*dummy + words * sizeof(uint32_t)) << dual) - 1); + if (retval != ERROR_OK) + goto err; + + /* Read SFDP block */ + if (IS_OCTOSPI) + retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, OCTOSPI_CCR_READ_SFDP(len), + SPIFLASH_READ_SFDP); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_SFDP); + if (retval != ERROR_OK) + goto err; + + retval = target_write_u32(target, io_base + SPI_AR, addr << dual); + if (retval != ERROR_OK) + goto err; + + /* dummy clocks */ + for (count = *dummy << dual; count > 0; --count) { + retval = target_read_u8(target, io_base + SPI_DR, (uint8_t *) buffer); + if (retval != ERROR_OK) + goto err; + } + + for ( ; words > 0; words--) { + if (dual != 0) { + uint32_t word1, word2; + + retval = target_read_u32(target, io_base + SPI_DR, &word1); + if (retval != ERROR_OK) + goto err; + retval = target_read_u32(target, io_base + SPI_DR, &word2); + if (retval != ERROR_OK) + goto err; + + if (!flash1) { + /* shift odd numbered bytes into even numbered ones */ + word1 >>= 8; + word2 >>= 8; + } + + /* pack even numbered bytes into one word */ + *buffer = (word1 & 0xFFU) | ((word1 & 0xFF0000U) >> 8) | + ((word2 & 0xFFU) << 16) | ((word2 & 0xFF0000U) << 8); + + + } else { + retval = target_read_u32(target, io_base + SPI_DR, buffer); + if (retval != ERROR_OK) + goto err; + } + LOG_DEBUG("raw SFDP data 0x%08" PRIx32, *buffer); + + /* endian correction, sfdp data is always le uint32_t based */ + *buffer = le_to_h_u32((uint8_t *) buffer); + buffer++; + } + +err: + return retval; +} + +/* Return ID of flash device(s) */ +/* On exit, indirect mode is kept */ +static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) +{ + struct target *target = bank->target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + uint32_t io_base = stmqspi_info->io_base; + uint8_t byte; + unsigned int type, count, len1, len2; + int retval; + + /* invalidate both ids */ + *id1 = 0; + *id2 = 0; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* SPIFLASH_READ_MID causes device in octal mode to go berserk, so don't use in this case */ + for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) { + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<saved_cr & (1U< 0; --count) { + if ((stmqspi_info->saved_cr & ((1U<> 8) | ((uint32_t) byte) << 16; + len1++; + } + } + if ((stmqspi_info->saved_cr & ((1U<> 8) | ((uint32_t) byte) << 16; + len2++; + } + } + } + + if (((*id1 != 0x000000) && (*id1 != 0xFFFFFF)) || + ((*id2 != 0x000000) && (*id2 != 0xFFFFFF))) + break; + } + + if ((stmqspi_info->saved_cr & ((1U<saved_cr & ((1U<target; + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + struct flash_sector *sectors = NULL; + uint32_t io_base = stmqspi_info->io_base; + uint32_t id1 = 0, id2 = 0, data = 0; + const struct flash_device *p; + const uint32_t magic = 0xAEF1510E; + unsigned int dual, fsize; + bool octal_dtr; + int retval; + + if (stmqspi_info->probed) { + bank->size = 0; + bank->num_sectors = 0; + if (bank->sectors) + free(bank->sectors); + bank->sectors = NULL; + memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); + stmqspi_info->sfdp_dummy1 = 0; + stmqspi_info->sfdp_dummy2 = 0; + stmqspi_info->probed = false; + } + + /* Abort any previous operation */ + retval = target_write_u32(target, io_base + SPI_CR, + READ_REG(SPI_CR) | (1U<octo = false; + } else if (READ_REG(OCTOSPI_MAGIC) == OCTO_MAGIC_ID) { + LOG_DEBUG("OCTOSPI_MAGIC present"); + stmqspi_info->octo = true; + } else { + LOG_ERROR("No QSPI, no OCTOSPI at 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + + /* save current FSEL and DFM bits in QSPI/OCTOSPI_CR, current QSPI/OCTOSPI_CCR value */ + stmqspi_info->saved_cr = READ_REG(SPI_CR); + if (retval == ERROR_OK) + stmqspi_info->saved_ccr = READ_REG(SPI_CCR); + + if (IS_OCTOSPI) { + uint32_t mtyp; + + mtyp = ((READ_REG(OCTOSPI_DCR1) & OCTOSPI_MTYP_MASK))>>OCTOSPI_MTYP_POS; + if (retval == ERROR_OK) + stmqspi_info->saved_tcr = READ_REG(OCTOSPI_TCR); + if (retval == ERROR_OK) + stmqspi_info->saved_ir = READ_REG(OCTOSPI_IR); + if ((mtyp != 0x0) && (mtyp != 0x1)) { + retval = ERROR_FAIL; + LOG_ERROR("Only regular SPI protocol supported in OCTOSPI"); + } + if (retval == ERROR_OK) { + LOG_DEBUG("OCTOSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", OCTOSPI_CR 0x%08" + PRIx32 ", OCTOSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, + stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); + } else { + LOG_ERROR("No OCTOSPI at io_base 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + } else { + if (retval == ERROR_OK) { + LOG_DEBUG("QSPI at 0x%08" PRIx64 ", io_base at 0x%08" PRIx32 ", QSPI_CR 0x%08" + PRIx32 ", QSPI_CCR 0x%08" PRIx32 ", %d-byte addr", bank->base, io_base, + stmqspi_info->saved_cr, stmqspi_info->saved_ccr, SPI_ADSIZE); + if (stmqspi_info->saved_ccr & (1U << QSPI_DDRM)) + LOG_WARNING("DDR mode is untested and suffers from some silicon bugs"); + } else { + LOG_ERROR("No QSPI at io_base 0x%08" PRIx32, io_base); + stmqspi_info->probed = false; + stmqspi_info->dev.name = "none"; + return ERROR_FAIL; + } + } + + dual = (stmqspi_info->saved_cr & (1U<saved_ccr & (1U<write_start_alignment = bank->write_end_alignment = 2; + else + bank->write_start_alignment = bank->write_end_alignment = 1; + + /* read and decode flash ID; returns in indirect mode */ + retval = read_flash_id(bank, &id1, &id2); + LOG_DEBUG("id1 0x%06" PRIx32 ", id2 0x%06" PRIx32, id1, id2); + if (retval == ERROR_FLASH_BANK_NOT_PROBED) { + /* no id retrieved, so id must be set manually */ + LOG_INFO("No id - set flash parameters manually"); + retval = ERROR_OK; + goto err; + } + + if (retval != ERROR_OK) + goto err; + + /* identify flash1 */ + for (p = flash_devices; id1 && p->name ; p++) { + if (p->device_id == id1) { + memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); + if (p->size_in_bytes / 4096) + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "kbytes", p->name, id1, p->size_in_bytes / 1024); + else + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "bytes", p->name, id1, p->size_in_bytes); + break; + } + } + + if (id1 && !p->name) { + /* chip not been identified by id, then try SFDP */ + struct flash_device temp; + uint32_t saved_cr = stmqspi_info->saved_cr; + + /* select flash1 */ + stmqspi_info->saved_cr = stmqspi_info->saved_cr & ~(1U<saved_cr = saved_cr; + + if (retval == ERROR_OK) { + LOG_INFO("flash1 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "kbytes", temp.name, id1, temp.size_in_bytes / 1024); + /* save info and retrieved *good* id as spi_sfdp clears all info */ + memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); + stmqspi_info->dev.device_id = id1; + } else { + /* even not identified by SFDP, then give up */ + LOG_WARNING("Unknown flash1 device id = 0x%06" PRIx32 + " - set flash parameters manually", id1); + retval = ERROR_OK; + goto err; + } + } + + /* identify flash2 */ + for (p = flash_devices; id2 && p->name ; p++) { + if (p->device_id == id2) { + if (p->size_in_bytes / 4096) + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "kbytes", p->name, id2, p->size_in_bytes / 1024); + else + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "bytes", p->name, id2, p->size_in_bytes); + + if (!id1) + memcpy(&stmqspi_info->dev, p, sizeof(stmqspi_info->dev)); + else { + if ((stmqspi_info->dev.read_cmd != p->read_cmd) || + (stmqspi_info->dev.qread_cmd != p->qread_cmd) || + (stmqspi_info->dev.pprog_cmd != p->pprog_cmd) || + (stmqspi_info->dev.erase_cmd != p->erase_cmd) || + (stmqspi_info->dev.chip_erase_cmd != p->chip_erase_cmd) || + (stmqspi_info->dev.sectorsize != p->sectorsize) || + (stmqspi_info->dev.size_in_bytes != p->size_in_bytes)) { + LOG_ERROR("Incompatible flash1/flash2 devices"); + goto err; + } + /* page size is optional in SFDP, so accept smallest value */ + if (p->pagesize < stmqspi_info->dev.pagesize) + stmqspi_info->dev.pagesize = p->pagesize; + } + break; + } + } + + if (id2 && !p->name) { + /* chip not been identified by id, then try SFDP */ + struct flash_device temp; + uint32_t saved_cr = stmqspi_info->saved_cr; + + /* select flash2 */ + stmqspi_info->saved_cr = stmqspi_info->saved_cr | (1U<saved_cr = saved_cr; + + if (retval == ERROR_OK) + LOG_INFO("flash2 \'%s\' id = 0x%06" PRIx32 " size = %" PRIu32 + "kbytes", temp.name, id2, temp.size_in_bytes / 1024); + else { + /* even not identified by SFDP, then give up */ + LOG_WARNING("Unknown flash2 device id = 0x%06" PRIx32 + " - set flash parameters manually", id2); + retval = ERROR_OK; + goto err; + } + + if (!id1) + memcpy(&stmqspi_info->dev, &temp, sizeof(stmqspi_info->dev)); + else { + if ((stmqspi_info->dev.read_cmd != temp.read_cmd) || + (stmqspi_info->dev.qread_cmd != temp.qread_cmd) || + (stmqspi_info->dev.pprog_cmd != temp.pprog_cmd) || + (stmqspi_info->dev.erase_cmd != temp.erase_cmd) || + (stmqspi_info->dev.chip_erase_cmd != temp.chip_erase_cmd) || + (stmqspi_info->dev.sectorsize != temp.sectorsize) || + (stmqspi_info->dev.size_in_bytes != temp.size_in_bytes)) { + LOG_ERROR("Incompatible flash1/flash2 devices"); + goto err; + } + /* page size is optional in SFDP, so accept smallest value */ + if (temp.pagesize < stmqspi_info->dev.pagesize) + stmqspi_info->dev.pagesize = temp.pagesize; + } + } + + /* Set correct size value */ + bank->size = stmqspi_info->dev.size_in_bytes << dual; + + fsize = ((READ_REG(SPI_DCR)>>SPI_FSIZE_POS) & ((1U<size == (1U<<(fsize + 1))) + LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); + else if (bank->size == (1U<<(fsize + 0))) + LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); + else + LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); + + /* if no sectors, then treat whole flash as single sector */ + if (stmqspi_info->dev.sectorsize == 0) + stmqspi_info->dev.sectorsize = stmqspi_info->dev.size_in_bytes; + /* if no page_size, then use sectorsize as page_size */ + if (stmqspi_info->dev.pagesize == 0) + stmqspi_info->dev.pagesize = stmqspi_info->dev.sectorsize; + + /* create and fill sectors array */ + bank->num_sectors = stmqspi_info->dev.size_in_bytes / stmqspi_info->dev.sectorsize; + sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + if (sectors == NULL) { + LOG_ERROR("not enough memory"); + retval = ERROR_FAIL; + goto err; + } + + for (unsigned int sector = 0; sector < bank->num_sectors; sector++) { + sectors[sector].offset = sector * (stmqspi_info->dev.sectorsize << dual); + sectors[sector].size = (stmqspi_info->dev.sectorsize << dual); + sectors[sector].is_erased = -1; + sectors[sector].is_protected = 0; + } + + bank->sectors = sectors; + stmqspi_info->probed = true; + +err: + /* Switch to memory mapped mode before return to prompt */ + set_mm_mode(bank); + + return retval; +} + +static int stmqspi_auto_probe(struct flash_bank *bank) +{ + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + + if (stmqspi_info->probed) + return ERROR_OK; + stmqspi_probe(bank); + return ERROR_OK; +} + +static int stmqspi_protect_check(struct flash_bank *bank) +{ + /* Nothing to do. Protection is only handled in SW. */ + return ERROR_OK; +} + +static int get_stmqspi_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; + + if (!(stmqspi_info->probed)) { + snprintf(buf, buf_size, + "\nQSPI flash bank not probed yet\n"); + return ERROR_FLASH_BANK_NOT_PROBED; + } + + snprintf(buf, buf_size, "flash%s%s \'%s\', device id = 0x%06" PRIx32 + ", flash size = %" PRIu32 "%sbytes\n(page size = %" PRIu32 + ", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8 + ", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8 + ", sector size = %" PRIu32 "%sbytes, sector_erase = 0x%02" PRIx8 ")", + ((stmqspi_info->saved_cr & ((1U<saved_cr & ((1U<dev.name, stmqspi_info->dev.device_id, + bank->size / 4096 ? bank->size / 1024 : bank->size, + bank->size / 4096 ? "k" : "", stmqspi_info->dev.pagesize, + stmqspi_info->dev.read_cmd, stmqspi_info->dev.qread_cmd, + stmqspi_info->dev.pprog_cmd, stmqspi_info->dev.chip_erase_cmd, + stmqspi_info->dev.sectorsize / 4096 ? + stmqspi_info->dev.sectorsize / 1024 : stmqspi_info->dev.sectorsize, + stmqspi_info->dev.sectorsize / 4096 ? "k" : "", + stmqspi_info->dev.erase_cmd); + + return ERROR_OK; +} + +static const struct command_registration stmqspi_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = stmqspi_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Mass erase entire flash device.", + }, + { + .name = "set", + .handler = stmqspi_handle_set, + .mode = COMMAND_EXEC, + .usage = "bank_id name chip_size page_size read_cmd qread_cmd pprg_cmd " + "[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]", + .help = "Set params of single flash chip", + }, + { + .name = "cmd", + .handler = stmqspi_handle_cmd, + .mode = COMMAND_EXEC, + .usage = "bank_id num_resp cmd_byte ...", + .help = "Send low-level command cmd_byte and following bytes or read num_resp.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration stmqspi_command_handlers[] = { + { + .name = "stmqspi", + .mode = COMMAND_ANY, + .help = "stmqspi flash command group", + .usage = "", + .chain = stmqspi_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver stmqspi_flash = { + .name = "stmqspi", + .commands = stmqspi_command_handlers, + .flash_bank_command = stmqspi_flash_bank_command, + .erase = stmqspi_erase, + .protect = stmqspi_protect, + .write = stmqspi_write, + .read = stmqspi_read, + .verify = stmqspi_verify, + .probe = stmqspi_probe, + .auto_probe = stmqspi_auto_probe, + .erase_check = stmqspi_blank_check, + .protect_check = stmqspi_protect_check, + .info = get_stmqspi_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/stmqspi.h b/src/flash/nor/stmqspi.h new file mode 100644 index 000000000..d8510ab19 --- /dev/null +++ b/src/flash/nor/stmqspi.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2016 - 2018 by Andreas Bolsch * + * andreas.bolsch@mni.thm.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifndef OPENOCD_FLASH_NOR_STMQSPI_H +#define OPENOCD_FLASH_NOR_STMQSPI_H + +#include "spi.h" + +/* QSPI register offsets */ +#define QSPI_CR (0x00) /* Control register */ +#define QSPI_DCR (0x04) /* Device configuration register */ +#define QSPI_SR (0x08) /* Status register */ +#define QSPI_FCR (0x0C) /* Flag clear register */ +#define QSPI_DLR (0x10) /* Data length register */ +#define QSPI_CCR (0x14) /* Communication configuration register */ +#define QSPI_AR (0x18) /* Address register */ +#define QSPI_ABR (0x1C) /* Alternate bytes register */ +#define QSPI_DR (0x20) /* Data register */ + +/* common bits in QSPI_CR and OCTOSPI_CR */ +#define SPI_FSEL_FLASH 7 /* Select flash 2 */ +#define SPI_DUAL_FLASH 6 /* Dual flash mode */ +#define SPI_ABORT 1 /* Abort bit */ + +/* common bits in QSPI_DCR and OCTOSPI_DCR1 */ +#define SPI_FSIZE_POS 16 /* bit position of FSIZE */ +#define SPI_FSIZE_LEN 5 /* width of FSIZE field */ + +/* common bits in QSPI_SR/FCR and OCTOSPI_SR/FCR */ +#define SPI_BUSY 5 /* Busy flag */ +#define SPI_FTF 2 /* FIFO threshold flag */ +#define SPI_TCF 1 /* Transfer complete flag */ + +/* fields in QSPI_CCR */ +#define QSPI_DDRM 31 /* position of DDRM bit */ +#define SPI_DMODE_POS 24 /* bit position of DMODE */ +#define QSPI_DCYC_POS 18 /* bit position of DCYC */ +#define QSPI_DCYC_LEN 5 /* width of DCYC field */ +#define QSPI_DCYC_MASK (((1U<octo) +#define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR) +#define SPI_DCR (IS_OCTOSPI ? OCTOSPI_DCR1 : QSPI_DCR) +#define SPI_SR (IS_OCTOSPI ? OCTOSPI_SR : QSPI_SR) +#define SPI_FCR (IS_OCTOSPI ? OCTOSPI_FCR : QSPI_FCR) +#define SPI_DLR (IS_OCTOSPI ? OCTOSPI_DLR : QSPI_DLR) +#define SPI_AR (IS_OCTOSPI ? OCTOSPI_AR : QSPI_AR) +#define SPI_DR (IS_OCTOSPI ? OCTOSPI_DR : QSPI_DR) +#define SPI_CCR (IS_OCTOSPI ? OCTOSPI_CCR : QSPI_CCR) + +#endif /* OPENOCD_FLASH_NOR_STMQSPI_H */ diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 278c73e7f..e73dd22f6 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -44,31 +44,31 @@ #define SMI_READ_REG(a) (_SMI_READ_REG(a)) #define _SMI_READ_REG(a) \ { \ - int __a; \ - uint32_t __v; \ + int _ret; \ + uint32_t _value; \ \ - __a = target_read_u32(target, io_base + (a), &__v); \ - if (__a != ERROR_OK) \ - return __a; \ - __v; \ + _ret = target_read_u32(target, io_base + (a), &_value); \ + if (_ret != ERROR_OK) \ + return _ret; \ + _value; \ } #define SMI_WRITE_REG(a, v) \ { \ - int __r; \ + int _retval; \ \ - __r = target_write_u32(target, io_base + (a), (v)); \ - if (__r != ERROR_OK) \ - return __r; \ + _retval = target_write_u32(target, io_base + (a), (v)); \ + if (_retval != ERROR_OK) \ + return _retval; \ } #define SMI_POLL_TFF(timeout) \ { \ - int __r; \ + int _retval; \ \ - __r = poll_tff(target, io_base, timeout); \ - if (__r != ERROR_OK) \ - return __r; \ + _retval = poll_tff(target, io_base, timeout); \ + if (_retval != ERROR_OK) \ + return _retval; \ } #define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \ diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 87c8cede7..66b9a4cb6 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -454,7 +454,8 @@ COMMAND_HANDLER(handle_flash_write_image_command) if (retval != ERROR_OK) return retval; - retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock); + retval = flash_write_unlock_verify(target, &image, &written, auto_erase, + auto_unlock, true, false); if (retval != ERROR_OK) { image_close(&image); return retval; @@ -471,6 +472,58 @@ COMMAND_HANDLER(handle_flash_write_image_command) return retval; } +COMMAND_HANDLER(handle_flash_verify_image_command) +{ + struct target *target = get_current_target(CMD_CTX); + + struct image image; + uint32_t verified; + + int retval; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!target) { + LOG_ERROR("no target selected"); + return ERROR_FAIL; + } + + struct duration bench; + duration_start(&bench); + + if (CMD_ARGC >= 2) { + image.base_address_set = 1; + COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); + } else { + image.base_address_set = 0; + image.base_address = 0x0; + } + + image.start_address_set = 0; + + retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); + if (retval != ERROR_OK) + return retval; + + retval = flash_write_unlock_verify(target, &image, &verified, false, + false, false, true); + if (retval != ERROR_OK) { + image_close(&image); + return retval; + } + + if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { + command_print(CMD, "verified %" PRIu32 " bytes from file %s " + "in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0], + duration_elapsed(&bench), duration_kbps(&bench, verified)); + } + + image_close(&image); + + return retval; +} + COMMAND_HANDLER(handle_flash_fill_command) { target_addr_t address; @@ -1142,7 +1195,15 @@ static const struct command_registration flash_exec_command_handlers[] = { .mode = COMMAND_EXEC, .usage = "[erase] [unlock] filename [offset [file_type]]", .help = "Write an image to flash. Optionally first unprotect " - "and/or erase the region to be used. Allow optional " + "and/or erase the region to be used. Allow optional " + "offset from beginning of bank (defaults to zero)", + }, + { + .name = "verify_image", + .handler = handle_flash_verify_image_command, + .mode = COMMAND_EXEC, + .usage = "filename [offset [file_type]]", + .help = "Verify an image against flash. Allow optional " "offset from beginning of bank (defaults to zero)", }, { diff --git a/src/target/image.c b/src/target/image.c index 0b7debaef..20c6d77b2 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -1019,7 +1019,7 @@ void image_close(struct image *image) image->sections = NULL; } -int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) +int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) { uint32_t crc = 0xffffffff; LOG_DEBUG("Calculating checksum"); diff --git a/src/target/image.h b/src/target/image.h index 765d29022..53c27d812 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -99,7 +99,7 @@ void image_close(struct image *image); int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t const *data); -int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, +int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); #define ERROR_IMAGE_FORMAT_ERROR (-1400) diff --git a/src/target/target.c b/src/target/target.c index 3b1c666e5..db759d9c3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1031,11 +1031,11 @@ int target_run_flash_async_algorithm(struct target *target, * programming. The exact delay shouldn't matter as long as it's * less than buffer size / flash speed. This is very unlikely to * run when using high latency connections such as USB. */ - alive_sleep(10); + alive_sleep(2); /* to stop an infinite loop on some targets check and increment a timeout * this issue was observed on a stellaris using the new ICDI interface */ - if (timeout++ >= 500) { + if (timeout++ >= 2500) { LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); return ERROR_FLASH_OPERATION_FAILED; } @@ -1049,6 +1049,10 @@ int target_run_flash_async_algorithm(struct target *target, if (thisrun_bytes > count * block_size) thisrun_bytes = count * block_size; + /* Force end of large blocks to be word aligned */ + if (thisrun_bytes >= 16) + thisrun_bytes -= (rp + thisrun_bytes) & 0x03; + /* Write data to fifo */ retval = target_write_buffer(target, wp, thisrun_bytes, buffer); if (retval != ERROR_OK) @@ -1098,6 +1102,156 @@ int target_run_flash_async_algorithm(struct target *target, return retval; } +int target_run_read_async_algorithm(struct target *target, + uint8_t *buffer, uint32_t count, int block_size, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t buffer_start, uint32_t buffer_size, + uint32_t entry_point, uint32_t exit_point, void *arch_info) +{ + int retval; + int timeout = 0; + + const uint8_t *buffer_orig = buffer; + + /* Set up working area. First word is write pointer, second word is read pointer, + * rest is fifo data area. */ + uint32_t wp_addr = buffer_start; + uint32_t rp_addr = buffer_start + 4; + uint32_t fifo_start_addr = buffer_start + 8; + uint32_t fifo_end_addr = buffer_start + buffer_size; + + uint32_t wp = fifo_start_addr; + uint32_t rp = fifo_start_addr; + + /* validate block_size is 2^n */ + assert(!block_size || !(block_size & (block_size - 1))); + + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + /* Start up algorithm on target */ + retval = target_start_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, + exit_point, + arch_info); + + if (retval != ERROR_OK) { + LOG_ERROR("error starting target flash read algorithm"); + return retval; + } + + while (count > 0) { + retval = target_read_u32(target, wp_addr, &wp); + if (retval != ERROR_OK) { + LOG_ERROR("failed to get write pointer"); + break; + } + + LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, + (size_t) (buffer - buffer_orig), count, wp, rp); + + if (wp == 0) { + LOG_ERROR("flash read algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if (((wp - fifo_start_addr) & (block_size - 1)) || wp < fifo_start_addr || wp >= fifo_end_addr) { + LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp); + break; + } + + /* Count the number of bytes available in the fifo without + * crossing the wrap around. */ + uint32_t thisrun_bytes; + if (wp >= rp) + thisrun_bytes = wp - rp; + else + thisrun_bytes = fifo_end_addr - rp; + + if (thisrun_bytes == 0) { + /* Throttle polling a bit if transfer is (much) faster than flash + * reading. The exact delay shouldn't matter as long as it's + * less than buffer size / flash speed. This is very unlikely to + * run when using high latency connections such as USB. */ + alive_sleep(2); + + /* to stop an infinite loop on some targets check and increment a timeout + * this issue was observed on a stellaris using the new ICDI interface */ + if (timeout++ >= 2500) { + LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); + return ERROR_FLASH_OPERATION_FAILED; + } + continue; + } + + /* Reset our timeout */ + timeout = 0; + + /* Limit to the amount of data we actually want to read */ + if (thisrun_bytes > count * block_size) + thisrun_bytes = count * block_size; + + /* Force end of large blocks to be word aligned */ + if (thisrun_bytes >= 16) + thisrun_bytes -= (rp + thisrun_bytes) & 0x03; + + /* Read data from fifo */ + retval = target_read_buffer(target, rp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / block_size; + rp += thisrun_bytes; + if (rp >= fifo_end_addr) + rp = fifo_start_addr; + + /* Store updated write pointer to target */ + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + break; + + /* Avoid GDB timeouts */ + keep_alive(); + + } + + if (retval != ERROR_OK) { + /* abort flash write algorithm on target */ + target_write_u32(target, rp_addr, 0); + } + + int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, + 10000, + arch_info); + + if (retval2 != ERROR_OK) { + LOG_ERROR("error waiting for target flash write algorithm"); + retval = retval2; + } + + if (retval == ERROR_OK) { + /* check if algorithm set wp = 0 after fifo writer loop finished */ + retval = target_read_u32(target, wp_addr, &wp); + if (retval == ERROR_OK && wp == 0) { + LOG_ERROR("flash read algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + } + } + + return retval; +} + int target_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { diff --git a/src/target/target.h b/src/target/target.h index ee0bdfb65..44463b74f 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -577,6 +577,18 @@ int target_run_flash_async_algorithm(struct target *target, uint32_t entry_point, uint32_t exit_point, void *arch_info); +/** + * This routine is a wrapper for asynchronous algorithms. + * + */ +int target_run_read_async_algorithm(struct target *target, + uint8_t *buffer, uint32_t count, int block_size, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t buffer_start, uint32_t buffer_size, + uint32_t entry_point, uint32_t exit_point, + void *arch_info); + /** * Read @a count items of @a size bytes from the memory of @a target at * the @a address given. diff --git a/tcl/board/b-l475e-iot01a.cfg b/tcl/board/b-l475e-iot01a.cfg new file mode 100644 index 000000000..be411e49f --- /dev/null +++ b/tcl/board/b-l475e-iot01a.cfg @@ -0,0 +1,56 @@ +# This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip. +# http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 + + # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + + # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER + mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR + mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f412g-disco.cfg b/tcl/board/stm32f412g-disco.cfg new file mode 100644 index 000000000..b6bdb64a5 --- /dev/null +++ b/tcl/board/stm32f412g-disco.cfg @@ -0,0 +1,70 @@ +# This is an STM32F412G discovery board with a single STM32F412ZGT6 chip. +# http://www.st.com/en/evaluation-tools/32f412gdiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PG06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V + + # Port B: PB02:AF09:V + mmw 0x40020400 0x00000020 0x00000010 ;# MODER + mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x00000900 0x00000600 ;# AFRL + + # Port F: PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x40021400 0x000AA000 0x00055000 ;# MODER + mmw 0x40021408 0x000FF000 0x00000000 ;# OSPEEDR + mmw 0x40021420 0x99000000 0x66000000 ;# AFRL + mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH + + # Port G: PG06:AF10:V + mmw 0x40021800 0x00002000 0x00001000 ;# MODER + mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK + sleep 1 + mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 + mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f413h-disco.cfg b/tcl/board/stm32f413h-disco.cfg new file mode 100644 index 000000000..99f2a4933 --- /dev/null +++ b/tcl/board/stm32f413h-disco.cfg @@ -0,0 +1,83 @@ +# This is an STM32F413H discovery board with a single STM32F413ZHT6 chip. +# http://www.st.com/en/evaluation-tools/32f413hdiscovery.html + +# +# Untested!!! +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000000FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOHEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PB02: CLK, PD13: BK1_IO3, PE02: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V + + # Port B: PB02:AF09:V + mmw 0x40020400 0x00000020 0x00000010 ;# MODER + mmw 0x40020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x00000900 0x00000600 ;# AFRL + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + # Port F: PF09:AF10:V, PF08:AF10:V + mmw 0x40021400 0x000A0000 0x00050000 ;# MODER + mmw 0x40021408 0x000F0000 0x00000000 ;# OSPEEDR + mmw 0x40021424 0x000000AA 0x00000055 ;# AFRH + + # Port G: PG06:AF10:V + mmw 0x40021800 0x00002000 0x00001000 ;# MODER + mmw 0x40021808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40021820 0x0A000000 0x05000000 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000003 ;# 3 WS for 96 MHz HCLK + sleep 1 + mww 0x40023804 0x24001808 ;# 96 MHz: HSI, PLLM=8, PLLN=96, PLLP=2 + mww 0x40023808 0x00001000 ;# APB1: /2, APB2: /1 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f469i-disco.cfg b/tcl/board/stm32f469i-disco.cfg new file mode 100644 index 000000000..ab6751225 --- /dev/null +++ b/tcl/board/stm32f469i-disco.cfg @@ -0,0 +1,65 @@ +# This is an STM32F469I discovery board with a single STM32F469NIH6 chip. +# http://www.st.com/en/evaluation-tools/32f469idiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PF10: CLK, PB06: BK1_NCS, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PF08: BK1_IO0 + + # PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + + # Port B: PB06:AF10:V + mmw 0x40020400 0x00002000 0x00001000 ;# MODER + mmw 0x40020408 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000000 0x05000000 ;# AFRL + + # Port F: PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x40021400 0x002AA000 0x00155000 ;# MODER + mmw 0x40021408 0x003FF000 0x00000000 ;# OSPEEDR + mmw 0x40021420 0x99000000 0x66000000 ;# AFRL + mmw 0x40021424 0x000009AA 0x00000655 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000005 ;# 5 WS for 160 MHz HCLK + sleep 1 + mww 0x40023804 0x24002808 ;# 160 MHz: HSI, PLLM=8, PLLN=160, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f723e-disco.cfg b/tcl/board/stm32f723e-disco.cfg new file mode 100644 index 000000000..3c04d86f0 --- /dev/null +++ b/tcl/board/stm32f723e-disco.cfg @@ -0,0 +1,74 @@ +# This is an STM32F723E discovery board with a single STM32F723IEK6 chip. +# http://www.st.com/en/evaluation-tools/32f723ediscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 128KB +set WORKAREASIZE 0x20000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port C: PC10:AF09:V, PC09:AF09:V + mmw 0x40020800 0x00280000 0x00140000 ;# MODER + mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR + mmw 0x40020824 0x00000990 0x00000660 ;# AFRH + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f746g-disco.cfg b/tcl/board/stm32f746g-disco.cfg new file mode 100644 index 000000000..14e89e162 --- /dev/null +++ b/tcl/board/stm32f746g-disco.cfg @@ -0,0 +1,69 @@ +# This is an STM32F746G discovery board with a single STM32F746NGH6 chip. +# http://www.st.com/en/evaluation-tools/32f746gdiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 256KB +set WORKAREASIZE 0x40000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PD12: BK1_IO1, PD11: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V + mmw 0x40020C00 0x0A800000 0x05400000 ;# MODER + mmw 0x40020C08 0x0FC00000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00999000 0x00666000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32f769i-disco.cfg b/tcl/board/stm32f769i-disco.cfg new file mode 100644 index 000000000..cc4334bf4 --- /dev/null +++ b/tcl/board/stm32f769i-disco.cfg @@ -0,0 +1,79 @@ +# This is an STM32F769I discovery board with a single STM32F769NIH6 chip. +# http://www.st.com/en/evaluation-tools/32f769idiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 256KB +set WORKAREASIZE 0x40000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32f7x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x40023830 0x000007FF 0 ;# RCC_AHB1ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x40023838 0x00000002 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB02: CLK, PB06: BK1_NCS, PD13: BK1_IO3, PE02: BK1_IO2, PC10: BK1_IO1, PC09: BK1_IO0 + + # PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V + + # Port B: PB06:AF10:V, PB02:AF09:V + mmw 0x40020400 0x00002020 0x00001010 ;# MODER + mmw 0x40020408 0x00003030 0x00000000 ;# OSPEEDR + mmw 0x40020420 0x0A000900 0x05000600 ;# AFRL + + # Port C: PC10:AF09:V, PC09:AF09:V + mmw 0x40020800 0x00280000 0x00140000 ;# MODER + mmw 0x40020808 0x003C0000 0x00000000 ;# OSPEEDR + mmw 0x40020824 0x00000990 0x00000660 ;# AFRH + + # Port D: PD13:AF09:V + mmw 0x40020C00 0x08000000 0x04000000 ;# MODER + mmw 0x40020C08 0x0C000000 0x00000000 ;# OSPEEDR + mmw 0x40020C24 0x00900000 0x00600000 ;# AFRH + + # Port E: PE02:AF09:V + mmw 0x40021000 0x00000020 0x00000010 ;# MODER + mmw 0x40021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x40021020 0x00000900 0x00000600 ;# AFRL + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x03500008 ;# QUADSPI_CR: PRESCALER=3, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00190100 ;# QUADSPI_DCR: FSIZE=0x19, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # exit qpi mode + mww 0xA0001014 0x000033f5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + + # 1-line memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + + # 4-line qpi mode + mww 0xA0001014 0x00003135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=EQIO + + # 4-line memory-mapped read mode with 4-byte addresses + mww 0xA0001014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0xA, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=4READ4B +} + +$_TARGETNAME configure -event reset-init { + mww 0x40023C00 0x00000006 ;# 6 WS for 192 MHz HCLK + sleep 1 + mww 0x40023804 0x24003008 ;# 192 MHz: PLLM=8, PLLN=192, PLLP=2 + mww 0x40023808 0x00009400 ;# APB1: /4, APB2: /2 + mmw 0x40023800 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40023808 0x00000002 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32h735g-disco.cfg b/tcl/board/stm32h735g-disco.cfg new file mode 100644 index 000000000..405e47024 --- /dev/null +++ b/tcl/board/stm32h735g-disco.cfg @@ -0,0 +1,122 @@ +# This is a stm32h735g-dk with a single STM32H735IGK6 chip. +# https://www.st.com/en/evaluation-tools/stm32h735g-dk.html +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h735igk6 + +# enable stmqspi +if {![info exists OCTOSPI1]} { + set OCTOSPI1 1 + set OCTOSPI2 0 +} + +source [find target/stm32h7x.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x58024540 0x000006FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) + sleep 1 ;# Wait for clock startup + + mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 + mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 + + # PG06: OCSPI1_NCS, PF10: OCSPI1_CLK, PB02: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PD05: OCSPI1_IO5, + # PD04: OCSPI1_IO4, PD13: OCSPI1_IO3, PE02: OCSPI1_IO2, PD12: OCSPI1_IO1, PD11: OCSPI1_IO0 + + # PB02:AF10:V, PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V + # PD04:AF10:V, PE02:AF09:V, PF10:AF09:V, PG09:AF09:V, PG06:AF10:V + # Port B: PB02:AF10:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58020420 0x00000A00 0x00000500 ;# AFRL + # Port D: PD13:AF09:V, PD12:AF09:V, PD11:AF09:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + mmw 0x58020C00 0x0A808A00 0x05404500 ;# MODER + mmw 0x58020C08 0x0FC0CF00 0x00000000 ;# OSPEEDR + mmw 0x58020C0C 0x00000000 0x0FC0CF00 ;# PUPDR + mmw 0x58020C20 0xA0AA0000 0x50550000 ;# AFRL + mmw 0x58020C24 0x00999000 0x00666000 ;# AFRH + # Port E: PE02:AF09:V + mmw 0x58021000 0x00000020 0x00000010 ;# MODER + mmw 0x58021008 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802100C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58021020 0x00000900 0x00000600 ;# AFRL + # Port F: PF10:AF09:V + mmw 0x58021400 0x00200000 0x00100000 ;# MODER + mmw 0x58021408 0x00300000 0x00000000 ;# OSPEEDR + mmw 0x5802140C 0x00000000 0x00300000 ;# PUPDR + mmw 0x58021424 0x00000900 0x00000600 ;# AFRH + # Port G: PG09:AF09:V, PG06:AF10:V + mmw 0x58021800 0x00082000 0x00041000 ;# MODER + mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR + mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x00000090 0x00000060 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 + + mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + flash probe $a ;# load configuration from CR, TCR, CCR, IR register values + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global OCTOSPI1 + global OCTOSPI2 + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $OCTOSPI1 } { + octospi_init 1 + } +} diff --git a/tcl/board/stm32h745i-disco.cfg b/tcl/board/stm32h745i-disco.cfg new file mode 100644 index 000000000..5adcfea16 --- /dev/null +++ b/tcl/board/stm32h745i-disco.cfg @@ -0,0 +1,45 @@ +# This is a stm32h745i-disco with a single STM32H745XIH6 chip. +# www.st.com/en/product/stm32h745i-disco.html +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h745xih6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x_dual_bank.cfg] + +source [find board/stm32h7x_dual_qspi.cfg] + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h747i-disco.cfg b/tcl/board/stm32h747i-disco.cfg new file mode 100644 index 000000000..22fd74aea --- /dev/null +++ b/tcl/board/stm32h747i-disco.cfg @@ -0,0 +1,136 @@ +# This is a stm32h747i-disco with a single STM32H747XIH6 chip. +# www.st.com/en/product/stm32h747i-disco.html +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h747xih6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x_dual_bank.cfg] + +# QUADSPI initialization +# qpi: 4-line mode +proc qspi_init { qpi } { + global a + mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PB02: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, + # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 + + # PB02:AF09:V, PD11:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H + # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V + + # Port B: PB02:AF09:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x58020420 0x00000900 0x00000600 ;# AFRL + # Port D: PD11:AF09:V + mmw 0x58020C00 0x00800000 0x00400000 ;# MODER + mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF09:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x58021400 0x0008A000 0x00045000 ;# MODER + mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR + mmw 0x58021420 0x99000000 0x66000000 ;# AFRL + mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH + # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H + mmw 0x58021800 0x20082000 0x10041000 ;# MODER + mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x09000090 0x06000060 ;# AFRH + # Port H: PH03:AF09:V, PH02:AF09:V + mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER + mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR + mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL + + # correct FSIZE is 0x1A, however, this causes trouble when + # reading the last bytes at end of bank in *memory mapped* mode + + # for dual flash mode 2 * mt25ql512 + mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 + mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 + + mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 + mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # Exit QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI + sleep 1 + + if { $qpi == 1 } { + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Configure dummy clocks via volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. + mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks + sleep 1 + + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Enable QPI mode via enhanced volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. + mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode + sleep 1 + + # Enter QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI + sleep 1 + + # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ + } else { + # memory-mapped read mode with 4-byte addresses + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h750b-disco.cfg b/tcl/board/stm32h750b-disco.cfg new file mode 100644 index 000000000..e6062035a --- /dev/null +++ b/tcl/board/stm32h750b-disco.cfg @@ -0,0 +1,45 @@ +# This is a stm32h750b-dk with a single STM32H750XBH6 chip. +# www.st.com/en/product/stm32h750b-dk.html +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h750xbh6 + +# enable stmqspi +if {![info exists QUADSPI]} { + set QUADSPI 1 +} + +source [find target/stm32h7x.cfg] + +source [find board/stm32h7x_dual_qspi.cfg] + +$_CHIPNAME.cpu0 configure -event reset-init { + global QUADSPI + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $QUADSPI } { + qspi_init 1 + } +} + diff --git a/tcl/board/stm32h7b3i-disco.cfg b/tcl/board/stm32h7b3i-disco.cfg new file mode 100644 index 000000000..e5512eade --- /dev/null +++ b/tcl/board/stm32h7b3i-disco.cfg @@ -0,0 +1,128 @@ +# This is a stm32h7b3i-dk with a single STM32H7B3LIH6Q chip. +# https://www.st.com/en/evaluation-tools/stm32h7b3i-dk.html +# + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +set CHIPNAME stm32h7b3lih6q + +# enable stmqspi +if {![info exists OCTOSPI1]} { + set OCTOSPI1 1 + set OCTOSPI2 0 +} + +source [find target/stm32h7x_dual_bank.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x58024540 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x58024534 0x00284000 0 ;# RCC_AHB3ENR |= IOMNGREN, OSPI2EN, OSPI1EN (enable clocks) + sleep 1 ;# Wait for clock startup + + mww 0x5200B404 0x03010111 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI1 + mww 0x5200B408 0x00000000 ;# OCTOSPIM_P2CR: disable Port 2 + + # PG06: OCSPI1_NCS, PB02: OCSPI1_CLK, PC05: OCSPI1_DQS, PD07: OCSPI1_IO7, PG09: OCSPI1_IO6, PH03: OCSPI1_IO5, + # PC01: OCSPI1_IO4, PF06: OCSPI1_IO3, PF07: OCSPI1_IO2, PF09: OCSPI1_IO1, PD11: OCSPI1_IO0 + + # PB02:AF09:V, PC05:AF10:V, PC01:AF10:V, PD11:AF09:V, PD07:AF10:V, PF09:AF10:V + # PF07:AF10:V, PF06:AF10:V, PG09:AF09:V, PG06:AF10:V, PH03:AF09:V + # Port B: PB02:AF09:V + mmw 0x58020400 0x00000020 0x00000010 ;# MODER + mmw 0x58020408 0x00000030 0x00000000 ;# OSPEEDR + mmw 0x5802040C 0x00000000 0x00000030 ;# PUPDR + mmw 0x58020420 0x00000900 0x00000600 ;# AFRL + # Port C: PC05:AF10:V, PC01:AF10:V + mmw 0x58020800 0x00000808 0x00000404 ;# MODER + mmw 0x58020808 0x00000C0C 0x00000000 ;# OSPEEDR + mmw 0x5802080C 0x00000000 0x00000C0C ;# PUPDR + mmw 0x58020820 0x00A000A0 0x00500050 ;# AFRL + # Port D: PD11:AF09:V, PD07:AF10:V + mmw 0x58020C00 0x00808000 0x00404000 ;# MODER + mmw 0x58020C08 0x00C0C000 0x00000000 ;# OSPEEDR + mmw 0x58020C0C 0x00000000 0x00C0C000 ;# PUPDR + mmw 0x58020C20 0xA0000000 0x50000000 ;# AFRL + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF09:AF10:V, PF07:AF10:V, PF06:AF10:V + mmw 0x58021400 0x0008A000 0x00045000 ;# MODER + mmw 0x58021408 0x000CF000 0x00000000 ;# OSPEEDR + mmw 0x5802140C 0x00000000 0x000CF000 ;# PUPDR + mmw 0x58021420 0xAA000000 0x55000000 ;# AFRL + mmw 0x58021424 0x000000A0 0x00000050 ;# AFRH + # Port G: PG09:AF09:V, PG06:AF10:V + mmw 0x58021800 0x00082000 0x00041000 ;# MODER + mmw 0x58021808 0x000C3000 0x00000000 ;# OSPEEDR + mmw 0x5802180C 0x00000000 0x000C3000 ;# PUPDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x00000090 0x00000060 ;# AFRH + # Port H: PH03:AF09:V + mmw 0x58021C00 0x00000080 0x00000040 ;# MODER + mmw 0x58021C08 0x000000C0 0x00000000 ;# OSPEEDR + mmw 0x58021C0C 0x00000000 0x000000C0 ;# PUPDR + mmw 0x58021C20 0x00009000 0x00006000 ;# AFRL + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0x52005130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0x52005008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0x5200500C 0x00000005 ;# OCTOSPI_DCR2: PRESCALER=5 + + mww 0x52005108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0x52005100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0x52005110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + flash probe $a ;# load configuration from CR, TCR, CCR, IR register values + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0x52005000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0x52005108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0x52005100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0x52005110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_CHIPNAME.cpu0 configure -event reset-init { + global OCTOSPI1 + global OCTOSPI2 + + mmw 0x52002000 0x00000004 0x0000000B ;# FLASH_ACR: 4 WS for 192 MHZ HCLK + + mmw 0x58024400 0x00000001 0x00000018 ;# RCC_CR: HSIDIV=1, HSI on + mmw 0x58024410 0x10000000 0xEE000007 ;# RCC_CFGR: MCO2=system, MCO2PRE=8, HSI as system clock + mww 0x58024418 0x00000040 ;# RCC_D1CFGR: D1CPRE=1, D1PPRE=2, HPRE=1 + mww 0x5802441C 0x00000440 ;# RCC_D2CFGR: D2PPRE2=2, D2PPRE1=2 + mww 0x58024420 0x00000040 ;# RCC_D3CFGR: D3PPRE=2 + mww 0x58024428 0x00000040 ;# RCC_PPLCKSELR: DIVM3=0, DIVM2=0, DIVM1=4, PLLSRC=HSI + mmw 0x5802442C 0x0001000C 0x00000002 ;# RCC_PLLCFGR: PLL1RGE=8MHz to 16MHz, PLL1VCOSEL=wide + mww 0x58024430 0x01070217 ;# RCC_PLL1DIVR: 192 MHz: DIVR1=2, DIVQ=8, DIVP1=2, DIVN1=24 + mmw 0x58024400 0x01000000 0 ;# RCC_CR: PLL1ON=1 + sleep 1 + mmw 0x58024410 0x00000003 0 ;# RCC_CFGR: PLL1 as system clock + sleep 1 + + adapter speed 24000 + + if { $OCTOSPI1 } { + octospi_init 1 + } +} diff --git a/tcl/board/stm32h7x_dual_qspi.cfg b/tcl/board/stm32h7x_dual_qspi.cfg new file mode 100644 index 000000000..bdff9c1b8 --- /dev/null +++ b/tcl/board/stm32h7x_dual_qspi.cfg @@ -0,0 +1,90 @@ +# stm32h754i-disco and stm32h750b-dk dual quad qspi. + +# QUADSPI initialization +# qpi: 4-line mode +proc qspi_init { qpi } { + global a + mmw 0x580244E0 0x000007FF 0 ;# RCC_AHB4ENR |= GPIOAEN-GPIOKEN (enable clocks) + mmw 0x580244D4 0x00004000 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PG06: BK1_NCS, PF10: CLK, PF06: BK1_IO3, PF07: BK1_IO2, PF09: BK1_IO1, PD11: BK1_IO0, + # PG14: BK2_IO3, PG09: BK2_IO2, PH03: BK2_IO1, PH02: BK2_IO0 + + # PD11:AF09:V, PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V, PG14:AF09:H + # PG09:AF09:V, PG06:AF10:H, PH03:AF09:V, PH02:AF09:V + + # Port D: PD11:AF09:V + mmw 0x58020C00 0x00800000 0x00400000 ;# MODER + mmw 0x58020C08 0x00C00000 0x00000000 ;# OSPEEDR + mmw 0x58020C24 0x00009000 0x00006000 ;# AFRH + # Port F: PF10:AF09:V, PF09:AF10:V, PF07:AF09:V, PF06:AF09:V + mmw 0x58021400 0x0028A000 0x00145000 ;# MODER + mmw 0x58021408 0x003CF000 0x00000000 ;# OSPEEDR + mmw 0x58021420 0x99000000 0x66000000 ;# AFRL + mmw 0x58021424 0x000009A0 0x00000650 ;# AFRH + # Port G: PG14:AF09:H, PG09:AF09:V, PG06:AF10:H + mmw 0x58021800 0x20082000 0x10041000 ;# MODER + mmw 0x58021808 0x200C2000 0x10001000 ;# OSPEEDR + mmw 0x58021820 0x0A000000 0x05000000 ;# AFRL + mmw 0x58021824 0x09000090 0x06000060 ;# AFRH + # Port H: PH03:AF09:V, PH02:AF09:V + mmw 0x58021C00 0x000000A0 0x00000050 ;# MODER + mmw 0x58021C08 0x000000F0 0x00000000 ;# OSPEEDR + mmw 0x58021C20 0x00009900 0x00006600 ;# AFRL + + # correct FSIZE is 0x1A, however, this causes trouble when + # reading the last bytes at end of bank in *memory mapped* mode + + # for dual flash mode 2 * mt25ql512 + mww 0x52005000 0x05500058 ;# QUADSPI_CR: PRESCALER=5, APMS=1, FTHRES=0, FSEL=0, DFM=1, SSHIFT=1, TCEN=1 + mww 0x52005004 0x001A0200 ;# QUADSPI_DCR: FSIZE=0x1A, CSHT=0x02, CKMODE=0 + + mww 0x52005030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0x52005014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1 + mmw 0x52005000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # Exit QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=Exit QPI + sleep 1 + + if { $qpi == 1 } { + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Configure dummy clocks via volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000181 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Volatile Conf. Reg. + mwh 0x52005020 0xABAB ;# QUADSPI_DR: 0xAB 0xAB for 10 dummy clocks + sleep 1 + + # Write Enable + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000106 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enable + sleep 1 + + # Enable QPI mode via enhanced volatile configuration register + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005010 0x00000001 ;# QUADSPI_DLR: 2 data bytes + mww 0x52005014 0x01000161 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x1, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Write Enhanced Conf. Reg. + mwh 0x52005020 0x3F3F ;# QUADSPI_DR: 0x3F 0x3F to enable QPI and DPI mode + sleep 1 + + # Enter QPI mode + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x00000135 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x1, INSTR=Enter QPI + sleep 1 + + # memory-mapped fast read mode with 4-byte addresses and 10 dummy cycles (for read only) + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0F283FEC ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x3, DCYC=0xA, ADSIZE=0x3, ADMODE=0x3, IMODE=0x3, INSTR=Fast READ + } else { + # memory-mapped read mode with 4-byte addresses + mmw 0x52005000 0x00000002 0 ;# QUADSPI_CR: ABORT=1 + mww 0x52005014 0x0D003513 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x3, ADMODE=0x1, IMODE=0x1, INSTR=READ + } +} diff --git a/tcl/board/stm32l476g-disco.cfg b/tcl/board/stm32l476g-disco.cfg new file mode 100644 index 000000000..dab2fe12d --- /dev/null +++ b/tcl/board/stm32l476g-disco.cfg @@ -0,0 +1,56 @@ +# This is an STM32L476G discovery board with a single STM32L476VGT6 chip. +# http://www.st.com/en/evaluation-tools/32l476gdiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PE11: NCS, PE10: CLK, PE15: BK1_IO3, PE14: BK1_IO2, PE13: BK1_IO1, PE12: BK1_IO0 + + # PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + + # Port E: PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0xAAA00000 0x55500000 ;# MODER + mmw 0x48001008 0xFFF00000 0x00000000 ;# OSPEEDR + mmw 0x48001024 0xAAAAAA00 0x55555500 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00170100 ;# QUADSPI_DCR: FSIZE=0x17, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32l496g-disco.cfg b/tcl/board/stm32l496g-disco.cfg new file mode 100644 index 000000000..a93b07cc1 --- /dev/null +++ b/tcl/board/stm32l496g-disco.cfg @@ -0,0 +1,66 @@ +# This is an STM32L496G discovery board with a single STM32L496AGI6 chip. +# http://www.st.com/en/evaluation-tools/32l496gdiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set QUADSPI 1 + +source [find target/stm32l4x.cfg] + +# QUADSPI initialization +proc qspi_init { } { + global a + mmw 0x4002104C 0x000001FF 0 ;# RCC_AHB2ENR |= GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000100 0 ;# RCC_AHB3ENR |= QSPIEN (enable clock) + sleep 1 ;# Wait for clock startup + + # PB11: BK1_NCS, PA03: CLK, PA06: BK1_IO3, PA07: BK1_IO2, PB00: BK1_IO1, PB01: BK1_IO0 + + # PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V + + # Port A: PA07:AF10:V, PA06:AF10:V, PA03:AF10:V + mmw 0x48000000 0x0000A080 0x00005040 ;# MODER + mmw 0x48000008 0x0000F0C0 0x00000000 ;# OSPEEDR + mmw 0x48000020 0xAA00A000 0x55005000 ;# AFRL + + # Port B: PB11:AF10:V, PB01:AF10:V, PB00:AF10:V + mmw 0x48000400 0x0080000A 0x00400005 ;# MODER + mmw 0x48000408 0x00C0000F 0x00000000 ;# OSPEEDR + mmw 0x48000420 0x000000AA 0x00000055 ;# AFRL + mmw 0x48000424 0x0000A000 0x00005000 ;# AFRH + + mww 0xA0001030 0x00001000 ;# QUADSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x01500008 ;# QUADSPI_CR: PRESCALER=1, APMS=1, FTHRES=0, FSEL=0, DFM=0, SSHIFT=0, TCEN=1 + mww 0xA0001004 0x00160100 ;# QUADSPI_DCR: FSIZE=0x16, CSHT=0x01, CKMODE=0 + mmw 0xA0001000 0x00000001 0 ;# QUADSPI_CR: EN=1 + + # 1-line spi mode + mww 0xA0001014 0x000003F5 ;# QUADSPI_CCR: FMODE=0x0, DMODE=0x0, DCYC=0x0, ADSIZE=0x0, ADMODE=0x0, IMODE=0x3, INSTR=RSTQIO + sleep 1 + + # memory-mapped read mode with 3-byte addresses + mww 0xA0001014 0x0D002503 ;# QUADSPI_CCR: FMODE=0x3, DMODE=0x1, DCYC=0x0, ADSIZE=0x2, ADMODE=0x1, IMODE=0x1, INSTR=READ +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000004 0x00000003 ;# 4 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + qspi_init +} diff --git a/tcl/board/stm32l4p5g-disco.cfg b/tcl/board/stm32l4p5g-disco.cfg new file mode 100644 index 000000000..d7420edf2 --- /dev/null +++ b/tcl/board/stm32l4p5g-disco.cfg @@ -0,0 +1,130 @@ +# This is a STM32L4P5G discovery board with a single STM32L4R9AGI6 chip. +# http://www.st.com/en/evaluation-tools/stm32l4p5g-dk.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set OCTOSPI1 1 +set OCTOSPI2 0 + +source [find target/stm32l4x.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) + mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) + sleep 1 ;# Wait for clock startup + + mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) + + mww 0x50061C04 0x07050333 ;# OCTOSPIM_P1CR: assign Port 1 to OCTOSPI2 + mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 + + # PE11: P1_NCS, PE10: P1_CLK, PG06: P1_DQS, PD07: P1_IO7, PC03: P1_IO6, PD05: P1_IO5 + # PD04: P1_IO4, PA06: P1_IO3, PA07: P1_IO2, PE13: P1_IO1, PE11: P1_IO0 + + # PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + # PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V + + # Port A: PA07:AF10:V, PA06:AF10:V + mmw 0x48000000 0x0000A000 0x00005000 ;# MODER + mmw 0x48000008 0x0000F000 0x00000000 ;# OSPEEDR + mmw 0x4800000C 0x00000000 0x0000F000 ;# PUPDR + mmw 0x48000020 0xAA000000 0x55000000 ;# AFRL + # Port C: PC03:AF10:V + mmw 0x48000800 0x00000080 0x00000040 ;# MODER + mmw 0x48000808 0x000000C0 0x00000000 ;# OSPEEDR + mmw 0x4800080C 0x00000000 0x000000C0 ;# PUPDR + mmw 0x48000820 0x0000A000 0x00005000 ;# AFRL + # Port D: PD07:AF10:V, PD05:AF10:V, PD04:AF10:V + mmw 0x48000C00 0x00008A00 0x00004500 ;# MODER + mmw 0x48000C08 0x0000CF00 0x00000000 ;# OSPEEDR + mmw 0x48000C0C 0x00000000 0x0000CF00 ;# PUPDR + mmw 0x48000C20 0xA0AA0000 0x50550000 ;# AFRL + # Port E: PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V + mmw 0x48001000 0x0AA00000 0x05500000 ;# MODER + mmw 0x48001008 0x0FF00000 0x00000000 ;# OSPEEDR + mmw 0x4800100C 0x00000000 0x0FF00000 ;# PUPDR + mmw 0x48001024 0x00AAAA00 0x00555500 ;# AFRH + # Port G: PG06:AF03:V + mmw 0x48001800 0x00002000 0x00001000 ;# MODER + mmw 0x48001808 0x00003000 0x00000000 ;# OSPEEDR + mmw 0x4800180C 0x00000000 0x00003000 ;# PUPDR + mmw 0x48001820 0x03000000 0x0C000000 ;# AFRL + + # PG12: P2_NCS, PF04: P2_CLK, PF12: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PG01: P2_IO5 + # PG00: P2_IO4, PF03: P2_IO3, PF02: P2_IO2, PF01: P2_IO1, PF00: P2_IO0 + + # PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V + # PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V + + # Port F: PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V + mmw 0x48001400 0x020002AA 0x01000155 ;# MODER + mmw 0x48001408 0x030003FF 0x00000000 ;# OSPEEDR + mmw 0x4800140C 0x00000000 0x030003FF ;# PUPDR + mmw 0x48001420 0x00055555 0x000AAAAA ;# AFRL + mmw 0x48001424 0x00050000 0x000A0000 ;# AFRH + # Port G: PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V + mmw 0x48001800 0x0228000A 0x01140005 ;# MODER + mmw 0x48001808 0x033C000F 0x00000000 ;# OSPEEDR + mmw 0x4800180C 0x00000000 0x033C000F ;# PUPDR + mmw 0x48001820 0x00000055 0x000000AA ;# AFRL + mmw 0x48001824 0x00050550 0x000A0AA0 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 + + mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 24000 + + octospi_init 1 +} + diff --git a/tcl/board/stm32l4r9i-disco.cfg b/tcl/board/stm32l4r9i-disco.cfg new file mode 100644 index 000000000..70ed19940 --- /dev/null +++ b/tcl/board/stm32l4r9i-disco.cfg @@ -0,0 +1,100 @@ +# This is a STM32L4R9I discovery board with a single STM32L4R9AII6 chip. +# http://www.st.com/en/evaluation-tools/32l4r9idiscovery.html + +# This is for using the onboard STLINK +source [find interface/stlink.cfg] + +transport select hla_swd + +# increase working area to 96KB +set WORKAREASIZE 0x18000 + +# enable stmqspi +set OCTOSPI1 1 +set OCTOSPI2 0 + +source [find target/stm32l4x.cfg] + +# OCTOSPI initialization +# octo: 8-line mode +proc octospi_init { octo } { + global a b + mmw 0x4002104C 0x001001FF 0 ;# RCC_AHB2ENR |= OSPIMEN, GPIOAEN-GPIOIEN (enable clocks) + mmw 0x40021050 0x00000300 0 ;# RCC_AHB3ENR |= OSPI2EN, OSPI1EN (enable clocks) + mmw 0x40021058 0x10000000 0 ;# RCC_APB1ENR1 |= PWREN (enable clock) + sleep 1 ;# Wait for clock startup + + mmw 0x40007004 0x00000200 0 ;# PWR_CR2 |= IOSV (required for use of GPOIG, cf. RM0432) + + mww 0x50061C04 0x00000000 ;# OCTOSPIM_P1CR: disable Port 1 + mww 0x50061C08 0x03010111 ;# OCTOSPIM_P2CR: assign Port 2 to OCTOSPI1 + + # PG12: P2_NCS, PI06: P2_CLK, PG15: P2_DQS, PG10: P2_IO7, PG09: P2_IO6, PH10: P2_IO5, + # PH09: P2_IO4, PH08: P2_IO3, PI09: P2_IO2, PI10: P2_IO1, PI11: P2_IO0 + + # PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V + # PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V + + # Port G: PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V + mmw 0x48001800 0x82280000 0x41140000 ;# MODER + mmw 0x48001808 0xC33C0000 0x00000000 ;# OSPEEDR + mmw 0x48001824 0x50050550 0xA00A0AA0 ;# AFRH + + # Port H: PH10:AF05:V, PH09:AF05:V, PH08:AF05:V + mmw 0x48001C00 0x002A0000 0x00150000 ;# MODER + mmw 0x48001C08 0x003F0000 0x00000000 ;# OSPEEDR + mmw 0x48001C24 0x00000555 0x00000AAA ;# AFRH + + # Port I: PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V + mmw 0x48002000 0x00A82000 0x00541000 ;# MODER + mmw 0x48002008 0x00FC3000 0x00000000 ;# OSPEEDR + mmw 0x48002020 0x05000000 0x0A000000 ;# AFRL + mmw 0x48002024 0x00005550 0x0000AAA0 ;# AFRH + + # OCTOSPI1: memory-mapped 1-line read mode with 4-byte addresses + mww 0xA0001130 0x00001000 ;# OCTOSPI_LPTR: deactivate CS after 4096 clocks when FIFO is full + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x1, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=0 + mww 0xA0001008 0x01190100 ;# OCTOSPI_DCR1: MTYP=0x1, FSIZE=0x19, CSHT=0x01, CKMODE=0, DLYBYP=0 + mww 0xA000100C 0x00000001 ;# OCTOSPI_DCR2: PRESCALER=1 + + mww 0xA0001108 0x00000000 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=0, DCYC=0x0 + mww 0xA0001100 0x01003101 ;# OCTOSPI_CCR: DMODE=0x1, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x1, ISIZE=0x0, IMODE=0x1 + mww 0xA0001110 0x00000013 ;# OCTOSPI_IR: INSTR=READ4B + + if { $octo == 1 } { + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 ;# Read Status Register + stmqspi cmd $a 0 0x72 0x00 0x00 0x00 0x00 0x02 ;# Write Conf. Reg. 2, addr 0x00000000: DTR OPI enable + + # OCTOSPI1: memory-mapped 8-line read mode with 4-byte addresses + mww 0xA0001000 0x3040000B ;# OCTOSPI_CR: FMODE=0x3, APMS=1, FTHRES=0, FSEL=0, DQM=0, TCEN=1, EN=1 + mww 0xA0001108 0x10000006 ;# OCTOSPI_TCR: SSHIFT=0, DHQC=1, DCYC=0x6 + mww 0xA0001100 0x2C003C1C ;# OCTOSPI_CCR: DTR, DMODE=0x4, ABMODE=0x0, ADSIZE=0x3, ADMODE=0x4, ISIZE=0x1, IMODE=0x4 + mww 0xA0001110 0x0000EE11 ;# OCTOSPI_IR: INSTR=OCTA DTR Read + + flash probe $a ;# reload configuration from CR, TCR, CCR, IR register values + + stmqspi cmd $a 0 0x06 ;# Write Enable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 0 0x04 ;# Write Disable + stmqspi cmd $a 1 0x05 0x00 0x00 0x00 0x00 ;# Read Status Register (note dummy address in 8-line mode) + stmqspi cmd $a 1 0x71 0x00 0x00 0x00 0x00 ;# Read Conf. Reg. 2, addr 0x00000000: DOPI, SOPI bits + } +} + +$_TARGETNAME configure -event reset-init { + mmw 0x40022000 0x00000003 0x0000000C ;# 3 WS for 72 MHz HCLK + sleep 1 + mmw 0x40021000 0x00000100 0x00000000 ;# HSI on + mww 0x4002100C 0x01002432 ;# RCC_PLLCFGR 72 MHz: PLLREN=1, PLLM=4, PLLN=36, PLLR=2, HSI + mww 0x40021008 0x00008001 ;# always HSI, APB1: /1, APB2: /1 + mmw 0x40021000 0x01000000 0x00000000 ;# PLL on + sleep 1 + mmw 0x40021008 0x00000003 0x00000000 ;# switch to PLL + sleep 1 + + adapter speed 4000 + + octospi_init 1 +} diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index b95e783c5..15875336e 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -52,6 +52,12 @@ flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.otp stm32f2x 0x1fff7800 0 0 0 $_TARGETNAME +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + # JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz # # Since we may be running of an RC oscilator, we crank down the speed a diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg index 6ad4b65f8..3c7679de2 100644 --- a/tcl/target/stm32f7x.cfg +++ b/tcl/target/stm32f7x.cfg @@ -12,7 +12,7 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32f7x } - set _ENDIAN little +set _ENDIAN little # Work-area is a space in RAM used for flash programming # By default use 128kB @@ -64,6 +64,12 @@ flash bank $_CHIPNAME.otp stm32f2x 0x1ff0f000 0 0 0 $_TARGETNAME # the Flash via ITCM alias as virtual flash bank $_CHIPNAME.itcm-flash.alias virtual 0x00200000 0 0 0 $_TARGETNAME $_FLASHNAME +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} + # adapter speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz adapter speed 2000 diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg index 763a7857a..8258e5031 100644 --- a/tcl/target/stm32h7x.cfg +++ b/tcl/target/stm32h7x.cfg @@ -104,6 +104,23 @@ if {[set $_CHIPNAME.DUAL_CORE]} { # Make sure that cpu0 is selected targets $_CHIPNAME.cpu0 +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 +} else { + if { [info exists OCTOSPI1] && $OCTOSPI1 } { + set a [llength [flash list]] + set _OCTOSPINAME1 $_CHIPNAME.octospi1 + flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_CHIPNAME.cpu0 0x52005000 + } + if { [info exists OCTOSPI2] && $OCTOSPI2 } { + set b [llength [flash list]] + set _OCTOSPINAME2 $_CHIPNAME.octospi2 + flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_CHIPNAME.cpu0 0x5200A000 + } +} + # Clock after reset is HSI at 64 MHz, no need of PLL adapter speed 1800 diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 46e6f7e0d..7f08f3c4b 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -50,6 +50,23 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +if { [info exists QUADSPI] && $QUADSPI } { + set a [llength [flash list]] + set _QSPINAME $_CHIPNAME.qspi + flash bank $_QSPINAME stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 +} else { + if { [info exists OCTOSPI1] && $OCTOSPI1 } { + set a [llength [flash list]] + set _OCTOSPINAME1 $_CHIPNAME.octospi1 + flash bank $_OCTOSPINAME1 stmqspi 0x90000000 0 0 0 $_TARGETNAME 0xA0001000 + } + if { [info exists OCTOSPI2] && $OCTOSPI2 } { + set b [llength [flash list]] + set _OCTOSPINAME2 $_CHIPNAME.octospi2 + flash bank $_OCTOSPINAME2 stmqspi 0x70000000 0 0 0 $_TARGETNAME 0xA0001400 + } +} + # Common knowledges tells JTAG speed should be <= F_CPU/6. # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on # the safe side. From 06c7a53f1fff20bcc4be9e63f83ae98664777f34 Mon Sep 17 00:00:00 2001 From: Kevin Yang Date: Wed, 4 Nov 2020 10:39:29 -0800 Subject: [PATCH 063/113] target/cortex_m: Change sleep to running state When the core is in sleep mode, the core is no longer retiring instructions. Cortext M remains in "unknown" state. This patch converts sleep mode to "running" state. Change-Id: I1e9b6c9be51fd0f1f6ce81af9b1f5f9f1f43c661 Signed-off-by: Kevin Yang Reviewed-on: http://openocd.zylin.com/5921 Reviewed-by: Tomas Vanek Tested-by: jenkins --- src/target/cortex_m.c | 8 ++------ src/target/target.h | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 08b3661ea..0c1a99fc0 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -656,13 +656,9 @@ static int cortex_m_poll(struct target *target) } } - /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state. - * How best to model low power modes? - */ - if (target->state == TARGET_UNKNOWN) { - /* check if processor is retiring instructions */ - if (cortex_m->dcb_dhcsr & S_RETIRE_ST) { + /* check if processor is retiring instructions or sleeping */ + if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) { target->state = TARGET_RUNNING; retval = ERROR_OK; } diff --git a/src/target/target.h b/src/target/target.h index 44463b74f..b9ae2f78e 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -47,7 +47,7 @@ struct gdb_fileio_info; /* * TARGET_UNKNOWN = 0: we don't know anything about the target yet - * TARGET_RUNNING = 1: the target is executing user code + * TARGET_RUNNING = 1: the target is executing or ready to execute user code * TARGET_HALTED = 2: the target is not executing code, and ready to talk to the * debugger. on an xscale it means that the debug handler is executing * TARGET_RESET = 3: the target is being held in reset (only a temporary state, From 175f30e6952be5ca0e06b2e8753d8c72d6b90446 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 9 Nov 2020 12:53:30 +0100 Subject: [PATCH 064/113] tcl/board: rename board file ST b-l475e-iot01a Use the board file name as _.cfg Add the SPDX tag to workaround an error in checkpatch that fails to recognize as valid a patch that only changes a file name. Change-Id: I929cd9e5f9fe2e7386950643487534c9a5a05bc6 Signed-off-by: Antonio Borneo Fixes: e44539d66c89 ("Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface") Reviewed-on: http://openocd.zylin.com/5931 Reviewed-by: Tarek BOCHKATI Tested-by: jenkins --- tcl/board/{b-l475e-iot01a.cfg => st_b-l475e-iot01a.cfg} | 2 ++ 1 file changed, 2 insertions(+) rename tcl/board/{b-l475e-iot01a.cfg => st_b-l475e-iot01a.cfg} (97%) diff --git a/tcl/board/b-l475e-iot01a.cfg b/tcl/board/st_b-l475e-iot01a.cfg similarity index 97% rename from tcl/board/b-l475e-iot01a.cfg rename to tcl/board/st_b-l475e-iot01a.cfg index be411e49f..e75c99d7a 100644 --- a/tcl/board/b-l475e-iot01a.cfg +++ b/tcl/board/st_b-l475e-iot01a.cfg @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + # This is an B-L475E-IOT01A Discovery kit for IoT node with a single STM32L475VGT6 chip. # http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html From 109dc1975f25a36a501811e48267b17d7dc19688 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 9 Nov 2020 15:50:55 +0100 Subject: [PATCH 065/113] flash/stmqspi: minor fixes on coding style Add space around operators; use BIT() macro in place of left shifting constant 1; remove space between cast operator and value; do not check a pointer before free() it; add parenthesis around parameters in macros; fix indentation using only TABs; remove line continuation '\' at code lines out of macros. Change-Id: I809e8ee72d7bfe49d0edf10afb36efe2458de77c Signed-off-by: Antonio Borneo Fixes: e44539d66c89 ("Flash, FRAM and EEPROM driver for STM32 QUAD-/OCTOSPI interface") Reviewed-on: http://openocd.zylin.com/5932 Tested-by: jenkins Reviewed-by: Christopher Head --- src/flash/nor/sfdp.c | 8 +- src/flash/nor/stmqspi.c | 207 ++++++++++++++++++++-------------------- src/flash/nor/stmqspi.h | 16 ++-- src/target/target.c | 2 +- 4 files changed, 115 insertions(+), 118 deletions(-) diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c index 02b4cedec..2fbc37d1f 100644 --- a/src/flash/nor/sfdp.c +++ b/src/flash/nor/sfdp.c @@ -81,7 +81,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, /* retrieve SFDP header */ memset(&header, 0, sizeof(header)); - retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *) &header); + retval = read_sfdp_block(bank, 0x0, sizeof(header) >> 2, (uint32_t *)&header); if (retval != ERROR_OK) return retval; LOG_DEBUG("header 0x%08" PRIx32 " 0x%08" PRIx32, header.signature, header.revision); @@ -105,7 +105,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, } memset(pheaders, 0, sizeof(struct sfdp_phdr) * nph); retval = read_sfdp_block(bank, sizeof(header), - (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *) pheaders); + (sizeof(struct sfdp_phdr) >> 2) * nph, (uint32_t *)pheaders); if (retval != ERROR_OK) goto err; @@ -132,7 +132,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, LOG_DEBUG("word %02d 0x%08X", j + 1, ptable[j]); if (id == SFDP_BASIC_FLASH) { - struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *) ptable; + struct sfdp_basic_flash_param *table = (struct sfdp_basic_flash_param *)ptable; uint16_t erase; if (words < 9) { @@ -215,7 +215,7 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, LOG_INFO("device has to be switched to 4-byte addresses"); } } else if (id == SFDP_4BYTE_ADDR) { - struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *) ptable; + struct sfdp_4byte_addr_param *table = (struct sfdp_4byte_addr_param *)ptable; if (words >= (offsetof(struct sfdp_4byte_addr_param, erase_t1234) + sizeof(table->erase_t1234)) >> 2) { diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index 486ee53ce..11529f410 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -40,6 +40,7 @@ #endif #include "imp.h" +#include #include #include #include @@ -137,7 +138,7 @@ /* 4-byte address in octo mode, else 3-byte address for read SFDP */ #define OCTOSPI_CCR_READ_SFDP(len) \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & ~OCTOSPI_ADDR4 & OCTOSPI_NO_ALTB) | \ - ((len < 4) ? OCTOSPI_ADDR3 : OCTOSPI_ADDR4)) + (((len) < 4) ? OCTOSPI_ADDR3 : OCTOSPI_ADDR4)) #define OCTOSPI_CCR_WRITE_ENABLE \ ((OCTOSPI_MODE_CCR & OCTOSPI_NO_ADDR & OCTOSPI_NO_ALTB & OCTOSPI_NO_DATA)) @@ -153,17 +154,17 @@ #define SPI_ADSIZE (((stmqspi_info->saved_ccr >> SPI_ADSIZE_POS) & 0x3) + 1) -#define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t) cmd)<<8) | (~cmd & 0xFFU)) : cmd)) +#define OPI_CMD(cmd) ((OPI_MODE ? ((((uint16_t)(cmd)) << 8) | (~(cmd) & 0xFFU)) : (cmd))) #define OCTOSPI_CMD(mode, ccr, ir) \ ({ \ retval = target_write_u32(target, io_base + OCTOSPI_CR, \ - OCTOSPI_MODE | mode); \ + OCTOSPI_MODE | (mode)); \ if (retval == ERROR_OK) \ retval = target_write_u32(target, io_base + OCTOSPI_TCR, \ (stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | \ - ((OPI_MODE && (mode == OCTOSPI_READ_MODE)) ? \ - (OPI_DUMMY<saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 2 * count : count) - 1); if (retval != ERROR_OK) goto err; @@ -354,11 +355,11 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status) *status = 0; /* for debugging only */ - (void) READ_REG(SPI_SR); + (void)READ_REG(SPI_SR); for ( ; count > 0; --count) { - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) { /* get status of flash 1 in dual mode or flash 1 only mode */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) @@ -366,13 +367,12 @@ static int read_status_reg(struct flash_bank *bank, uint16_t *status) *status |= data; } - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { /* get status of flash 2 in dual mode or flash 2 only mode */ retval = target_read_u8(target, io_base + SPI_DR, &data); if (retval != ERROR_OK) goto err; - *status |= ((uint16_t) data) << 8; + *status |= ((uint16_t)data) << 8; } } @@ -417,7 +417,7 @@ static int qspi_write_enable(struct flash_bank *bank) /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { LOG_ERROR("Cannot write enable flash1. Status=0x%02" PRIx8, status & 0xFF); @@ -462,8 +462,7 @@ static int qspi_write_enable(struct flash_bank *bank) /* Check write enabled for flash 2 */ status >>= 8; - if (((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { LOG_ERROR("Cannot write enable flash2. Status=0x%02" PRIx8, status & 0xFF); @@ -546,8 +545,8 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) goto err; /* Check for command in progress for flash 1 */ - if (((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Mass erase command not accepted by flash1. Status=0x%02" PRIx8, status & 0xFF); @@ -557,8 +556,8 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) /* Check for command in progress for flash 2 */ status >>= 8; - if (((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && + ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Mass erase command not accepted by flash2. Status=0x%02" PRIx8, status & 0xFF); @@ -595,7 +594,7 @@ static int log2u(uint32_t word) int result; for (result = 0; (unsigned int) result < sizeof(uint32_t) * CHAR_BIT; result++) - if (word == (1UL<saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; /* chip_erase_cmd, sectorsize and erase_cmd are optional */ if ((CMD_ARGC < 7) || (CMD_ARGC > 10)) @@ -715,14 +714,14 @@ COMMAND_HANDLER(stmqspi_handle_set) bank->size = stmqspi_info->dev.size_in_bytes << dual; io_base = stmqspi_info->io_base; - fsize = (READ_REG(SPI_DCR)>>SPI_FSIZE_POS) & ((1U<> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1); if (retval != ERROR_OK) return retval; LOG_DEBUG("FSIZE = 0x%04x", fsize); - if (bank->size == (1U<<(fsize + 1))) + if (bank->size == BIT(fsize + 1)) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); - else if (bank->size == (1U<<(fsize + 0))) + else if (bank->size == BIT(fsize + 0)) LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); else LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); @@ -749,12 +748,12 @@ COMMAND_HANDLER(stmqspi_handle_set) LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 "kbytes," " bank size = %" PRIu32 "kbytes", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes / 1024, - (stmqspi_info->dev.size_in_bytes / 1024)<dev.size_in_bytes / 1024) << dual); else LOG_INFO("flash \'%s\' id = unknown\nchip size = %" PRIu32 "bytes," " bank size = %" PRIu32 "bytes", stmqspi_info->dev.name, stmqspi_info->dev.size_in_bytes, - stmqspi_info->dev.size_in_bytes<dev.size_in_bytes << dual); stmqspi_info->probed = true; @@ -803,7 +802,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) if (num_read == 0) { /* nothing to read, then one command byte and for dual flash * an *even* number of data bytes to follow */ - if (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_write & 1) == 0) { LOG_ERROR("number of data bytes to write must be even in dual mode"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -811,7 +810,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) } } else { /* read mode, one command byte and up to four following address bytes */ - if (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) { if ((num_read & 1) != 0) { LOG_ERROR("number of bytes to read must be even in dual mode"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -825,7 +824,7 @@ COMMAND_HANDLER(stmqspi_handle_cmd) /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U< ", sizeof(output) - strlen(output) - 1); /* send cmd byte, if ADMODE indicates no address, this already triggers command */ - retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t) num_read) - 1); + retval = target_write_u32(target, io_base + SPI_DLR, ((uint32_t)num_read) - 1); if (retval != ERROR_OK) goto err; if (IS_OCTOSPI) retval = OCTOSPI_CMD(OCTOSPI_READ_MODE, (OCTOSPI_MODE_CCR & OCTOSPI_NO_DDTR & OCTOSPI_NO_ALTB & ~OCTOSPI_ADDR4 & ((num_write == 1) ? OCTOSPI_NO_ADDR : ~0U)) | - (((num_write - 2) & 0x3U)<saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) + != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Sector erase command not accepted by flash1. Status=0x%02" PRIx8, status & 0xFF); @@ -969,8 +968,8 @@ static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) /* Check for command in progress for flash 2 */ /* If BSY and WE are already cleared the erase did probably complete already */ status >>= 8; - if (((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && + ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { LOG_ERROR("Sector erase command not accepted by flash2. Status=0x%02" PRIx8, status & 0xFF); @@ -1084,7 +1083,7 @@ static int stmqspi_blank_check(struct flash_bank *bank) /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<address + codesize - sizeof(ccr_buffer), - sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; @@ -1177,7 +1176,7 @@ static int stmqspi_blank_check(struct flash_bank *bank) retval = target_write_buffer(target, algorithm->address + codesize + index * sizeof(erase_check_info), - sizeof(erase_check_info), (uint8_t *) &erase_check_info); + sizeof(erase_check_info), (uint8_t *)&erase_check_info); if (retval != ERROR_OK) goto err; } @@ -1202,7 +1201,7 @@ static int stmqspi_blank_check(struct flash_bank *bank) for (index = 0; index < count; index++) { retval = target_read_buffer(target, algorithm->address + codesize + index * sizeof(erase_check_info), - sizeof(erase_check_info), (uint8_t *) &erase_check_info); + sizeof(erase_check_info), (uint8_t *)&erase_check_info); if (retval != ERROR_OK) goto err; @@ -1276,7 +1275,7 @@ static int qspi_verify(struct flash_bank *bank, uint8_t *buffer, pagesize = SPIFLASH_DEF_PAGESIZE; /* adjust size according to dual flash mode */ - pagesize = (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? pagesize << 1 : pagesize; /* This will overlay the last 4 words of stmqspi/stmoctospi_crc32_code in target */ /* for read use the saved settings (memory mapped mode) but indirect read mode */ @@ -1307,7 +1306,7 @@ static int qspi_verify(struct flash_bank *bank, uint8_t *buffer, /* prepare QSPI/OCTOSPI_CCR register values */ retval = target_write_buffer(target, algorithm->address + codesize - sizeof(ccr_buffer), - sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; @@ -1379,7 +1378,7 @@ static int qspi_read_write_block(struct flash_bank *bank, uint8_t *buffer, LOG_DEBUG("%s: offset=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, offset, count); - dual = (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; /* see contrib/loaders/flash/stmqspi/stmqspi_read.S for src */ static const uint8_t stmqspi_read_code[] = { @@ -1412,7 +1411,7 @@ static int qspi_read_write_block(struct flash_bank *bank, uint8_t *buffer, h_to_le_32(OCTOSPI_MODE | OCTOSPI_READ_MODE), h_to_le_32(IS_OCTOSPI ? OCTOSPI_CCR_READ_STATUS : QSPI_CCR_READ_STATUS), h_to_le_32((stmqspi_info->saved_tcr & ~OCTOSPI_DCYC_MASK) | - (OPI_MODE ? (OPI_DUMMY<address + codesize - sizeof(ccr_buffer), - sizeof(ccr_buffer), (uint8_t *) ccr_buffer); + sizeof(ccr_buffer), (uint8_t *)ccr_buffer); if (retval != ERROR_OK) goto err; @@ -1592,7 +1591,7 @@ static int stmqspi_read(struct flash_bank *bank, uint8_t *buffer, /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<saved_cr & (1U<saved_ccr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1639,9 +1638,9 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ - if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) - && ((offset + count - 1) >= bank->sectors[sector].offset) - && bank->sectors[sector].is_protected) { + if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && + ((offset + count - 1) >= bank->sectors[sector].offset) && + bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %u protected", sector); return ERROR_FLASH_PROTECTED; } @@ -1655,7 +1654,7 @@ static int stmqspi_write(struct flash_bank *bank, const uint8_t *buffer, /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<saved_cr & (1U<saved_ccr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -1706,7 +1705,7 @@ static int stmqspi_verify(struct flash_bank *bank, const uint8_t *buffer, /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<io_base; uint8_t data; unsigned int dual, count; - bool flash1 = !(stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_FSEL_FLASH)); int retval; const unsigned int max_bytes = 64; - dual = (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; LOG_DEBUG("%s: len=%d, dual=%u, flash1=%d", __func__, len, dual, flash1); /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - stmqspi_info->saved_cr | (1U<saved_cr | BIT(SPI_ABORT)); if (retval != ERROR_OK) goto err; @@ -1806,7 +1805,7 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len) err: /* Abort operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<target; struct stmqspi_flash_bank *stmqspi_info = bank->driver_priv; uint32_t io_base = stmqspi_info->io_base; - bool flash1 = !(stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_FSEL_FLASH)); unsigned int dual, count, len, *dummy; int retval; - dual = (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; if (IS_OCTOSPI && (((stmqspi_info->saved_ccr >> SPI_DMODE_POS) & 0x7) > 3)) { /* in OCTO mode 4-byte address and (yet) unknown number of dummy clocks */ @@ -1840,7 +1839,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, len = 3; /* use sfdp_dummy1/2 according to currently selected flash */ - dummy = (stmqspi_info->saved_cr & (1U<saved_cr & BIT(SPI_FSEL_FLASH)) ? &stmqspi_info->sfdp_dummy2 : &stmqspi_info->sfdp_dummy1; /* according to SFDP standard, there should always be 8 dummy *CLOCKS* @@ -1859,7 +1858,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - stmqspi_info->saved_cr | (1U<saved_cr | BIT(SPI_ABORT)); if (retval != ERROR_OK) goto err; @@ -1894,7 +1893,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, /* dummy clocks */ for (count = *dummy << dual; count > 0; --count) { - retval = target_read_u8(target, io_base + SPI_DR, (uint8_t *) buffer); + retval = target_read_u8(target, io_base + SPI_DR, (uint8_t *)buffer); if (retval != ERROR_OK) goto err; } @@ -1929,7 +1928,7 @@ static int read_sfdp_block(struct flash_bank *bank, uint32_t addr, LOG_DEBUG("raw SFDP data 0x%08" PRIx32, *buffer); /* endian correction, sfdp data is always le uint32_t based */ - *buffer = le_to_h_u32((uint8_t *) buffer); + *buffer = le_to_h_u32((uint8_t *)buffer); buffer++; } @@ -1961,7 +1960,7 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) for (type = (IS_OCTOSPI && OPI_MODE) ? 1 : 0; type < 2 ; type++) { /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<saved_cr & (1U<saved_cr & BIT(SPI_DUAL_FLASH) ? count * 2 : count) - 1); if (retval != ERROR_OK) goto err; @@ -2014,29 +2013,29 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) } /* for debugging only */ - (void) READ_REG(SPI_SR); + (void)READ_REG(SPI_SR); /* Read ID from Data Register */ for (len1 = 0, len2 = 0; count > 0; --count) { - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { retval = target_read_u8(target, io_base + SPI_DR, &byte); if (retval != ERROR_OK) goto err; /* collect 3 bytes without continuation codes */ if ((byte != 0x7F) && (len1 < 3)) { - *id1 = (*id1 >> 8) | ((uint32_t) byte) << 16; + *id1 = (*id1 >> 8) | ((uint32_t)byte) << 16; len1++; } } - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != 0) { retval = target_read_u8(target, io_base + SPI_DR, &byte); if (retval != ERROR_OK) goto err; /* collect 3 bytes without continuation codes */ if ((byte != 0x7F) && (len2 < 3)) { - *id2 = (*id2 >> 8) | ((uint32_t) byte) << 16; + *id2 = (*id2 >> 8) | ((uint32_t)byte) << 16; len2++; } } @@ -2047,8 +2046,8 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) break; } - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) { if ((*id1 == 0x000000) || (*id1 == 0xFFFFFF)) { /* no id retrieved, so id must be set manually */ LOG_INFO("No id from flash1"); @@ -2056,8 +2055,7 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) } } - if ((stmqspi_info->saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) { if ((*id2 == 0x000000) || (*id2 == 0xFFFFFF)) { /* no id retrieved, so id must be set manually */ LOG_INFO("No id from flash2"); @@ -2085,8 +2083,7 @@ static int stmqspi_probe(struct flash_bank *bank) if (stmqspi_info->probed) { bank->size = 0; bank->num_sectors = 0; - if (bank->sectors) - free(bank->sectors); + free(bank->sectors); bank->sectors = NULL; memset(&stmqspi_info->dev, 0, sizeof(stmqspi_info->dev)); stmqspi_info->sfdp_dummy1 = 0; @@ -2096,7 +2093,7 @@ static int stmqspi_probe(struct flash_bank *bank) /* Abort any previous operation */ retval = target_write_u32(target, io_base + SPI_CR, - READ_REG(SPI_CR) | (1U<>OCTOSPI_MTYP_POS; + mtyp = ((READ_REG(OCTOSPI_DCR1) & OCTOSPI_MTYP_MASK)) >> OCTOSPI_MTYP_POS; if (retval == ERROR_OK) stmqspi_info->saved_tcr = READ_REG(OCTOSPI_TCR); if (retval == ERROR_OK) @@ -2167,8 +2164,8 @@ static int stmqspi_probe(struct flash_bank *bank) } } - dual = (stmqspi_info->saved_cr & (1U<saved_ccr & (1U<saved_cr & BIT(SPI_DUAL_FLASH)) ? 1 : 0; + octal_dtr = IS_OCTOSPI && (stmqspi_info->saved_ccr & BIT(OCTOSPI_DDTR)); if (dual || octal_dtr) bank->write_start_alignment = bank->write_end_alignment = 2; else @@ -2207,7 +2204,7 @@ static int stmqspi_probe(struct flash_bank *bank) uint32_t saved_cr = stmqspi_info->saved_cr; /* select flash1 */ - stmqspi_info->saved_cr = stmqspi_info->saved_cr & ~(1U<saved_cr = stmqspi_info->saved_cr & ~BIT(SPI_FSEL_FLASH); retval = spi_sfdp(bank, &temp, &read_sfdp_block); /* restore saved_cr */ @@ -2265,7 +2262,7 @@ static int stmqspi_probe(struct flash_bank *bank) uint32_t saved_cr = stmqspi_info->saved_cr; /* select flash2 */ - stmqspi_info->saved_cr = stmqspi_info->saved_cr | (1U<saved_cr = stmqspi_info->saved_cr | BIT(SPI_FSEL_FLASH); retval = spi_sfdp(bank, &temp, &read_sfdp_block); /* restore saved_cr */ @@ -2304,14 +2301,14 @@ static int stmqspi_probe(struct flash_bank *bank) /* Set correct size value */ bank->size = stmqspi_info->dev.size_in_bytes << dual; - fsize = ((READ_REG(SPI_DCR)>>SPI_FSIZE_POS) & ((1U<> SPI_FSIZE_POS) & (BIT(SPI_FSIZE_LEN) - 1)); if (retval != ERROR_OK) goto err; LOG_DEBUG("FSIZE = 0x%04x", fsize); - if (bank->size == (1U<<(fsize + 1))) + if (bank->size == BIT((fsize + 1))) LOG_DEBUG("FSIZE in DCR(1) matches actual capacity. Beware of silicon bug in H7, L4+, MP1."); - else if (bank->size == (1U<<(fsize + 0))) + else if (bank->size == BIT((fsize + 0))) LOG_DEBUG("FSIZE in DCR(1) is off by one regarding actual capacity. Fix for silicon bug?"); else LOG_ERROR("FSIZE in DCR(1) doesn't match actual capacity."); @@ -2380,10 +2377,10 @@ static int get_stmqspi_info(struct flash_bank *bank, char *buf, int buf_size) ", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8 ", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8 ", sector size = %" PRIu32 "%sbytes, sector_erase = 0x%02" PRIx8 ")", - ((stmqspi_info->saved_cr & ((1U<saved_cr & ((1U<saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) ? "1" : "", + ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | + BIT(SPI_FSEL_FLASH))) != 0) ? "2" : "", stmqspi_info->dev.name, stmqspi_info->dev.device_id, bank->size / 4096 ? bank->size / 1024 : bank->size, bank->size / 4096 ? "k" : "", stmqspi_info->dev.pagesize, diff --git a/src/flash/nor/stmqspi.h b/src/flash/nor/stmqspi.h index d8510ab19..85da25f09 100644 --- a/src/flash/nor/stmqspi.h +++ b/src/flash/nor/stmqspi.h @@ -51,7 +51,7 @@ #define SPI_DMODE_POS 24 /* bit position of DMODE */ #define QSPI_DCYC_POS 18 /* bit position of DCYC */ #define QSPI_DCYC_LEN 5 /* width of DCYC field */ -#define QSPI_DCYC_MASK (((1U<octo) #define SPI_CR (IS_OCTOSPI ? OCTOSPI_CR : QSPI_CR) diff --git a/src/target/target.c b/src/target/target.c index db759d9c3..9d4fe7721 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1154,7 +1154,7 @@ int target_run_read_async_algorithm(struct target *target, } LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, - (size_t) (buffer - buffer_orig), count, wp, rp); + (size_t)(buffer - buffer_orig), count, wp, rp); if (wp == 0) { LOG_ERROR("flash read algorithm aborted by target"); From f8453ae52cf336c337b7f135f10ed4afecf35a7c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 20 Oct 2019 09:40:34 +0200 Subject: [PATCH 066/113] target, register: allow a register hidden from gdb and 'reg' cmd Introduce a 'hidden' flag in struct reg to support a register cache containing different views of same data: e.g. Cortex-M has primask, basepri, faultmask and control registers accessed as one word. With the hidden flag we can add an reg_list item corresponding to hw access without exposing the register to user level. All the struct reg are allocated with calloc() but one in xscale.c allocated by malloc(). Change this one to use calloc() as well to guarantee initial value hidden=false Change-Id: I8da9f5a5a60777ae7ef943a841307487bd80fc6f Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5325 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 8 ++++---- src/target/register.h | 2 ++ src/target/target.c | 2 +- src/target/xscale.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index bb4c1317d..792bbdcea 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1189,7 +1189,7 @@ static int gdb_get_registers_packet(struct connection *connection, return gdb_error(connection, retval); for (i = 0; i < reg_list_size; i++) { - if (reg_list[i] == NULL || reg_list[i]->exist == false) + if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden) continue; reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } @@ -1203,7 +1203,7 @@ static int gdb_get_registers_packet(struct connection *connection, reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { - if (reg_list[i] == NULL || reg_list[i]->exist == false) + if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (!reg_list[i]->valid) { retval = reg_list[i]->type->get(reg_list[i]); @@ -2176,7 +2176,7 @@ static int get_reg_features_list(struct target *target, char const **feature_lis *feature_list = calloc(1, sizeof(char *)); for (int i = 0; i < reg_list_size; i++) { - if (reg_list[i]->exist == false) + if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (reg_list[i]->feature != NULL @@ -2270,7 +2270,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o int i; for (i = 0; i < reg_list_size; i++) { - if (reg_list[i]->exist == false) + if (reg_list[i]->exist == false || reg_list[i]->hidden) continue; if (strcmp(reg_list[i]->feature->name, features[current_feature])) diff --git a/src/target/register.h b/src/target/register.h index 7c53d6e16..1bae81183 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -134,6 +134,8 @@ struct reg { bool valid; /* When false, the register doesn't actually exist in the target. */ bool exist; + /* Hide the register from gdb and omit it in 'reg' cmd output */ + bool hidden; /* Size of the register in bits. */ uint32_t size; /* Used for generating XML description of registers. Can be set to NULL for diff --git a/src/target/target.c b/src/target/target.c index 9d4fe7721..3c1a6338e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3037,7 +3037,7 @@ COMMAND_HANDLER(handle_reg_command) for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { - if (reg->exist == false) + if (reg->exist == false || reg->hidden) continue; /* only print cached values if they are valid */ if (reg->valid) { diff --git a/src/target/xscale.c b/src/target/xscale.c index aaaed0ebb..b25999d3c 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -2882,7 +2882,7 @@ static void xscale_build_reg_cache(struct target *target) /* fill in values for the xscale reg cache */ (*cache_p)->name = "XScale registers"; (*cache_p)->next = NULL; - (*cache_p)->reg_list = malloc(num_regs * sizeof(struct reg)); + (*cache_p)->reg_list = calloc(num_regs, sizeof(struct reg)); (*cache_p)->num_regs = num_regs; for (i = 0; i < num_regs; i++) { From efbc447ed8d49ef0fa0638faf13315d767208ab6 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 20 Oct 2019 10:12:32 +0200 Subject: [PATCH 067/113] target/armv7m: rework Cortex-M register handling part 1 Define a new enum with DCRSR.REGSEL selectors. Introduce armv7m_map_id_to_regsel() to unify mapping in one place. Use DCRSR.REGSEL selectors for low level register read/write. Change-Id: Ida0ccdfa9cdb1257a1900b8bfbf172b076374d39 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5327 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Christopher Head --- src/target/armv7m.c | 53 +++++++++++++++---- src/target/armv7m.h | 112 +++++++++++++++++++++++++++++++--------- src/target/cortex_m.c | 64 ++++++++++------------- src/target/hla_target.c | 62 +++++++++++----------- 4 files changed, 189 insertions(+), 102 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 5e0694d8a..ba60a98a6 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -211,6 +211,40 @@ static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_OK; } +static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) +{ + switch (arm_reg_id) { + case ARMV7M_R0 ... ARMV7M_R14: + case ARMV7M_PC: + case ARMV7M_xPSR: + case ARMV7M_MSP: + case ARMV7M_PSP: + /* NOTE: we "know" here that the register identifiers + * match the Cortex-M DCRSR.REGSEL selectors values + * for R0..R14, PC, xPSR, MSP, and PSP. + */ + return arm_reg_id; + + case ARMV7M_FPSCR: + return ARMV7M_REGSEL_FPSCR; + + case ARMV7M_D0 ... ARMV7M_D15: + return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0); + + /* TODO: remove. This is temporary hack until packing/unpacking + * of special regs is moved to armv7m.c */ + case ARMV7M_PRIMASK: + case ARMV7M_BASEPRI: + case ARMV7M_FAULTMASK: + case ARMV7M_CONTROL: + return arm_reg_id; + + default: + LOG_ERROR("Bad register ID %u", arm_reg_id); + return arm_reg_id; + } +} + static int armv7m_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { @@ -223,22 +257,23 @@ static int armv7m_read_core_reg(struct target *target, struct reg *r, armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); + if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { /* map D0..D15 to S0..S31 */ - size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0); - retval = armv7m->load_core_reg_u32(target, regidx, ®_value); + retval = armv7m->load_core_reg_u32(target, regsel, ®_value); if (retval != ERROR_OK) return retval; buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value); - retval = armv7m->load_core_reg_u32(target, regidx + 1, ®_value); + retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value); if (retval != ERROR_OK) return retval; buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4, 0, 32, reg_value); } else { retval = armv7m->load_core_reg_u32(target, - armv7m_core_reg->num, ®_value); + regsel, ®_value); if (retval != ERROR_OK) return retval; buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value); @@ -261,24 +296,24 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r, armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); + if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { /* map D0..D15 to S0..S31 */ - size_t regidx = ARMV7M_S0 + 2 * (armv7m_core_reg->num - ARMV7M_D0); - uint32_t t = buf_get_u32(value, 0, 32); - retval = armv7m->store_core_reg_u32(target, regidx, t); + retval = armv7m->store_core_reg_u32(target, regsel, t); if (retval != ERROR_OK) goto out_error; t = buf_get_u32(value + 4, 0, 32); - retval = armv7m->store_core_reg_u32(target, regidx + 1, t); + retval = armv7m->store_core_reg_u32(target, regsel + 1, t); if (retval != ERROR_OK) goto out_error; } else { uint32_t t = buf_get_u32(value, 0, 32); LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t); - retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, t); + retval = armv7m->store_core_reg_u32(target, regsel, t); if (retval != ERROR_OK) goto out_error; } diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 01bf19e5c..8cd4df36f 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -34,36 +34,100 @@ extern const int armv7m_msp_reg_map[]; const char *armv7m_exception_string(int number); +/* Cortex-M DCRSR.REGSEL selectors */ +enum { + ARMV7M_REGSEL_R0, + ARMV7M_REGSEL_R1, + ARMV7M_REGSEL_R2, + ARMV7M_REGSEL_R3, + + ARMV7M_REGSEL_R4, + ARMV7M_REGSEL_R5, + ARMV7M_REGSEL_R6, + ARMV7M_REGSEL_R7, + + ARMV7M_REGSEL_R8, + ARMV7M_REGSEL_R9, + ARMV7M_REGSEL_R10, + ARMV7M_REGSEL_R11, + + ARMV7M_REGSEL_R12, + ARMV7M_REGSEL_R13, + ARMV7M_REGSEL_R14, + ARMV7M_REGSEL_PC = 15, + + ARMV7M_REGSEL_xPSR = 16, + ARMV7M_REGSEL_MSP, + ARMV7M_REGSEL_PSP, + + ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14, + ARMV7M_REGSEL_FPSCR = 0x21, + + /* 32bit Floating-point registers */ + ARMV7M_REGSEL_S0 = 0x40, + ARMV7M_REGSEL_S1, + ARMV7M_REGSEL_S2, + ARMV7M_REGSEL_S3, + ARMV7M_REGSEL_S4, + ARMV7M_REGSEL_S5, + ARMV7M_REGSEL_S6, + ARMV7M_REGSEL_S7, + ARMV7M_REGSEL_S8, + ARMV7M_REGSEL_S9, + ARMV7M_REGSEL_S10, + ARMV7M_REGSEL_S11, + ARMV7M_REGSEL_S12, + ARMV7M_REGSEL_S13, + ARMV7M_REGSEL_S14, + ARMV7M_REGSEL_S15, + ARMV7M_REGSEL_S16, + ARMV7M_REGSEL_S17, + ARMV7M_REGSEL_S18, + ARMV7M_REGSEL_S19, + ARMV7M_REGSEL_S20, + ARMV7M_REGSEL_S21, + ARMV7M_REGSEL_S22, + ARMV7M_REGSEL_S23, + ARMV7M_REGSEL_S24, + ARMV7M_REGSEL_S25, + ARMV7M_REGSEL_S26, + ARMV7M_REGSEL_S27, + ARMV7M_REGSEL_S28, + ARMV7M_REGSEL_S29, + ARMV7M_REGSEL_S30, + ARMV7M_REGSEL_S31, +}; + /* offsets into armv7m core register cache */ enum { /* for convenience, the first set of indices match - * the Cortex-M3/-M4 DCRSR selectors + * the Cortex-M DCRSR.REGSEL selectors */ - ARMV7M_R0, - ARMV7M_R1, - ARMV7M_R2, - ARMV7M_R3, + ARMV7M_R0 = ARMV7M_REGSEL_R0, + ARMV7M_R1 = ARMV7M_REGSEL_R1, + ARMV7M_R2 = ARMV7M_REGSEL_R2, + ARMV7M_R3 = ARMV7M_REGSEL_R3, - ARMV7M_R4, - ARMV7M_R5, - ARMV7M_R6, - ARMV7M_R7, + ARMV7M_R4 = ARMV7M_REGSEL_R4, + ARMV7M_R5 = ARMV7M_REGSEL_R5, + ARMV7M_R6 = ARMV7M_REGSEL_R6, + ARMV7M_R7 = ARMV7M_REGSEL_R7, - ARMV7M_R8, - ARMV7M_R9, - ARMV7M_R10, - ARMV7M_R11, + ARMV7M_R8 = ARMV7M_REGSEL_R8, + ARMV7M_R9 = ARMV7M_REGSEL_R9, + ARMV7M_R10 = ARMV7M_REGSEL_R10, + ARMV7M_R11 = ARMV7M_REGSEL_R11, - ARMV7M_R12, - ARMV7M_R13, - ARMV7M_R14, - ARMV7M_PC = 15, + ARMV7M_R12 = ARMV7M_REGSEL_R12, + ARMV7M_R13 = ARMV7M_REGSEL_R13, + ARMV7M_R14 = ARMV7M_REGSEL_R14, + ARMV7M_PC = ARMV7M_REGSEL_PC, - ARMV7M_xPSR = 16, - ARMV7M_MSP, - ARMV7M_PSP, + ARMV7M_xPSR = ARMV7M_REGSEL_xPSR, + ARMV7M_MSP = ARMV7M_REGSEL_MSP, + ARMV7M_PSP = ARMV7M_REGSEL_PSP, - /* this next set of indices is arbitrary */ + /* following indices are arbitrary, do not match DCRSR.REGSEL selectors */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, @@ -137,7 +201,7 @@ enum { }; #define ARMV7M_NUM_CORE_REGS (ARMV7M_xPSR + 1) -#define ARMV7M_NUM_CORE_REGS_NOFP (ARMV7M_NUM_CORE_REGS + 6) +#define ARMV7M_NUM_CORE_REGS_NOFP (ARMV7M_CONTROL + 1) #define ARMV7M_COMMON_MAGIC 0x2A452A45 @@ -159,8 +223,8 @@ struct armv7m_common { struct armv7m_trace_config trace_config; /* Direct processor core register read and writes */ - int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value); - int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value); + int (*load_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t *value); + int (*store_core_reg_u32)(struct target *target, uint32_t regsel, uint32_t value); int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 0c1a99fc0..4df903e66 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1607,29 +1607,25 @@ void cortex_m_enable_watchpoints(struct target *target) } static int cortex_m_load_core_reg_u32(struct target *target, - uint32_t num, uint32_t *value) + uint32_t regsel, uint32_t *value) { int retval; - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: + switch (regsel) { + case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: /* read a normal core register */ - retval = cortexm_dap_read_coreregister_u32(target, value, num); + retval = cortexm_dap_read_coreregister_u32(target, value, regsel); if (retval != ERROR_OK) { LOG_ERROR("JTAG failure %i", retval); return ERROR_JTAG_DEVICE_ERROR; } - LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); + LOG_DEBUG("load from core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); break; - case ARMV7M_FPSCR: + case ARMV7M_REGSEL_FPSCR: /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, 0x21); + retval = target_write_u32(target, DCB_DCRSR, ARMV7M_REGSEL_FPSCR); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, DCB_DCRDR, value); @@ -1638,16 +1634,16 @@ static int cortex_m_load_core_reg_u32(struct target *target, LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); break; - case ARMV7M_S0 ... ARMV7M_S31: + case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, num - ARMV7M_S0 + 0x40); + retval = target_write_u32(target, DCB_DCRSR, regsel); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, DCB_DCRDR, value); if (retval != ERROR_OK) return retval; LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), *value); + (int)(regsel - ARMV7M_REGSEL_S0), *value); break; case ARMV7M_PRIMASK: @@ -1658,9 +1654,9 @@ static int cortex_m_load_core_reg_u32(struct target *target, * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ - cortexm_dap_read_coreregister_u32(target, value, 20); + cortexm_dap_read_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - switch (num) { + switch (regsel) { case ARMV7M_PRIMASK: *value = buf_get_u32((uint8_t *)value, 0, 1); break; @@ -1678,7 +1674,7 @@ static int cortex_m_load_core_reg_u32(struct target *target, break; } - LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value); + LOG_DEBUG("load from special reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); break; default: @@ -1689,51 +1685,47 @@ static int cortex_m_load_core_reg_u32(struct target *target, } static int cortex_m_store_core_reg_u32(struct target *target, - uint32_t num, uint32_t value) + uint32_t regsel, uint32_t value) { int retval; uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - retval = cortexm_dap_write_coreregister_u32(target, value, num); + switch (regsel) { + case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: + retval = cortexm_dap_write_coreregister_u32(target, value, regsel); if (retval != ERROR_OK) { struct reg *r; LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + num; + r = armv7m->arm.core_cache->reg_list + regsel; /* TODO: don't use regsel as register index */ r->dirty = r->valid; return ERROR_JTAG_DEVICE_ERROR; } - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); + LOG_DEBUG("write core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, value); break; - case ARMV7M_FPSCR: + case ARMV7M_REGSEL_FPSCR: /* Floating-point Status and Registers */ retval = target_write_u32(target, DCB_DCRDR, value); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, DCB_DCRSR, 0x21 | (1<<16)); + retval = target_write_u32(target, DCB_DCRSR, ARMV7M_REGSEL_FPSCR | DCRSR_WnR); if (retval != ERROR_OK) return retval; LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); break; - case ARMV7M_S0 ... ARMV7M_S31: + case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: /* Floating-point Status and Registers */ retval = target_write_u32(target, DCB_DCRDR, value); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, DCB_DCRSR, (num - ARMV7M_S0 + 0x40) | (1<<16)); + retval = target_write_u32(target, DCB_DCRSR, regsel | DCRSR_WnR); if (retval != ERROR_OK) return retval; LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), value); + (int)(regsel - ARMV7M_REGSEL_S0), value); break; case ARMV7M_PRIMASK: @@ -1744,9 +1736,9 @@ static int cortex_m_store_core_reg_u32(struct target *target, * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ - cortexm_dap_read_coreregister_u32(target, ®, 20); + cortexm_dap_read_coreregister_u32(target, ®, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - switch (num) { + switch (regsel) { case ARMV7M_PRIMASK: buf_set_u32((uint8_t *)®, 0, 1, value); break; @@ -1764,9 +1756,9 @@ static int cortex_m_store_core_reg_u32(struct target *target, break; } - cortexm_dap_write_coreregister_u32(target, reg, 20); + cortexm_dap_write_coreregister_u32(target, reg, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); + LOG_DEBUG("write special reg %" PRIu32 " value 0x%" PRIx32 " ", regsel, value); break; default: diff --git a/src/target/hla_target.c b/src/target/hla_target.c index c02cbb643..f012664d7 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -51,7 +51,7 @@ static inline struct hl_interface_s *target_to_adapter(struct target *target) } static int adapter_load_core_reg_u32(struct target *target, - uint32_t num, uint32_t *value) + uint32_t regsel, uint32_t *value) { int retval; struct hl_interface_s *adapter = target_to_adapter(target); @@ -62,21 +62,21 @@ static int adapter_load_core_reg_u32(struct target *target, * in the v7m header match the Cortex-M3 Debug Core Register * Selector values for R0..R15, xPSR, MSP, and PSP. */ - switch (num) { - case 0 ... 18: + switch (regsel) { + case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: /* read a normal core register */ - retval = adapter->layout->api->read_reg(adapter->handle, num, value); + retval = adapter->layout->api->read_reg(adapter->handle, regsel, value); if (retval != ERROR_OK) { LOG_ERROR("JTAG failure %i", retval); return ERROR_JTAG_DEVICE_ERROR; } - LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); + LOG_DEBUG("load from core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); break; - case ARMV7M_FPSCR: + case ARMV7M_REGSEL_FPSCR: /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33); + retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); @@ -85,16 +85,16 @@ static int adapter_load_core_reg_u32(struct target *target, LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); break; - case ARMV7M_S0 ... ARMV7M_S31: + case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, num-ARMV7M_S0+64); + retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), *value); + (int)(regsel - ARMV7M_REGSEL_S0), *value); break; case ARMV7M_PRIMASK: @@ -105,11 +105,11 @@ static int adapter_load_core_reg_u32(struct target *target, * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ - retval = adapter->layout->api->read_reg(adapter->handle, 20, value); + retval = adapter->layout->api->read_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, value); if (retval != ERROR_OK) return retval; - switch (num) { + switch (regsel) { case ARMV7M_PRIMASK: *value = buf_get_u32((uint8_t *) value, 0, 1); break; @@ -127,8 +127,8 @@ static int adapter_load_core_reg_u32(struct target *target, break; } - LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", - (int)num, *value); + LOG_DEBUG("load from special reg %" PRIu32 " value 0x%" PRIx32 "", + regsel, *value); break; default: @@ -139,7 +139,7 @@ static int adapter_load_core_reg_u32(struct target *target, } static int adapter_store_core_reg_u32(struct target *target, - uint32_t num, uint32_t value) + uint32_t regsel, uint32_t value) { int retval; uint32_t reg; @@ -148,46 +148,42 @@ static int adapter_store_core_reg_u32(struct target *target, LOG_DEBUG("%s", __func__); - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (num) { - case 0 ... 18: - retval = adapter->layout->api->write_reg(adapter->handle, num, value); + switch (regsel) { + case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: + retval = adapter->layout->api->write_reg(adapter->handle, regsel, value); if (retval != ERROR_OK) { struct reg *r; LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + num; + r = armv7m->arm.core_cache->reg_list + regsel; /* TODO: don't use regsel as register index */ r->dirty = r->valid; return ERROR_JTAG_DEVICE_ERROR; } - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); + LOG_DEBUG("write core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, value); break; - case ARMV7M_FPSCR: + case ARMV7M_REGSEL_FPSCR: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33 | (1<<16)); + retval = target_write_u32(target, ARMV7M_SCS_DCRSR, ARMV7M_REGSEL_FPSCR | DCRSR_WnR); if (retval != ERROR_OK) return retval; LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); break; - case ARMV7M_S0 ... ARMV7M_S31: + case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, (num-ARMV7M_S0+64) | (1<<16)); + retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel | DCRSR_WnR); if (retval != ERROR_OK) return retval; LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(num - ARMV7M_S0), value); + (int)(regsel - ARMV7M_REGSEL_S0), value); break; case ARMV7M_PRIMASK: @@ -199,9 +195,9 @@ static int adapter_store_core_reg_u32(struct target *target, * it was removed from r1 docs, but still works. */ - adapter->layout->api->read_reg(adapter->handle, 20, ®); + adapter->layout->api->read_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, ®); - switch (num) { + switch (regsel) { case ARMV7M_PRIMASK: buf_set_u32((uint8_t *) ®, 0, 1, value); break; @@ -219,9 +215,9 @@ static int adapter_store_core_reg_u32(struct target *target, break; } - adapter->layout->api->write_reg(adapter->handle, 20, reg); + adapter->layout->api->write_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, reg); - LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); + LOG_DEBUG("write special reg %" PRIu32 " value 0x%" PRIx32 " ", regsel, value); break; default: From e4160bd42216d5e717822162e1dad83b1b7003a1 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Oct 2020 16:52:09 +0200 Subject: [PATCH 068/113] target/armv7m: rework Cortex-M register handling part 2 Make arm register id coherent with reg_list index. Without this reg_list[ARMV7M_R12] was possible but reg_list[ARMV7M_FPSCR] was out of bounds. Remove unused items from reg_list index. Change-Id: I84d3b5c496fc1839d07a5b74cb1fd1c3d4ff8989 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5862 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Christopher Head --- src/target/armv7m.c | 2 ++ src/target/armv7m.h | 38 +------------------------------------- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index ba60a98a6..177437391 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -254,6 +254,7 @@ static int armv7m_read_core_reg(struct target *target, struct reg *r, struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); + assert(num == (int)r->number); armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; @@ -293,6 +294,7 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r, struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); + assert(num == (int)r->number); armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 8cd4df36f..bd10905b8 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -133,40 +133,6 @@ enum { ARMV7M_FAULTMASK, ARMV7M_CONTROL, - /* 32bit Floating-point registers */ - ARMV7M_S0, - ARMV7M_S1, - ARMV7M_S2, - ARMV7M_S3, - ARMV7M_S4, - ARMV7M_S5, - ARMV7M_S6, - ARMV7M_S7, - ARMV7M_S8, - ARMV7M_S9, - ARMV7M_S10, - ARMV7M_S11, - ARMV7M_S12, - ARMV7M_S13, - ARMV7M_S14, - ARMV7M_S15, - ARMV7M_S16, - ARMV7M_S17, - ARMV7M_S18, - ARMV7M_S19, - ARMV7M_S20, - ARMV7M_S21, - ARMV7M_S22, - ARMV7M_S23, - ARMV7M_S24, - ARMV7M_S25, - ARMV7M_S26, - ARMV7M_S27, - ARMV7M_S28, - ARMV7M_S29, - ARMV7M_S30, - ARMV7M_S31, - /* 64bit Floating-point registers */ ARMV7M_D0, ARMV7M_D1, @@ -185,10 +151,8 @@ enum { ARMV7M_D14, ARMV7M_D15, - /* Floating-point status registers */ - ARMV7M_FPSID, + /* Floating-point status register */ ARMV7M_FPSCR, - ARMV7M_FPEXC, ARMV7M_LAST_REG, }; From d3a37b0e76ece5625db74b4f343ebcc90059657f Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Oct 2020 20:23:50 +0200 Subject: [PATCH 069/113] target/armv7m: rework Cortex-M register handling part 3 Move primask/basepri/faultmask/control packing/unpacking from cortex_m.c and hla_target.c to armv7m.c armv7m_read_core_reg() and armv7m_write_core_reg() where also the FP 32/64-bit registers conversion takes place. Introduce a new hidden register ARMV7M_PMSK_BPRI_FLTMSK_CTRL for packing/unpacking of special registers in the register cache. The new packing/unpacking is endianess safe. While on it improve returned error codes and LOG_ messages. Just minimal changes in cortex_m.c and hla_target.c, will be consolidated in the next patch. Change-Id: Id51e764e243e54b5fdaadf2a202eee7c4bc729fe Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5863 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Antonio Borneo --- src/target/armv7m.c | 204 +++++++++++++++++++++++++++++----------- src/target/armv7m.h | 10 ++ src/target/cortex_m.c | 67 ++----------- src/target/hla_target.c | 65 +------------ 4 files changed, 170 insertions(+), 176 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 177437391..7e9b72a8e 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -14,6 +14,9 @@ * Copyright (C) 2018 by Liviu Ionescu * * * * * + * Copyright (C) 2019 by Tomas Vanek * + * vanekt@fbl.cz * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -108,6 +111,15 @@ static const struct { { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, + /* A working register for packing/unpacking special regs, hidden from gdb */ + { ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL }, + + /* WARNING: If you use armv7m_write_core_reg() on one of 4 following + * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL + * cache only and are not flushed to CPU HW register. + * To trigger write to CPU HW register, add + * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); + */ { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, @@ -150,6 +162,9 @@ int armv7m_restore_context(struct target *target) if (armv7m->pre_restore_context) armv7m->pre_restore_context(target); + /* The descending order of register writes is crucial for correct + * packing of ARMV7M_PMSK_BPRI_FLTMSK_CTRL! + * See also comments in the register table above */ for (i = cache->num_regs - 1; i >= 0; i--) { if (cache->reg_list[i].dirty) { armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, @@ -225,110 +240,181 @@ static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) */ return arm_reg_id; + case ARMV7M_PMSK_BPRI_FLTMSK_CTRL: + return ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL; + case ARMV7M_FPSCR: return ARMV7M_REGSEL_FPSCR; case ARMV7M_D0 ... ARMV7M_D15: return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0); - /* TODO: remove. This is temporary hack until packing/unpacking - * of special regs is moved to armv7m.c */ - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - return arm_reg_id; - default: LOG_ERROR("Bad register ID %u", arm_reg_id); return arm_reg_id; } } +static bool armv7m_map_reg_packing(unsigned int arm_reg_id, + unsigned int *reg32_id, uint32_t *offset) +{ + switch (arm_reg_id) { + + case ARMV7M_PRIMASK: + *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; + *offset = 0; + return true; + case ARMV7M_BASEPRI: + *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; + *offset = 1; + return true; + case ARMV7M_FAULTMASK: + *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; + *offset = 2; + return true; + case ARMV7M_CONTROL: + *reg32_id = ARMV7M_PMSK_BPRI_FLTMSK_CTRL; + *offset = 3; + return true; + + default: + return false; + } +} + static int armv7m_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t reg_value; int retval; - struct arm_reg *armv7m_core_reg; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); assert(num == (int)r->number); - armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; + /* If a code calls read_reg, it expects the cache is no more dirty. + * Clear the dirty flag regardless of the later read succeeds or not + * to prevent unwanted cache flush after a read error */ + r->dirty = false; - uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); + if (r->size <= 8) { + /* any 8-bit or shorter register is packed */ + uint32_t offset = 0; /* silence false gcc warning */ + unsigned int reg32_id; + + bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); + assert(is_packed); + struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; + + /* Read 32-bit container register if not cached */ + if (!r32->valid) { + retval = armv7m_read_core_reg(target, r32, reg32_id, mode); + if (retval != ERROR_OK) + return retval; + } + + /* Copy required bits of 32-bit container register */ + buf_cpy(r32->value + offset, r->value, r->size); + + } else { + assert(r->size == 32 || r->size == 64); + + struct arm_reg *armv7m_core_reg = r->arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); - if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { - /* map D0..D15 to S0..S31 */ retval = armv7m->load_core_reg_u32(target, regsel, ®_value); if (retval != ERROR_OK) return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, - 0, 32, reg_value); - retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value); - if (retval != ERROR_OK) - return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value + 4, - 0, 32, reg_value); - } else { - retval = armv7m->load_core_reg_u32(target, - regsel, ®_value); - if (retval != ERROR_OK) - return retval; - buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value); + buf_set_u32(r->value, 0, 32, reg_value); + + if (r->size == 64) { + retval = armv7m->load_core_reg_u32(target, regsel + 1, ®_value); + if (retval != ERROR_OK) { + r->valid = false; + return retval; + } + buf_set_u32(r->value + 4, 0, 32, reg_value); + + uint64_t q = buf_get_u64(r->value, 0, 64); + LOG_DEBUG("read %s value 0x%016" PRIx64, r->name, q); + } else { + LOG_DEBUG("read %s value 0x%08" PRIx32, r->name, reg_value); + } } - armv7m->arm.core_cache->reg_list[num].valid = true; - armv7m->arm.core_cache->reg_list[num].dirty = false; + r->valid = true; - return retval; + return ERROR_OK; } static int armv7m_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint8_t *value) { int retval; - struct arm_reg *armv7m_core_reg; + uint32_t t; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); assert(num == (int)r->number); - armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; - - uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); - - if ((armv7m_core_reg->num >= ARMV7M_D0) && (armv7m_core_reg->num <= ARMV7M_D15)) { - /* map D0..D15 to S0..S31 */ - uint32_t t = buf_get_u32(value, 0, 32); - retval = armv7m->store_core_reg_u32(target, regsel, t); - if (retval != ERROR_OK) - goto out_error; - - t = buf_get_u32(value + 4, 0, 32); - retval = armv7m->store_core_reg_u32(target, regsel + 1, t); - if (retval != ERROR_OK) - goto out_error; - } else { - uint32_t t = buf_get_u32(value, 0, 32); - - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, t); - retval = armv7m->store_core_reg_u32(target, regsel, t); - if (retval != ERROR_OK) - goto out_error; + if (value != r->value) { + /* If we are not flushing the cache, store the new value to the cache */ + buf_cpy(value, r->value, r->size); } - armv7m->arm.core_cache->reg_list[num].valid = true; - armv7m->arm.core_cache->reg_list[num].dirty = false; + if (r->size <= 8) { + /* any 8-bit or shorter register is packed */ + uint32_t offset = 0; /* silence false gcc warning */ + unsigned int reg32_id; + + bool is_packed = armv7m_map_reg_packing(num, ®32_id, &offset); + assert(is_packed); + struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id]; + + if (!r32->valid) { + /* Before merging with other parts ensure the 32-bit register is valid */ + retval = armv7m_read_core_reg(target, r32, reg32_id, mode); + if (retval != ERROR_OK) + return retval; + } + + /* Write a part to the 32-bit container register */ + buf_cpy(value, r32->value + offset, r->size); + r32->dirty = true; + + } else { + assert(r->size == 32 || r->size == 64); + + struct arm_reg *armv7m_core_reg = r->arch_info; + uint32_t regsel = armv7m_map_id_to_regsel(armv7m_core_reg->num); + + t = buf_get_u32(value, 0, 32); + retval = armv7m->store_core_reg_u32(target, regsel, t); + if (retval != ERROR_OK) + goto out_error; + + if (r->size == 64) { + t = buf_get_u32(value + 4, 0, 32); + retval = armv7m->store_core_reg_u32(target, regsel + 1, t); + if (retval != ERROR_OK) + goto out_error; + + uint64_t q = buf_get_u64(value, 0, 64); + LOG_DEBUG("write %s value 0x%016" PRIx64, r->name, q); + } else { + LOG_DEBUG("write %s value 0x%08" PRIx32, r->name, t); + } + } + + r->valid = true; + r->dirty = false; return ERROR_OK; out_error: - LOG_ERROR("Error setting register"); - armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid; - return ERROR_JTAG_DEVICE_ERROR; + r->dirty = true; + LOG_ERROR("Error setting register %s", r->name); + return retval; } /** @@ -661,6 +747,7 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].value = calloc(1, storage_size); reg_list[i].dirty = false; reg_list[i].valid = false; + reg_list[i].hidden = i == ARMV7M_PMSK_BPRI_FLTMSK_CTRL; reg_list[i].type = &armv7m_reg_type; reg_list[i].arch_info = &arch_info[i]; @@ -669,6 +756,9 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ + if (reg_list[i].hidden) + continue; + feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = armv7m_regs[i].feature; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index bd10905b8..db6f8bc52 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -128,6 +128,16 @@ enum { ARMV7M_PSP = ARMV7M_REGSEL_PSP, /* following indices are arbitrary, do not match DCRSR.REGSEL selectors */ + + /* working register for packing/unpacking special regs, hidden from gdb */ + ARMV7M_PMSK_BPRI_FLTMSK_CTRL, + + /* WARNING: If you use armv7m_write_core_reg() on one of 4 following + * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL + * cache only and are not flushed to CPU HW register. + * To trigger write to CPU HW register, add + * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); + */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 4df903e66..00e7c3a57 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1646,35 +1646,12 @@ static int cortex_m_load_core_reg_u32(struct target *target, (int)(regsel - ARMV7M_REGSEL_S0), *value); break; - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - cortexm_dap_read_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); + case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: + retval = cortexm_dap_read_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); + if (retval != ERROR_OK) + return retval; - switch (regsel) { - case ARMV7M_PRIMASK: - *value = buf_get_u32((uint8_t *)value, 0, 1); - break; - - case ARMV7M_BASEPRI: - *value = buf_get_u32((uint8_t *)value, 8, 8); - break; - - case ARMV7M_FAULTMASK: - *value = buf_get_u32((uint8_t *)value, 16, 1); - break; - - case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *)value, 24, 3); - break; - } - - LOG_DEBUG("load from special reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); + LOG_DEBUG("load from special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, *value); break; default: @@ -1688,7 +1665,6 @@ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { int retval; - uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); switch (regsel) { @@ -1728,37 +1704,10 @@ static int cortex_m_store_core_reg_u32(struct target *target, (int)(regsel - ARMV7M_REGSEL_S0), value); break; - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ - cortexm_dap_read_coreregister_u32(target, ®, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); + case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: + cortexm_dap_write_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - switch (regsel) { - case ARMV7M_PRIMASK: - buf_set_u32((uint8_t *)®, 0, 1, value); - break; - - case ARMV7M_BASEPRI: - buf_set_u32((uint8_t *)®, 8, 8, value); - break; - - case ARMV7M_FAULTMASK: - buf_set_u32((uint8_t *)®, 16, 1, value); - break; - - case ARMV7M_CONTROL: - buf_set_u32((uint8_t *)®, 24, 3, value); - break; - } - - cortexm_dap_write_coreregister_u32(target, reg, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - - LOG_DEBUG("write special reg %" PRIu32 " value 0x%" PRIx32 " ", regsel, value); + LOG_DEBUG("write special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, value); break; default: diff --git a/src/target/hla_target.c b/src/target/hla_target.c index f012664d7..725c2d2fe 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -97,38 +97,12 @@ static int adapter_load_core_reg_u32(struct target *target, (int)(regsel - ARMV7M_REGSEL_S0), *value); break; - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ + case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: retval = adapter->layout->api->read_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, value); if (retval != ERROR_OK) return retval; - switch (regsel) { - case ARMV7M_PRIMASK: - *value = buf_get_u32((uint8_t *) value, 0, 1); - break; - - case ARMV7M_BASEPRI: - *value = buf_get_u32((uint8_t *) value, 8, 8); - break; - - case ARMV7M_FAULTMASK: - *value = buf_get_u32((uint8_t *) value, 16, 1); - break; - - case ARMV7M_CONTROL: - *value = buf_get_u32((uint8_t *) value, 24, 3); - break; - } - - LOG_DEBUG("load from special reg %" PRIu32 " value 0x%" PRIx32 "", - regsel, *value); + LOG_DEBUG("load from special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, *value); break; default: @@ -142,7 +116,6 @@ static int adapter_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { int retval; - uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); struct hl_interface_s *adapter = target_to_adapter(target); @@ -186,38 +159,10 @@ static int adapter_store_core_reg_u32(struct target *target, (int)(regsel - ARMV7M_REGSEL_S0), value); break; - case ARMV7M_PRIMASK: - case ARMV7M_BASEPRI: - case ARMV7M_FAULTMASK: - case ARMV7M_CONTROL: - /* Cortex-M3 packages these four registers as bitfields - * in one Debug Core register. So say r0 and r2 docs; - * it was removed from r1 docs, but still works. - */ + case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: + adapter->layout->api->write_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, value); - adapter->layout->api->read_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, ®); - - switch (regsel) { - case ARMV7M_PRIMASK: - buf_set_u32((uint8_t *) ®, 0, 1, value); - break; - - case ARMV7M_BASEPRI: - buf_set_u32((uint8_t *) ®, 8, 8, value); - break; - - case ARMV7M_FAULTMASK: - buf_set_u32((uint8_t *) ®, 16, 1, value); - break; - - case ARMV7M_CONTROL: - buf_set_u32((uint8_t *) ®, 24, 3, value); - break; - } - - adapter->layout->api->write_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, reg); - - LOG_DEBUG("write special reg %" PRIu32 " value 0x%" PRIx32 " ", regsel, value); + LOG_DEBUG("write special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, value); break; default: From 62394a6b1c25ac92630a4828ec1b5d70acfe6e0f Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 14 Oct 2020 21:03:02 +0200 Subject: [PATCH 070/113] target/cortex_m,hla_target: rework Cortex-M register handling part 4 Consolidate low level register read/write. Floating point registers were handled by target_read/write_u32 unlike other registers handled by cortexm_dap_read/write_coreregister_u32 There is no reason to do so in cortex_m. Remove cortexm_dap_read/write_coreregister_u32 and use cortex_m_load/store_core_reg_u32 directly. Similarly HLA adapters register read/write interface supports all registers so use it for any floating point and other registers. Change-Id: Ida679e5f4fec02d94ffb0bd3f265ed7ed2221cdc Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5864 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 123 ++-------------------------------------- src/target/hla_target.c | 112 +----------------------------------- 2 files changed, 8 insertions(+), 227 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 00e7c3a57..72a2bd322 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -56,8 +56,8 @@ static int cortex_m_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); static void cortex_m_dwt_free(struct target *target); -static int cortexm_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum) +static int cortex_m_load_core_reg_u32(struct target *target, + uint32_t regsel, uint32_t *value) { struct armv7m_common *armv7m = target_to_armv7m(target); int retval; @@ -71,7 +71,7 @@ static int cortexm_dap_read_coreregister_u32(struct target *target, return retval; } - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regnum); + retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel); if (retval != ERROR_OK) return retval; @@ -89,8 +89,8 @@ static int cortexm_dap_read_coreregister_u32(struct target *target, return retval; } -static int cortexm_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum) +static int cortex_m_store_core_reg_u32(struct target *target, + uint32_t regsel, uint32_t value) { struct armv7m_common *armv7m = target_to_armv7m(target); int retval; @@ -108,7 +108,7 @@ static int cortexm_dap_write_coreregister_u32(struct target *target, if (retval != ERROR_OK) return retval; - retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regnum | DCRSR_WnR); + retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WnR); if (retval != ERROR_OK) return retval; @@ -1606,117 +1606,6 @@ void cortex_m_enable_watchpoints(struct target *target) } } -static int cortex_m_load_core_reg_u32(struct target *target, - uint32_t regsel, uint32_t *value) -{ - int retval; - - switch (regsel) { - case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: - /* read a normal core register */ - retval = cortexm_dap_read_coreregister_u32(target, value, regsel); - - if (retval != ERROR_OK) { - LOG_ERROR("JTAG failure %i", retval); - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("load from core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); - break; - - case ARMV7M_REGSEL_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, ARMV7M_REGSEL_FPSCR); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); - break; - - case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRSR, regsel); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(regsel - ARMV7M_REGSEL_S0), *value); - break; - - case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: - retval = cortexm_dap_read_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("load from special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, *value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - -static int cortex_m_store_core_reg_u32(struct target *target, - uint32_t regsel, uint32_t value) -{ - int retval; - struct armv7m_common *armv7m = target_to_armv7m(target); - - switch (regsel) { - case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: - retval = cortexm_dap_write_coreregister_u32(target, value, regsel); - if (retval != ERROR_OK) { - struct reg *r; - - LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + regsel; /* TODO: don't use regsel as register index */ - r->dirty = r->valid; - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("write core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, value); - break; - - case ARMV7M_REGSEL_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, DCB_DCRSR, ARMV7M_REGSEL_FPSCR | DCRSR_WnR); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); - break; - - case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, DCB_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, DCB_DCRSR, regsel | DCRSR_WnR); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(regsel - ARMV7M_REGSEL_S0), value); - break; - - case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: - cortexm_dap_write_coreregister_u32(target, value, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL); - - LOG_DEBUG("write special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} - static int cortex_m_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 725c2d2fe..99afccc49 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -53,123 +53,15 @@ static inline struct hl_interface_s *target_to_adapter(struct target *target) static int adapter_load_core_reg_u32(struct target *target, uint32_t regsel, uint32_t *value) { - int retval; struct hl_interface_s *adapter = target_to_adapter(target); - - LOG_DEBUG("%s", __func__); - - /* NOTE: we "know" here that the register identifiers used - * in the v7m header match the Cortex-M3 Debug Core Register - * Selector values for R0..R15, xPSR, MSP, and PSP. - */ - switch (regsel) { - case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: - /* read a normal core register */ - retval = adapter->layout->api->read_reg(adapter->handle, regsel, value); - - if (retval != ERROR_OK) { - LOG_ERROR("JTAG failure %i", retval); - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("load from core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, *value); - break; - - case ARMV7M_REGSEL_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPSCR value 0x%" PRIx32, *value); - break; - - case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel); - if (retval != ERROR_OK) - return retval; - retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("load from FPU reg S%d value 0x%" PRIx32, - (int)(regsel - ARMV7M_REGSEL_S0), *value); - break; - - case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: - retval = adapter->layout->api->read_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, value); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("load from special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, *value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; + return adapter->layout->api->read_reg(adapter->handle, regsel, value); } static int adapter_store_core_reg_u32(struct target *target, uint32_t regsel, uint32_t value) { - int retval; - struct armv7m_common *armv7m = target_to_armv7m(target); struct hl_interface_s *adapter = target_to_adapter(target); - - LOG_DEBUG("%s", __func__); - - switch (regsel) { - case ARMV7M_REGSEL_R0 ... ARMV7M_REGSEL_PSP: - retval = adapter->layout->api->write_reg(adapter->handle, regsel, value); - - if (retval != ERROR_OK) { - struct reg *r; - - LOG_ERROR("JTAG failure"); - r = armv7m->arm.core_cache->reg_list + regsel; /* TODO: don't use regsel as register index */ - r->dirty = r->valid; - return ERROR_JTAG_DEVICE_ERROR; - } - LOG_DEBUG("write core reg %" PRIu32 " value 0x%" PRIx32 "", regsel, value); - break; - - case ARMV7M_REGSEL_FPSCR: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, ARMV7M_REGSEL_FPSCR | DCRSR_WnR); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPSCR value 0x%" PRIx32, value); - break; - - case ARMV7M_REGSEL_S0 ... ARMV7M_REGSEL_S31: - /* Floating-point Status and Registers */ - retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, ARMV7M_SCS_DCRSR, regsel | DCRSR_WnR); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("write FPU reg S%d value 0x%" PRIx32, - (int)(regsel - ARMV7M_REGSEL_S0), value); - break; - - case ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL: - adapter->layout->api->write_reg(adapter->handle, ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL, value); - - LOG_DEBUG("write special reg PRIMASK/BASEPRI/FAULTMASK/CONTROL value 0x%" PRIx32, value); - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; + return adapter->layout->api->write_reg(adapter->handle, regsel, value); } static int adapter_examine_debug_reason(struct target *target) From be631eed16bd9ef2b735fd64650ca7283d2ca361 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 25 Oct 2020 14:59:13 +0100 Subject: [PATCH 071/113] hla: API: specify that read_reg/write_reg use regsel as parameter The API of hla have been defined from ST-Link basic operations. By chance, all the current implementation of hla (st-link, ti-icdi and nulink) share the same way to handle the parameter 'num' of the API read_reg() and write_reg(), that is simply using it to initialize the field REGSEL (bits [6:0]) of armv7m Debug Core Register Selector Register (DCRSR). Add a comment in the API definition to highlight this, in case it get used by a further hla implementation, then rename as 'regsel' the 'num' parameter. Change-Id: I4b6a2c7d78b4fc4de2b9b2bdba065414b15c6ba3 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5882 Reviewed-by: Edward Fewell Tested-by: jenkins Reviewed-by: Zale Yu Reviewed-by: Tomas Vanek --- src/jtag/drivers/nulink_usb.c | 8 ++++---- src/jtag/drivers/stlink_usb.c | 8 ++++---- src/jtag/drivers/ti_icdi_usb.c | 8 ++++---- src/jtag/hla/hla_layout.h | 23 +++++++++++++++++++---- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c index 5fdbed3fc..00738ee4e 100644 --- a/src/jtag/drivers/nulink_usb.c +++ b/src/jtag/drivers/nulink_usb.c @@ -411,7 +411,7 @@ static int nulink_usb_step(void *handle) return res; } -static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) +static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { struct nulink_usb_handle_s *h = handle; @@ -434,7 +434,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ - h_u32_to_le(h->cmdbuf + h->cmdidx, num); + h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, 0); @@ -450,7 +450,7 @@ static int nulink_usb_read_reg(void *handle, int num, uint32_t *val) return res; } -static int nulink_usb_write_reg(void *handle, int num, uint32_t val) +static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct nulink_usb_handle_s *h = handle; @@ -473,7 +473,7 @@ static int nulink_usb_write_reg(void *handle, int num, uint32_t val) h->cmdbuf[h->cmdidx] = 0; h->cmdidx += 1; /* u32Addr */ - h_u32_to_le(h->cmdbuf + h->cmdidx, num); + h_u32_to_le(h->cmdbuf + h->cmdidx, regsel); h->cmdidx += 4; /* u32Data */ h_u32_to_le(h->cmdbuf + h->cmdidx, val); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index c54e2cc19..1d38103a2 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -2016,7 +2016,7 @@ static int stlink_usb_read_regs(void *handle) } /** */ -static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) +static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int res; struct stlink_usb_handle_s *h = handle; @@ -2030,7 +2030,7 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG; - h->cmdbuf[h->cmdidx++] = num; + h->cmdbuf[h->cmdidx++] = regsel; if (h->version.jtag_api == STLINK_JTAG_API_V1) { res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 4); @@ -2048,7 +2048,7 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) } /** */ -static int stlink_usb_write_reg(void *handle, int num, uint32_t val) +static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { struct stlink_usb_handle_s *h = handle; @@ -2061,7 +2061,7 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG; - h->cmdbuf[h->cmdidx++] = num; + h->cmdbuf[h->cmdidx++] = regsel; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 920be7783..00b2f9675 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -475,13 +475,13 @@ static int icdi_usb_read_regs(void *handle) return ERROR_OK; } -static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) +static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) { int result; struct icdi_usb_handle_s *h = handle; char cmd[10]; - snprintf(cmd, sizeof(cmd), "p%x", num); + snprintf(cmd, sizeof(cmd), "p%x", regsel); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; @@ -504,14 +504,14 @@ static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) return result; } -static int icdi_usb_write_reg(void *handle, int num, uint32_t val) +static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) { int result; char cmd[20]; uint8_t buf[4]; h_u32_to_le(buf, val); - int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num); + int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", regsel); hexify(cmd + cmd_len, buf, 4, sizeof(cmd)); result = icdi_send_cmd(handle, cmd); diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h index e0bbd0fed..a8088fe95 100644 --- a/src/jtag/hla/hla_layout.h +++ b/src/jtag/hla/hla_layout.h @@ -51,10 +51,25 @@ struct hl_layout_api_s { int (*step)(void *handle); /** */ int (*read_regs)(void *handle); - /** */ - int (*read_reg)(void *handle, int num, uint32_t *val); - /** */ - int (*write_reg)(void *handle, int num, uint32_t val); + /** + * Read one register from the target + * + * @param handle A pointer to the device-specific handle + * @param regsel Register selection index compatible with all the + * values allowed by armv7m DCRSR.REGSEL + * @param val A pointer to retrieve the register value + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*read_reg)(void *handle, unsigned int regsel, uint32_t *val); + /** + * Write one register to the target + * @param handle A pointer to the device-specific handle + * @param regsel Register selection index compatible with all the + * values allowed by armv7m DCRSR.REGSEL + * @param val The value to be written in the register + * @returns ERROR_OK on success, or an error code on failure. + */ + int (*write_reg)(void *handle, unsigned int regsel, uint32_t val); /** */ int (*read_mem)(void *handle, uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer); From 4d336e8ffb7507f893640d344326b46f4bd8762d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 25 Oct 2020 17:35:45 +0100 Subject: [PATCH 072/113] stlink: handle read/write FPU registers in HLA API Old stlink firmware in stlink V1 and stlink V2 pre-J15 do not handle FPU registers in the read_reg() and write_reg() API. Add code to be compatible with the new API of OpenOCD. Change-Id: Ib0439c5294b6911ea75efe8c7fa085b014317a4b Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5883 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/jtag/drivers/stlink_usb.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 1d38103a2..4545bcba0 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -324,6 +324,9 @@ struct stlink_usb_handle_s { /* aliases */ #define STLINK_F_HAS_TARGET_VOLT STLINK_F_HAS_TRACE +#define STLINK_F_HAS_FPU_REG STLINK_F_HAS_GETLASTRWSTATUS2 + +#define STLINK_REGSEL_IS_FPU(x) ((x) > 0x1F) struct speed_map { int speed; @@ -2023,6 +2026,15 @@ static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val) assert(handle != NULL); + if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { + res = stlink_usb_write_debug_reg(h, DCB_DCRSR, regsel & 0x7f); + if (res != ERROR_OK) + return res; + + /* FIXME: poll DHCSR.S_REGRDY before read DCRDR */ + return stlink_usb_v2_read_debug_reg(h, DCB_DCRDR, val); + } + stlink_usb_init_buffer(handle, h->rx_ep, h->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; @@ -2054,6 +2066,15 @@ static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val) assert(handle != NULL); + if (STLINK_REGSEL_IS_FPU(regsel) && !(h->version.flags & STLINK_F_HAS_FPU_REG)) { + int res = stlink_usb_write_debug_reg(h, DCB_DCRDR, val); + if (res != ERROR_OK) + return res; + + return stlink_usb_write_debug_reg(h, DCB_DCRSR, DCRSR_WnR | (regsel & 0x7f)); + /* FIXME: poll DHCSR.S_REGRDY after write DCRSR */ + } + stlink_usb_init_buffer(handle, h->rx_ep, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; From d811d2838b9edc230946a308917aedc28c9d111e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 21 Oct 2020 16:12:27 +0200 Subject: [PATCH 073/113] cortex_m: use the new enum ARMV7M_REGSEL_name Register xPSR is indexed directly with its value 16 or with the incorrect enum ARMV7M_xPSR. Replace them with the new enum ARMV7M_REGSEL_xPSR. Change-Id: I86600e7f78e39002ce45f66d4792d5067c1f541b Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5873 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/flash/nor/psoc6.c | 2 +- src/target/cortex_m.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 30bf88501..19d483bab 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -153,7 +153,7 @@ static int sromalgo_prepare(struct target *target) /* Restore THUMB bit in xPSR register */ const struct armv7m_common *cm = target_to_armv7m(target); - hr = cm->store_core_reg_u32(target, ARMV7M_xPSR, 0x01000000); + hr = cm->store_core_reg_u32(target, ARMV7M_REGSEL_xPSR, 0x01000000); if (hr != ERROR_OK) return hr; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 72a2bd322..ced7a8a67 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -530,7 +530,7 @@ static int cortex_m_debug_entry(struct target *target) /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */ if (xPSR & 0xf00) { r->dirty = r->valid; - cortex_m_store_core_reg_u32(target, 16, xPSR & ~0xff); + cortex_m_store_core_reg_u32(target, ARMV7M_REGSEL_xPSR, xPSR & ~0xff); } /* Are we in an exception handler */ From fc91936be7bac7a84636d6b907ac545876263f3e Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 20 Oct 2019 14:27:36 +0200 Subject: [PATCH 074/113] target/armv7m: use arch_info[i].value instead of allocated memory Change-Id: I9422cab484d0769404516947e16da1baa001a4e0 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5328 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/armv7m.c | 6 +----- src/target/cortex_m.c | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 7e9b72a8e..13370b54b 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -741,10 +741,7 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) reg_list[i].name = armv7m_regs[i].name; reg_list[i].size = armv7m_regs[i].bits; - size_t storage_size = DIV_ROUND_UP(armv7m_regs[i].bits, 8); - if (storage_size < 4) - storage_size = 4; - reg_list[i].value = calloc(1, storage_size); + reg_list[i].value = arch_info[i].value; reg_list[i].dirty = false; reg_list[i].valid = false; reg_list[i].hidden = i == ARMV7M_PMSK_BPRI_FLTMSK_CTRL; @@ -798,7 +795,6 @@ void armv7m_free_reg_cache(struct target *target) free(reg->feature); free(reg->reg_data_type); - free(reg->value); } free(cache->reg_list[0].arch_info); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ced7a8a67..7b3f3c70e 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -2044,7 +2044,6 @@ int cortex_m_examine(struct target *target) for (idx = ARMV7M_NUM_CORE_REGS_NOFP; idx < armv7m->arm.core_cache->num_regs; idx++) { - free(armv7m->arm.core_cache->reg_list[idx].value); free(armv7m->arm.core_cache->reg_list[idx].feature); free(armv7m->arm.core_cache->reg_list[idx].reg_data_type); } From f32ca2d25dae5526bf0bd70b1143aa34412fc7ec Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 22 Oct 2020 12:50:24 +0200 Subject: [PATCH 075/113] target/cortex_m: remove wrong xPSR.ICI/IT bits handling If a Cortex-M (not M0, M0+) target was stopped in the middle of a conditional IT block or in the load/store multiple instruction, cortex_m_debug_entry() used wrong xPSR bits to detect it and then cleared 8 bits of the exception number from xPSR - probably wrong bit mask again. I believe clearing of the ICI/IT bits in cortex_m_debug_entry() has no reason as Cortex-M does not use instruction injecting. Remove the wrong code. The change was originally a part of http://openocd.zylin.com/4862 It is now re-submitted as #4862 is not ready. Change-Id: If91cd91d1b81b2684f7d5f10cf20452cde1a7f56 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5874 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Antonio Borneo --- src/target/cortex_m.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 7b3f3c70e..fc72c0ed0 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -527,12 +527,6 @@ static int cortex_m_debug_entry(struct target *target) r = arm->cpsr; xPSR = buf_get_u32(r->value, 0, 32); - /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */ - if (xPSR & 0xf00) { - r->dirty = r->valid; - cortex_m_store_core_reg_u32(target, ARMV7M_REGSEL_xPSR, xPSR & ~0xff); - } - /* Are we in an exception handler */ if (xPSR & 0x1FF) { armv7m->exception_number = (xPSR & 0x1FF); From 608299484d52a60082bb7ff5bcde5249f9a3a1de Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 22 Oct 2020 13:18:40 +0200 Subject: [PATCH 076/113] flash/nor/psoc6: remove setting of xPSR.T bit from sromalgo_prepare() PSoC6 erases flash to 0x00 not more common 0xff, so a device with erased flash loads xPSR.T=0 from the zeroed reset vector. Wrong thumb bit value caused a target algorithm failed with HardFault. The low level write to xPSR solved the problem only if xPSR cached copy was not marked dirty. Later commit 49bd64347a21f5e12b33c256171b3035126d1260 fixed T setting for all Cortex-M target algorithms. Since 49bd64 this part of code is useless as xPSR target_start_algorithm() sets always xPSR dirty so the effect of the low level write is eliminated (and proper setting of thumb bit is ensured in target_start_algorithm()) Change-Id: I68aea5e921fbc6203f2fe91a45f10d22869327de Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5875 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/psoc6.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 19d483bab..931404e3e 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -151,12 +151,6 @@ static int sromalgo_prepare(struct target *target) if (hr != ERROR_OK) return hr; - /* Restore THUMB bit in xPSR register */ - const struct armv7m_common *cm = target_to_armv7m(target); - hr = cm->store_core_reg_u32(target, ARMV7M_REGSEL_xPSR, 0x01000000); - if (hr != ERROR_OK) - return hr; - /* Allocate Working Area for Stack and Flash algorithm */ hr = target_alloc_working_area(target, RAM_STACK_WA_SIZE, &g_stack_area); if (hr != ERROR_OK) From b1f488ec1ea4c8b5410026610c621f85b5ff17f3 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 22 Oct 2020 20:36:30 +0200 Subject: [PATCH 077/113] target/armv7m, cortex_m: fix misleading comments Change-Id: I4fea29f07f4d3b8b2578b538ef0eef5f1eea285f Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5876 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Antonio Borneo --- src/target/armv7m.c | 3 +-- src/target/cortex_m.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 13370b54b..f14ce0d88 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -493,8 +493,7 @@ int armv7m_start_algorithm(struct target *target, return ERROR_TARGET_NOT_HALTED; } - /* refresh core register cache - * Not needed if core register cache is always consistent with target process state */ + /* Store all non-debug execution registers to armv7m_algorithm_info context */ for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { armv7m_algorithm_info->context[i] = buf_get_u32( diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index fc72c0ed0..94cf82489 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -817,15 +817,19 @@ static int cortex_m_resume(struct target *target, int current, * in parallel with disabled interrupts can cause local faults * to not be taken. * - * REVISIT this clearly breaks non-debug execution, since the - * PRIMASK register state isn't saved/restored... workaround - * by never resuming app code after debug execution. + * This breaks non-debug (application) execution if not + * called from armv7m_start_algorithm() which saves registers. */ buf_set_u32(r->value, 0, 1, 1); r->dirty = true; r->valid = true; - /* Make sure we are in Thumb mode */ + /* Make sure we are in Thumb mode, set xPSR.T bit */ + /* armv7m_start_algorithm() initializes entire xPSR register. + * This duplicity handles the case when cortex_m_resume() + * is used with the debug_execution flag directly, + * not called through armv7m_start_algorithm(). + */ r = armv7m->arm.cpsr; buf_set_u32(r->value, 24, 1, 1); r->dirty = true; From 8f927d51643ceb6b3696772c5fabd5ba9f48fcd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Thomas?= Date: Tue, 29 Jan 2019 21:14:58 +0100 Subject: [PATCH 078/113] Add CMSIS-DAP v2 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change implements CMSIS-DAP v2 which works with raw USB bulk transfers. The old driver is now split into a generic CMSIS part and a HID backend, with a new raw USB backend for CMSIS-DAP v2. New commands: - cmsis_dap_backend (usb_bulk | hid | auto) - cmsis_dap_usb interface Change-Id: I4218477b12ccbfe19c9b332321cd21394bf44e30 Signed-off-by: Mickaël Thomas Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4831 Tested-by: jenkins --- configure.ac | 3 +- src/jtag/drivers/Makefile.am | 12 +- .../drivers/{cmsis_dap_usb.c => cmsis_dap.c} | 321 +++++++-------- src/jtag/drivers/cmsis_dap.h | 28 ++ src/jtag/drivers/cmsis_dap_usb_bulk.c | 373 ++++++++++++++++++ src/jtag/drivers/cmsis_dap_usb_hid.c | 208 ++++++++++ src/jtag/interfaces.c | 4 +- 7 files changed, 761 insertions(+), 188 deletions(-) rename src/jtag/drivers/{cmsis_dap_usb.c => cmsis_dap.c} (88%) create mode 100644 src/jtag/drivers/cmsis_dap.h create mode 100644 src/jtag/drivers/cmsis_dap_usb_bulk.c create mode 100644 src/jtag/drivers/cmsis_dap_usb_hid.c diff --git a/configure.ac b/configure.ac index 3e49213cc..9cb20ad89 100644 --- a/configure.ac +++ b/configure.ac @@ -119,6 +119,7 @@ m4_define([USB1_ADAPTERS], [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]], [[xds110], [TI XDS110 Debug Probe], [XDS110]], + [[cmsis_dap_v2], [CMSIS-DAP v2 Compliant Debugger], [CMSIS_DAP_USB]], [[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], [[aice], [Andes JTAG Programmer], [AICE]]]) @@ -129,7 +130,7 @@ m4_define([USB0_ADAPTERS], [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]]]) m4_define([HIDAPI_ADAPTERS], - [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP]], + [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], [[nulink], [Nu-Link Programmer], [HLADAPTER_NULINK]]]) m4_define([HIDAPI_USB1_ADAPTERS], diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 1a5ab4a2d..f7a54b003 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -170,8 +170,15 @@ endif if OPENJTAG DRIVERFILES += %D%/openjtag.c endif -if CMSIS_DAP -DRIVERFILES += %D%/cmsis_dap_usb.c +if CMSIS_DAP_HID +DRIVERFILES += %D%/cmsis_dap_usb_hid.c +DRIVERFILES += %D%/cmsis_dap.c +endif +if CMSIS_DAP_USB +DRIVERFILES += %D%/cmsis_dap_usb_bulk.c +if !CMSIS_DAP_HID +DRIVERFILES += %D%/cmsis_dap.c +endif endif if IMX_GPIO DRIVERFILES += %D%/imx_gpio.c @@ -189,6 +196,7 @@ DRIVERHEADERS = \ %D%/jtag_usb_common.h \ %D%/libftdi_helper.h \ %D%/libusb_helper.h \ + %D%/cmsis_dap.h \ %D%/minidriver_imp.h \ %D%/mpsse.h \ %D%/rlink.h \ diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap.c similarity index 88% rename from src/jtag/drivers/cmsis_dap_usb.c rename to src/jtag/drivers/cmsis_dap.c index 6d55392d5..8ddb54179 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1,4 +1,7 @@ /*************************************************************************** + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * * Copyright (C) 2016 by Maksym Hilliaka * * oter@frozen-team.com * * * @@ -38,12 +41,26 @@ #include #include -#include +#include "cmsis_dap.h" -/* - * See CMSIS-DAP documentation: - * Version 0.01 - Beta. - */ +#if BUILD_CMSIS_DAP_USB == 1 +const struct cmsis_dap_backend cmsis_dap_usb_backend; +extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; +#endif + +#if BUILD_CMSIS_DAP_HID == 1 +const struct cmsis_dap_backend cmsis_dap_hid_backend; +#endif + +static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { +#if BUILD_CMSIS_DAP_USB == 1 + &cmsis_dap_usb_backend, +#endif + +#if BUILD_CMSIS_DAP_HID == 1 + &cmsis_dap_hid_backend, +#endif +}; /* USB Config */ @@ -52,6 +69,7 @@ * PID 0xf001: LPC-Link-II CMSIS_DAP * PID 0xf002: OPEN-SDA CMSIS_DAP (Freedom Board) * PID 0x2722: Keil ULINK2 CMSIS-DAP + * PID 0x2750: Keil ULINKplus CMSIS-DAP * * VID 0x0d28: mbed Software * PID 0x0204: MBED CMSIS-DAP @@ -61,10 +79,10 @@ /* vid = pid = 0 marks the end of the list */ static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; -static wchar_t *cmsis_dap_serial; +static char *cmsis_dap_serial; +static int cmsis_dap_backend = -1; static bool swd_mode; -#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */ #define USB_TIMEOUT 1000 /* CMSIS-DAP General Commands */ @@ -163,14 +181,6 @@ static const char * const info_caps_str[] = { /* max clock speed (kHz) */ #define DAP_MAX_CLOCK 5000 -struct cmsis_dap { - hid_device *dev_handle; - uint16_t packet_size; - int packet_count; - uint8_t *packet_buffer; - uint8_t caps; - uint8_t mode; -}; struct pending_transfer_result { uint8_t cmd; @@ -223,91 +233,10 @@ static uint8_t output_pins = SWJ_PIN_SRST | SWJ_PIN_TRST; static struct cmsis_dap *cmsis_dap_handle; -static int cmsis_dap_usb_open(void) + +static int cmsis_dap_open(void) { - hid_device *dev = NULL; - int i; - struct hid_device_info *devs, *cur_dev; - unsigned short target_vid, target_pid; - bool found = false; - - target_vid = 0; - target_pid = 0; - - if (hid_init() != 0) { - LOG_ERROR("unable to open HIDAPI"); - return ERROR_FAIL; - } - - /* - * The CMSIS-DAP specification stipulates: - * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the - * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." - */ - devs = hid_enumerate(0x0, 0x0); - cur_dev = devs; - while (NULL != cur_dev) { - if (0 == cmsis_dap_vid[0]) { - if (NULL == cur_dev->product_string) { - LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", - cur_dev->vendor_id, cur_dev->product_id); - } else { - if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { - /* if the user hasn't specified VID:PID *and* - * product string contains "CMSIS-DAP", pick it - */ - found = true; - } - } - } else { - /* otherwise, exhaustively compare against all VID:PID in list */ - for (i = 0; cmsis_dap_vid[i] || cmsis_dap_pid[i]; i++) { - if ((cmsis_dap_vid[i] == cur_dev->vendor_id) && (cmsis_dap_pid[i] == cur_dev->product_id)) - found = true; - } - - if (cmsis_dap_vid[i] || cmsis_dap_pid[i]) - found = true; - } - - /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */ - if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0) - found = false; - - if (found) { - /* we have found an adapter, so exit further checks */ - /* check serial number matches if given */ - if (cmsis_dap_serial != NULL) { - if ((cur_dev->serial_number != NULL) && wcscmp(cmsis_dap_serial, cur_dev->serial_number) == 0) { - break; - } - } else - break; - - found = false; - } - - cur_dev = cur_dev->next; - } - - if (NULL != cur_dev) { - target_vid = cur_dev->vendor_id; - target_pid = cur_dev->product_id; - } - - if (target_vid == 0 && target_pid == 0) { - LOG_ERROR("unable to find CMSIS-DAP device"); - hid_free_enumeration(devs); - return ERROR_FAIL; - } - - dev = hid_open_path(cur_dev->path); - hid_free_enumeration(devs); - - if (dev == NULL) { - LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); - return ERROR_FAIL; - } + const struct cmsis_dap_backend *backend = NULL; struct cmsis_dap *dap = malloc(sizeof(struct cmsis_dap)); if (dap == NULL) { @@ -315,42 +244,55 @@ static int cmsis_dap_usb_open(void) return ERROR_FAIL; } - dap->dev_handle = dev; dap->caps = 0; dap->mode = 0; + dap->packet_size = 0; /* initialized by backend */ - cmsis_dap_handle = dap; + if (cmsis_dap_backend >= 0) { + /* Use forced backend */ + backend = cmsis_dap_backends[cmsis_dap_backend]; + if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) != ERROR_OK) + backend = NULL; + } else { + /* Try all backends */ + for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { + backend = cmsis_dap_backends[i]; + if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) == ERROR_OK) + break; + else + backend = NULL; + } + } - /* allocate default packet buffer, may be changed later. - * currently with HIDAPI we have no way of getting the output report length - * without this info we cannot communicate with the adapter. - * For the moment we ahve to hard code the packet size */ - - int packet_size = PACKET_SIZE; - - /* atmel cmsis-dap uses 512 byte reports */ - /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained - * board */ - /* TODO: HID report descriptor should be parsed instead of - * hardcoding a match by VID */ - if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175) - packet_size = 512 + 1; - - cmsis_dap_handle->packet_buffer = malloc(packet_size); - cmsis_dap_handle->packet_size = packet_size; - - if (cmsis_dap_handle->packet_buffer == NULL) { - LOG_ERROR("unable to allocate memory"); + if (backend == NULL) { + LOG_ERROR("unable to find a matching CMSIS-DAP device"); + free(dap); return ERROR_FAIL; } + assert(dap->packet_size > 0); + + dap->backend = backend; + dap->packet_buffer = malloc(dap->packet_size); + + if (dap->packet_buffer == NULL) { + LOG_ERROR("unable to allocate memory"); + dap->backend->close(dap); + free(dap); + return ERROR_FAIL; + } + + cmsis_dap_handle = dap; + return ERROR_OK; } -static void cmsis_dap_usb_close(struct cmsis_dap *dap) +static void cmsis_dap_close(struct cmsis_dap *dap) { - hid_close(dap->dev_handle); - hid_exit(); + if (dap->backend) { + dap->backend->close(dap); + dap->backend = NULL; + } free(cmsis_dap_handle->packet_buffer); free(cmsis_dap_handle); @@ -364,47 +306,27 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap) } } -static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen) -{ -#ifdef CMSIS_DAP_JTAG_DEBUG - LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]); -#endif - /* Pad the rest of the TX buffer with 0's */ - memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen); - - /* write data to device */ - int retval = hid_write(dap->dev_handle, dap->packet_buffer, dap->packet_size); - if (retval == -1) { - LOG_ERROR("error writing data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } - - return ERROR_OK; -} - /* Send a message and receive the reply */ -static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen) +static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) { if (pending_fifo_block_count) { LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count); while (pending_fifo_block_count) { - hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10); + dap->backend->read(dap, 10); pending_fifo_block_count--; } pending_fifo_put_idx = 0; pending_fifo_get_idx = 0; } - int retval = cmsis_dap_usb_write(dap, txlen); - if (retval != ERROR_OK) + int retval = dap->backend->write(dap, txlen, USB_TIMEOUT); + if (retval < 0) return retval; /* get reply */ - retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT); - if (retval == -1 || retval == 0) { - LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); - return ERROR_FAIL; - } + retval = dap->backend->read(dap, USB_TIMEOUT); + if (retval < 0) + return retval; return ERROR_OK; } @@ -422,7 +344,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Pins(uint8_t pins, uint8_t mask, uint32_t delay buffer[5] = (delay >> 8) & 0xff; buffer[6] = (delay >> 16) & 0xff; buffer[7] = (delay >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 8); + retval = cmsis_dap_xfer(cmsis_dap_handle, 8); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_PINS failed."); @@ -448,7 +370,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Clock(uint32_t swj_clock) buffer[3] = (swj_clock >> 8) & 0xff; buffer[4] = (swj_clock >> 16) & 0xff; buffer[5] = (swj_clock >> 24) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 6); + retval = cmsis_dap_xfer(cmsis_dap_handle, 6); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_SWJ_CLOCK failed."); @@ -477,7 +399,7 @@ static int cmsis_dap_cmd_DAP_SWJ_Sequence(uint8_t s_len, const uint8_t *sequence buffer[2] = s_len; bit_copy(&buffer[3], 0, sequence, 0, s_len); - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3); + retval = cmsis_dap_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3); if (retval != ERROR_OK || buffer[1] != DAP_OK) return ERROR_FAIL; @@ -493,7 +415,7 @@ static int cmsis_dap_cmd_DAP_Info(uint8_t info, uint8_t **data) buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_INFO; buffer[2] = info; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); + retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_INFO failed."); @@ -514,7 +436,7 @@ static int cmsis_dap_cmd_DAP_LED(uint8_t led, uint8_t state) buffer[1] = CMD_DAP_LED; buffer[2] = led; buffer[3] = state; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); + retval = cmsis_dap_xfer(cmsis_dap_handle, 4); if (retval != ERROR_OK || buffer[1] != 0x00) { LOG_ERROR("CMSIS-DAP command CMD_LED failed."); @@ -532,7 +454,7 @@ static int cmsis_dap_cmd_DAP_Connect(uint8_t mode) buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_CONNECT; buffer[2] = mode; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); + retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command CMD_CONNECT failed."); @@ -554,7 +476,7 @@ static int cmsis_dap_cmd_DAP_Disconnect(void) buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_DISCONNECT; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 2); + retval = cmsis_dap_xfer(cmsis_dap_handle, 2); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DISCONNECT failed."); @@ -576,7 +498,7 @@ static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, buffer[4] = (retry_count >> 8) & 0xff; buffer[5] = match_retry & 0xff; buffer[6] = (match_retry >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7); + retval = cmsis_dap_xfer(cmsis_dap_handle, 7); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_TFER_Configure failed."); @@ -594,7 +516,7 @@ static int cmsis_dap_cmd_DAP_SWD_Configure(uint8_t cfg) buffer[0] = 0; /* report number */ buffer[1] = CMD_DAP_SWD_CONFIGURE; buffer[2] = cfg; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 3); + retval = cmsis_dap_xfer(cmsis_dap_handle, 3); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_SWD_Configure failed."); @@ -614,7 +536,7 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us) buffer[1] = CMD_DAP_DELAY; buffer[2] = delay_us & 0xff; buffer[3] = (delay_us >> 8) & 0xff; - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 4); + retval = cmsis_dap_xfer(cmsis_dap_handle, 4); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_Delay failed."); @@ -684,9 +606,14 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) } } - queued_retval = cmsis_dap_usb_write(dap, idx); - if (queued_retval != ERROR_OK) + int retval = dap->backend->write(dap, idx, USB_TIMEOUT); + + if (retval < 0) { + queued_retval = retval; goto skip; + } else { + queued_retval = ERROR_OK; + } pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count; pending_fifo_block_count++; @@ -708,12 +635,12 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms) LOG_ERROR("no pending write"); /* get reply */ - int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); - if (retval == 0 && timeout_ms < USB_TIMEOUT) + int retval = dap->backend->read(dap, timeout_ms); + if (retval == ERROR_TIMEOUT_REACHED && timeout_ms < USB_TIMEOUT) return; - if (retval == -1 || retval == 0) { - LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle)); + if (retval <= 0) { + LOG_DEBUG("error reading data"); queued_retval = ERROR_FAIL; goto skip; } @@ -969,7 +896,7 @@ static int cmsis_dap_init(void) int retval; uint8_t *data; - retval = cmsis_dap_usb_open(); + retval = cmsis_dap_open(); if (retval != ERROR_OK) return retval; @@ -1048,7 +975,7 @@ static int cmsis_dap_init(void) LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt); } - LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count); + LOG_DEBUG("Allocating FIFO for %d pending packets", cmsis_dap_handle->packet_count); for (int i = 0; i < cmsis_dap_handle->packet_count; i++) { pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result)); if (!pending_fifo[i].transfers) { @@ -1120,7 +1047,7 @@ static int cmsis_dap_quit(void) cmsis_dap_cmd_DAP_LED(LED_ID_RUN, LED_OFF); cmsis_dap_cmd_DAP_LED(LED_ID_CONNECT, LED_OFF); - cmsis_dap_usb_close(cmsis_dap_handle); + cmsis_dap_close(cmsis_dap_handle); return ERROR_OK; } @@ -1261,7 +1188,7 @@ static void cmsis_dap_flush(void) #endif /* send command to USB device */ - int retval = cmsis_dap_usb_xfer(cmsis_dap_handle, queued_seq_buf_end + 3); + int retval = cmsis_dap_xfer(cmsis_dap_handle, queued_seq_buf_end + 3); if (retval != ERROR_OK || buffer[1] != DAP_OK) { LOG_ERROR("CMSIS-DAP command CMD_DAP_JTAG_SEQ failed."); exit(-1); @@ -1668,7 +1595,7 @@ COMMAND_HANDLER(cmsis_dap_handle_cmd_command) for (i = 0; i < CMD_ARGC; i++) buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16); - retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1); + retval = cmsis_dap_xfer(cmsis_dap_handle, CMD_ARGC + 1); if (retval != ERROR_OK) { LOG_ERROR("CMSIS-DAP command failed."); @@ -1712,21 +1639,32 @@ COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command) } COMMAND_HANDLER(cmsis_dap_handle_serial_command) +{ + if (CMD_ARGC == 1) + cmsis_dap_serial = strdup(CMD_ARGV[0]); + else + LOG_ERROR("expected exactly one argument to cmsis_dap_serial "); + + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_backend_command) { if (CMD_ARGC == 1) { - size_t len = mbstowcs(NULL, CMD_ARGV[0], 0); - cmsis_dap_serial = calloc(len + 1, sizeof(wchar_t)); - if (cmsis_dap_serial == NULL) { - LOG_ERROR("unable to allocate memory"); - return ERROR_OK; - } - if (mbstowcs(cmsis_dap_serial, CMD_ARGV[0], len + 1) == (size_t)-1) { - free(cmsis_dap_serial); - cmsis_dap_serial = NULL; - LOG_ERROR("unable to convert serial"); + if (strcmp(CMD_ARGV[0], "auto") == 0) { + cmsis_dap_backend = -1; /* autoselect */ + } else { + for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) { + if (strcasecmp(cmsis_dap_backends[i]->name, CMD_ARGV[0]) == 0) { + cmsis_dap_backend = i; + return ERROR_OK; + } + } + + LOG_ERROR("invalid backend argument to cmsis_dap_backend "); } } else { - LOG_ERROR("expected exactly one argument to cmsis_dap_serial "); + LOG_ERROR("expected exactly one argument to cmsis_dap_backend "); } return ERROR_OK; @@ -1750,6 +1688,7 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { COMMAND_REGISTRATION_DONE }; + static const struct command_registration cmsis_dap_command_handlers[] = { { .name = "cmsis-dap", @@ -1772,6 +1711,22 @@ static const struct command_registration cmsis_dap_command_handlers[] = { .help = "set the serial number of the adapter", .usage = "serial_string", }, + { + .name = "cmsis_dap_backend", + .handler = &cmsis_dap_handle_backend_command, + .mode = COMMAND_CONFIG, + .help = "set the communication backend to use (USB bulk or HID).", + .usage = "(auto | usb_bulk | hid)", + }, +#if BUILD_CMSIS_DAP_USB + { + .name = "cmsis_dap_usb", + .chain = cmsis_dap_usb_subcommand_handlers, + .mode = COMMAND_ANY, + .help = "USB bulk backend-specific commands", + .usage = "", + }, +#endif COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h new file mode 100644 index 000000000..8cbb8dd07 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap.h @@ -0,0 +1,28 @@ +#ifndef OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H +#define OPENOCD_JTAG_DRIVERS_CMSIS_DAP_H + +#include + +struct cmsis_dap_backend; +struct cmsis_dap_backend_data; +struct command_registration; + +struct cmsis_dap { + struct cmsis_dap_backend_data *bdata; + const struct cmsis_dap_backend *backend; + uint16_t packet_size; + int packet_count; + uint8_t *packet_buffer; + uint8_t caps; + uint8_t mode; +}; + +struct cmsis_dap_backend { + const char *name; + int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial); + void (*close)(struct cmsis_dap *dap); + int (*read)(struct cmsis_dap *dap, int timeout_ms); + int (*write)(struct cmsis_dap *dap, int len, int timeout_ms); +}; + +#endif diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c new file mode 100644 index 000000000..b82e3dae5 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -0,0 +1,373 @@ +/*************************************************************************** + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * + * Copyright (C) 2016 by Maksym Hilliaka * + * oter@frozen-team.com * + * * + * Copyright (C) 2016 by Phillip Pearson * + * pp@myelin.co.nz * + * * + * Copyright (C) 2014 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2013 by mike brown * + * mike@theshedworks.org.uk * + * * + * Copyright (C) 2013 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "cmsis_dap.h" + +struct cmsis_dap_backend_data { + libusb_context *usb_ctx; + libusb_device_handle *dev_handle; + unsigned int ep_out; + unsigned int ep_in; + int interface; +}; + +static int cmsis_dap_usb_interface = -1; + +static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial) +{ + int err; + libusb_context *ctx; + libusb_device **device_list; + + err = libusb_init(&ctx); + if (err) { + LOG_ERROR("libusb initialization failed: %s", libusb_strerror(err)); + return ERROR_FAIL; + } + + int num_devices = libusb_get_device_list(ctx, &device_list); + if (num_devices < 0) { + LOG_ERROR("could not enumerate USB devices: %s", libusb_strerror(num_devices)); + libusb_exit(ctx); + return ERROR_FAIL; + } + + for (int i = 0; i < num_devices; i++) { + libusb_device *dev = device_list[i]; + struct libusb_device_descriptor dev_desc; + + err = libusb_get_device_descriptor(dev, &dev_desc); + if (err) { + LOG_ERROR("could not get device descriptor for device %d: %s", i, libusb_strerror(err)); + continue; + } + + /* Match VID/PID */ + + bool id_match = true; /* match if we don't enter the loop (no filter) */ + for (int id = 0; vids[id] || pids[id]; id++) { + id_match = !vids[id] || dev_desc.idVendor == vids[id]; + id_match &= !pids[id] || dev_desc.idProduct == pids[id]; + + if (id_match) + break; + } + + if (!id_match) + continue; + + /* Don't continue if we asked for a serial number and the device doesn't have one */ + if (dev_desc.iSerialNumber == 0 && serial && serial[0]) + continue; + + libusb_device_handle *dev_handle = NULL; + err = libusb_open(dev, &dev_handle); + if (err) { + /* It's to be expected that most USB devices can't be opened + * so only report an error if it was explicitly selected + */ + if (vids[0] || pids[0]) { + LOG_ERROR("could not open device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } else { + LOG_DEBUG("could not open device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } + continue; + } + + /* Match serial number */ + + bool serial_match = (serial == NULL); + char dev_serial[256] = {0}; + if (dev_desc.iSerialNumber > 0) { + err = libusb_get_string_descriptor_ascii( + dev_handle, dev_desc.iSerialNumber, + (uint8_t *)dev_serial, sizeof(dev_serial)); + + if (err < 0) { + LOG_ERROR("could not read serial number for device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) { + serial_match = true; + } + } + + if (!serial_match) { + libusb_close(dev_handle); + continue; + } + + /* Find the CMSIS-DAP string in product string */ + + bool cmsis_dap_found = false; + char product_string[256] = {0}; + if (dev_desc.iProduct > 0) { + err = libusb_get_string_descriptor_ascii( + dev_handle, dev_desc.iProduct, + (uint8_t *)product_string, sizeof(product_string)); + if (err < 0) { + LOG_ERROR("could not read product string for device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + } else if (strstr(product_string, "CMSIS-DAP")) { + LOG_DEBUG("CMSIS-DAP found in product string"); + cmsis_dap_found = true; + } + } + + /* Find the CMSIS-DAP interface */ + + for (int config = 0; config < dev_desc.bNumConfigurations; config++) { + struct libusb_config_descriptor *config_desc; + err = libusb_get_config_descriptor(dev, config, &config_desc); + if (err) { + LOG_ERROR("could not get configuration descriptor %d for device 0x%04x:0x%04x: %s", + config, dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + continue; + } + + int config_num = config_desc->bConfigurationValue; + + for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) { + const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; + int interface_num = intf_desc->bInterfaceNumber; + + /* Skip this interface if another one was requested explicitly */ + if (cmsis_dap_usb_interface != -1 && cmsis_dap_usb_interface != interface_num) + continue; + + /* CMSIS-DAP v2 spec says: + * + * CMSIS-DAP with default V2 configuration uses WinUSB and is therefore faster. + * Optionally support for streaming SWO trace is provided via an additional USB endpoint. + * + * The WinUSB configuration requires custom class support with the interface setting + * Class Code: 0xFF (Vendor specific) + * Subclass: 0x00 + * Protocol code: 0x00 + * + * Depending on the configuration it uses the following USB endpoints which should be configured + * in the interface descriptor in this order: + * - Endpoint 1: Bulk Out – used for commands received from host PC. + * - Endpoint 2: Bulk In – used for responses send to host PC. + * - Endpoint 3: Bulk In (optional) – used for streaming SWO trace (if enabled with SWO_STREAM). + */ + + if (intf_desc->bNumEndpoints < 2) + continue; + + if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) + continue; + + if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || + (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) + continue; + + /* Bypass the following checks if this interface was explicitly requested. */ + if (cmsis_dap_usb_interface == -1) { + if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || + intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) + continue; + + /* Search for "CMSIS-DAP" in the interface string */ + if (cmsis_dap_usb_interface != -1 && !cmsis_dap_found) { + if (intf_desc->iInterface == 0) + continue; + + char interface_str[256] = {0}; + + err = libusb_get_string_descriptor_ascii( + dev_handle, intf_desc->iInterface, + (uint8_t *)interface_str, sizeof(interface_str)); + if (err < 0) { + LOG_ERROR("could not read interface string for device 0x%04x:0x%04x: %s", + dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + continue; + } else if (!strstr(interface_str, "CMSIS-DAP")) { + continue; + } else { + LOG_DEBUG("CMSIS-DAP found in interface string"); + } + } + } + + int packet_size = intf_desc->endpoint[0].wMaxPacketSize; + int ep_out = intf_desc->endpoint[0].bEndpointAddress; + int ep_in = intf_desc->endpoint[1].bEndpointAddress; + + /* That's the one! */ + libusb_free_config_descriptor(config_desc); + libusb_free_device_list(device_list, true); + + LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s", + dev_desc.idVendor, dev_desc.idProduct, dev_serial); + + int current_config; + err = libusb_get_configuration(dev_handle, ¤t_config); + if (err) { + LOG_ERROR("could not find current configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + if (config_num != current_config) { + err = libusb_set_configuration(dev_handle, config_num); + if (err) { + LOG_ERROR("could not set configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + } + + err = libusb_claim_interface(dev_handle, interface_num); + if (err) + LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (dap->bdata == NULL) { + LOG_ERROR("unable to allocate memory"); + libusb_release_interface(dev_handle, interface_num); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */ + dap->bdata->usb_ctx = ctx; + dap->bdata->dev_handle = dev_handle; + dap->bdata->ep_out = ep_out; + dap->bdata->ep_in = ep_in; + dap->bdata->interface = interface_num; + return ERROR_OK; + } + + libusb_free_config_descriptor(config_desc); + } + + libusb_close(dev_handle); + } + + libusb_free_device_list(device_list, true); + + libusb_exit(ctx); + return ERROR_FAIL; +} + +static void cmsis_dap_usb_close(struct cmsis_dap *dap) +{ + libusb_release_interface(dap->bdata->dev_handle, dap->bdata->interface); + libusb_close(dap->bdata->dev_handle); + libusb_exit(dap->bdata->usb_ctx); + free(dap->bdata); + dap->bdata = NULL; +} + +static int cmsis_dap_usb_read(struct cmsis_dap *dap, int timeout_ms) +{ + int transferred = 0; + int err; + + err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_in, + dap->packet_buffer, dap->packet_size, &transferred, timeout_ms); + if (err) { + if (err == LIBUSB_ERROR_TIMEOUT) { + return ERROR_TIMEOUT_REACHED; + } else { + LOG_ERROR("error reading data: %s", libusb_strerror(err)); + return ERROR_FAIL; + } + } + + memset(&dap->packet_buffer[transferred], 0, dap->packet_size - transferred); + + return transferred; +} + +static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen, int timeout_ms) +{ + int transferred = 0; + int err; + + /* skip the first byte that is only used by the HID backend */ + err = libusb_bulk_transfer(dap->bdata->dev_handle, dap->bdata->ep_out, + dap->packet_buffer + 1, txlen - 1, &transferred, timeout_ms); + if (err) { + if (err == LIBUSB_ERROR_TIMEOUT) { + return ERROR_TIMEOUT_REACHED; + } else { + LOG_ERROR("error writing data: %s", libusb_strerror(err)); + return ERROR_FAIL; + } + } + + return transferred; +} + +COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command) +{ + if (CMD_ARGC == 1) + cmsis_dap_usb_interface = strtoul(CMD_ARGV[0], NULL, 10); + else + LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface "); + + return ERROR_OK; +} + +const struct command_registration cmsis_dap_usb_subcommand_handlers[] = { + { + .name = "interface", + .handler = &cmsis_dap_handle_usb_interface_command, + .mode = COMMAND_CONFIG, + .help = "set the USB interface number to use (for USB bulk backend only)", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct cmsis_dap_backend cmsis_dap_usb_backend = { + .name = "usb_bulk", + .open = cmsis_dap_usb_open, + .close = cmsis_dap_usb_close, + .read = cmsis_dap_usb_read, + .write = cmsis_dap_usb_write, +}; diff --git a/src/jtag/drivers/cmsis_dap_usb_hid.c b/src/jtag/drivers/cmsis_dap_usb_hid.c new file mode 100644 index 000000000..681aef171 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_usb_hid.c @@ -0,0 +1,208 @@ +/*************************************************************************** + * Copyright (C) 2018 by Mickaël Thomas * + * mickael9@gmail.com * + * * + * Copyright (C) 2016 by Maksym Hilliaka * + * oter@frozen-team.com * + * * + * Copyright (C) 2016 by Phillip Pearson * + * pp@myelin.co.nz * + * * + * Copyright (C) 2014 by Paul Fertser * + * fercerpav@gmail.com * + * * + * Copyright (C) 2013 by mike brown * + * mike@theshedworks.org.uk * + * * + * Copyright (C) 2013 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "cmsis_dap.h" + +#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */ + +struct cmsis_dap_backend_data { + hid_device *dev_handle; +}; + +static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial) +{ + hid_device *dev = NULL; + int i; + struct hid_device_info *devs, *cur_dev; + unsigned short target_vid, target_pid; + + target_vid = 0; + target_pid = 0; + + if (hid_init() != 0) { + LOG_ERROR("unable to open HIDAPI"); + return ERROR_FAIL; + } + + /* + * The CMSIS-DAP specification stipulates: + * "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the + * debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer." + */ + devs = hid_enumerate(0x0, 0x0); + cur_dev = devs; + while (NULL != cur_dev) { + bool found = false; + + if (0 == vids[0]) { + if (NULL == cur_dev->product_string) { + LOG_DEBUG("Cannot read product string of device 0x%x:0x%x", + cur_dev->vendor_id, cur_dev->product_id); + } else if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) { + /* if the user hasn't specified VID:PID *and* + * product string contains "CMSIS-DAP", pick it + */ + found = true; + } + } else { + /* otherwise, exhaustively compare against all VID:PID in list */ + for (i = 0; vids[i] || pids[i]; i++) { + if ((vids[i] == cur_dev->vendor_id) && (pids[i] == cur_dev->product_id)) + found = true; + } + } + + /* LPC-LINK2 has cmsis-dap on interface 0 and other HID functions on other interfaces */ + if (cur_dev->vendor_id == 0x1fc9 && cur_dev->product_id == 0x0090 && cur_dev->interface_number != 0) + found = false; + + if (found) { + /* check serial number matches if given */ + if (serial == NULL) + break; + + if (cur_dev->serial_number != NULL) { + size_t len = (strlen(serial) + 1) * sizeof(wchar_t); + wchar_t *wserial = malloc(len); + mbstowcs(wserial, serial, len); + + if (wcscmp(wserial, cur_dev->serial_number) == 0) { + free(wserial); + break; + } else { + free(wserial); + wserial = NULL; + } + } + } + + cur_dev = cur_dev->next; + } + + if (NULL != cur_dev) { + target_vid = cur_dev->vendor_id; + target_pid = cur_dev->product_id; + } + + if (target_vid == 0 && target_pid == 0) { + hid_free_enumeration(devs); + return ERROR_FAIL; + } + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (dap->bdata == NULL) { + LOG_ERROR("unable to allocate memory"); + return ERROR_FAIL; + } + + dev = hid_open_path(cur_dev->path); + hid_free_enumeration(devs); + + if (dev == NULL) { + LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid); + return ERROR_FAIL; + } + + /* allocate default packet buffer, may be changed later. + * currently with HIDAPI we have no way of getting the output report length + * without this info we cannot communicate with the adapter. + * For the moment we have to hard code the packet size */ + + dap->packet_size = PACKET_SIZE; + + /* atmel cmsis-dap uses 512 byte reports */ + /* except when it doesn't e.g. with mEDBG on SAMD10 Xplained + * board */ + /* TODO: HID report descriptor should be parsed instead of + * hardcoding a match by VID */ + if (target_vid == 0x03eb && target_pid != 0x2145 && target_pid != 0x2175) + dap->packet_size = 512 + 1; + + dap->bdata->dev_handle = dev; + + return ERROR_OK; +} + +static void cmsis_dap_hid_close(struct cmsis_dap *dap) +{ + hid_close(dap->bdata->dev_handle); + hid_exit(); + free(dap->bdata); + dap->bdata = NULL; +} + +static int cmsis_dap_hid_read(struct cmsis_dap *dap, int timeout_ms) +{ + int retval = hid_read_timeout(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms); + + if (retval == 0) { + return ERROR_TIMEOUT_REACHED; + } else if (retval == -1) { + LOG_ERROR("error reading data: %ls", hid_error(dap->bdata->dev_handle)); + return ERROR_FAIL; + } + + return retval; +} + +static int cmsis_dap_hid_write(struct cmsis_dap *dap, int txlen, int timeout_ms) +{ + (void) timeout_ms; + + /* Pad the rest of the TX buffer with 0's */ + memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen); + + /* write data to device */ + int retval = hid_write(dap->bdata->dev_handle, dap->packet_buffer, dap->packet_size); + if (retval == -1) { + LOG_ERROR("error writing data: %ls", hid_error(dap->bdata->dev_handle)); + return ERROR_FAIL; + } + + return retval; +} + +const struct cmsis_dap_backend cmsis_dap_hid_backend = { + .name = "hid", + .open = cmsis_dap_hid_open, + .close = cmsis_dap_hid_close, + .read = cmsis_dap_hid_read, + .write = cmsis_dap_hid_write, +}; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 2fa53be2b..061a78f9c 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -134,7 +134,7 @@ extern struct adapter_driver aice_adapter_driver; #if BUILD_BCM2835GPIO == 1 extern struct adapter_driver bcm2835gpio_adapter_driver; #endif -#if BUILD_CMSIS_DAP == 1 +#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 extern struct adapter_driver cmsis_dap_adapter_driver; #endif #if BUILD_KITPROG == 1 @@ -254,7 +254,7 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_BCM2835GPIO == 1 &bcm2835gpio_adapter_driver, #endif -#if BUILD_CMSIS_DAP == 1 +#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 &cmsis_dap_adapter_driver, #endif #if BUILD_KITPROG == 1 From e6770f1ab6b9a34dbe90d3fa6ae4093914a0d707 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 30 Jul 2020 10:26:34 +0200 Subject: [PATCH 079/113] jtag/drivers/cmsis_dap: fix usb bulk connection logic http://openocd.zylin.com/4831 has following problems in selecting USB device/interface to connect: - attempts connection to any device with user class and 2 bulk endpoints - regardless of cmsis_dap_vid_pid or cmsis_dap_serial setting connects to the first suitable device Distinguish between real match and no filtering cases and use that info appropriately. Add debug messages to show why the interface is refused. Move CMSIS-DAP interface string detection before checking of class/endpoints to give more understandable debug log in the case the device is refused. Keep track of reliable matches in both device and interface enumeration. First search for the interface with CMSIS-DAP in the interface string. If it fails, chose the first suitable interface. Change-Id: Ia1aacd5631a9f5c5db580bfb5745ceb6240d61ad Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5789 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/jtag/drivers/cmsis_dap_usb_bulk.c | 249 +++++++++++++++++--------- 1 file changed, 165 insertions(+), 84 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index b82e3dae5..0134c0376 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -81,7 +81,8 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p /* Match VID/PID */ - bool id_match = true; /* match if we don't enter the loop (no filter) */ + bool id_match = false; + bool id_filter = vids[0] || pids[0]; for (int id = 0; vids[id] || pids[id]; id++) { id_match = !vids[id] || dev_desc.idVendor == vids[id]; id_match &= !pids[id] || dev_desc.idProduct == pids[id]; @@ -90,7 +91,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p break; } - if (!id_match) + if (id_filter && !id_match) continue; /* Don't continue if we asked for a serial number and the device doesn't have one */ @@ -103,7 +104,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p /* It's to be expected that most USB devices can't be opened * so only report an error if it was explicitly selected */ - if (vids[0] || pids[0]) { + if (id_filter) { LOG_ERROR("could not open device 0x%04x:0x%04x: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else { @@ -115,7 +116,7 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p /* Match serial number */ - bool serial_match = (serial == NULL); + bool serial_match = false; char dev_serial[256] = {0}; if (dev_desc.iSerialNumber > 0) { err = libusb_get_string_descriptor_ascii( @@ -123,35 +124,44 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p (uint8_t *)dev_serial, sizeof(dev_serial)); if (err < 0) { - LOG_ERROR("could not read serial number for device 0x%04x:0x%04x: %s", - dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); + const char *msg = "could not read serial number for device 0x%04x:0x%04x: %s"; + if (serial) + LOG_WARNING(msg, dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); + else + LOG_DEBUG(msg, dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); } else if (serial && strncmp(dev_serial, serial, sizeof(dev_serial)) == 0) { serial_match = true; } } - if (!serial_match) { + if (serial && !serial_match) { libusb_close(dev_handle); continue; } /* Find the CMSIS-DAP string in product string */ - bool cmsis_dap_found = false; + bool cmsis_dap_in_product_str = false; char product_string[256] = {0}; if (dev_desc.iProduct > 0) { err = libusb_get_string_descriptor_ascii( dev_handle, dev_desc.iProduct, (uint8_t *)product_string, sizeof(product_string)); if (err < 0) { - LOG_ERROR("could not read product string for device 0x%04x:0x%04x: %s", + LOG_WARNING("could not read product string for device 0x%04x:0x%04x: %s", dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); } else if (strstr(product_string, "CMSIS-DAP")) { - LOG_DEBUG("CMSIS-DAP found in product string"); - cmsis_dap_found = true; + LOG_DEBUG("found product string of 0x%04x:0x%04x '%s'", + dev_desc.idVendor, dev_desc.idProduct, product_string); + cmsis_dap_in_product_str = true; } } + bool device_identified_reliably = cmsis_dap_in_product_str + || serial_match || id_match; + /* Find the CMSIS-DAP interface */ for (int config = 0; config < dev_desc.bNumConfigurations; config++) { @@ -163,7 +173,11 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p continue; } + LOG_DEBUG("enumerating interfaces of 0x%04x:0x%04x", + dev_desc.idVendor, dev_desc.idProduct); int config_num = config_desc->bConfigurationValue; + const struct libusb_interface_descriptor *intf_desc_candidate = NULL; + const struct libusb_interface_descriptor *intf_desc_found = NULL; for (int interface = 0; interface < config_desc->bNumInterfaces; interface++) { const struct libusb_interface_descriptor *intf_desc = &config_desc->interface[interface].altsetting[0]; @@ -190,98 +204,165 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p * - Endpoint 3: Bulk In (optional) – used for streaming SWO trace (if enabled with SWO_STREAM). */ - if (intf_desc->bNumEndpoints < 2) + /* Search for "CMSIS-DAP" in the interface string */ + bool cmsis_dap_in_interface_str = false; + if (intf_desc->iInterface != 0) { + + char interface_str[256] = {0}; + + err = libusb_get_string_descriptor_ascii( + dev_handle, intf_desc->iInterface, + (uint8_t *)interface_str, sizeof(interface_str)); + if (err < 0) { + LOG_DEBUG("could not read interface string %d for device 0x%04x:0x%04x: %s", + intf_desc->iInterface, + dev_desc.idVendor, dev_desc.idProduct, + libusb_strerror(err)); + } else if (strstr(interface_str, "CMSIS-DAP")) { + cmsis_dap_in_interface_str = true; + LOG_DEBUG("found interface %d string '%s'", + interface_num, interface_str); + } + } + + /* Bypass the following check if this interface was explicitly requested. */ + if (cmsis_dap_usb_interface == -1) { + if (!cmsis_dap_in_product_str && !cmsis_dap_in_interface_str) + continue; + } + + /* check endpoints */ + if (intf_desc->bNumEndpoints < 2) { + LOG_DEBUG("skipping interface %d, has only %d endpoints", + interface_num, intf_desc->bNumEndpoints); continue; + } if ((intf_desc->endpoint[0].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || - (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) + (intf_desc->endpoint[0].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_OUT) { + LOG_DEBUG("skipping interface %d, endpoint[0] is not bulk out", + interface_num); continue; + } if ((intf_desc->endpoint[1].bmAttributes & 3) != LIBUSB_TRANSFER_TYPE_BULK || - (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) + (intf_desc->endpoint[1].bEndpointAddress & 0x80) != LIBUSB_ENDPOINT_IN) { + LOG_DEBUG("skipping interface %d, endpoint[1] is not bulk in", + interface_num); continue; + } - /* Bypass the following checks if this interface was explicitly requested. */ - if (cmsis_dap_usb_interface == -1) { - if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || - intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) + /* We can rely on the interface is really CMSIS-DAP if + * - we've seen CMSIS-DAP in the interface string + * - config asked explicitly for an interface number + * - the device has only one interface + * The later two cases should be honored only if we know + * we are on the rigt device */ + bool intf_identified_reliably = cmsis_dap_in_interface_str + || (device_identified_reliably && + (cmsis_dap_usb_interface != -1 + || config_desc->bNumInterfaces == 1)); + + if (intf_desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC || + intf_desc->bInterfaceSubClass != 0 || intf_desc->bInterfaceProtocol != 0) { + /* If the interface is reliably identified + * then we need not insist on setting USB class, subclass and protocol + * exactly as the specification requires. + * At least KitProg3 uses class 0 contrary to the specification */ + if (intf_identified_reliably) { + LOG_WARNING("Using CMSIS-DAPv2 interface %d with wrong class %" PRId8 + " subclass %" PRId8 " or protocol %" PRId8, + interface_num, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); + } else { + LOG_DEBUG("skipping interface %d, class %" PRId8 + " subclass %" PRId8 " protocol %" PRId8, + interface_num, + intf_desc->bInterfaceClass, + intf_desc->bInterfaceSubClass, + intf_desc->bInterfaceProtocol); continue; - /* Search for "CMSIS-DAP" in the interface string */ - if (cmsis_dap_usb_interface != -1 && !cmsis_dap_found) { - if (intf_desc->iInterface == 0) - continue; - - char interface_str[256] = {0}; - - err = libusb_get_string_descriptor_ascii( - dev_handle, intf_desc->iInterface, - (uint8_t *)interface_str, sizeof(interface_str)); - if (err < 0) { - LOG_ERROR("could not read interface string for device 0x%04x:0x%04x: %s", - dev_desc.idVendor, dev_desc.idProduct, libusb_strerror(err)); - continue; - } else if (!strstr(interface_str, "CMSIS-DAP")) { - continue; - } else { - LOG_DEBUG("CMSIS-DAP found in interface string"); - } } } - int packet_size = intf_desc->endpoint[0].wMaxPacketSize; - int ep_out = intf_desc->endpoint[0].bEndpointAddress; - int ep_in = intf_desc->endpoint[1].bEndpointAddress; - - /* That's the one! */ - libusb_free_config_descriptor(config_desc); - libusb_free_device_list(device_list, true); - - LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s", - dev_desc.idVendor, dev_desc.idProduct, dev_serial); - - int current_config; - err = libusb_get_configuration(dev_handle, ¤t_config); - if (err) { - LOG_ERROR("could not find current configuration: %s", libusb_strerror(err)); - libusb_close(dev_handle); - libusb_exit(ctx); - return ERROR_FAIL; + if (intf_identified_reliably) { + /* That's the one! */ + intf_desc_found = intf_desc; + break; } - if (config_num != current_config) { - err = libusb_set_configuration(dev_handle, config_num); - if (err) { - LOG_ERROR("could not set configuration: %s", libusb_strerror(err)); - libusb_close(dev_handle); - libusb_exit(ctx); - return ERROR_FAIL; - } + if (!intf_desc_candidate && device_identified_reliably) { + /* This interface looks suitable for CMSIS-DAP. Store the pointer to it + * and keep searching for another one with CMSIS-DAP in interface string */ + intf_desc_candidate = intf_desc; } - - err = libusb_claim_interface(dev_handle, interface_num); - if (err) - LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); - - dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); - if (dap->bdata == NULL) { - LOG_ERROR("unable to allocate memory"); - libusb_release_interface(dev_handle, interface_num); - libusb_close(dev_handle); - libusb_exit(ctx); - return ERROR_FAIL; - } - - dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */ - dap->bdata->usb_ctx = ctx; - dap->bdata->dev_handle = dev_handle; - dap->bdata->ep_out = ep_out; - dap->bdata->ep_in = ep_in; - dap->bdata->interface = interface_num; - return ERROR_OK; } + if (!intf_desc_found) { + /* We were not able to identify reliably which interface is CMSIS-DAP. + * Let's use the first suitable if we found one */ + intf_desc_found = intf_desc_candidate; + } + + if (!intf_desc_found) { + libusb_free_config_descriptor(config_desc); + continue; + } + + /* We've chosen an interface, connect to it */ + int interface_num = intf_desc_found->bInterfaceNumber; + int packet_size = intf_desc_found->endpoint[0].wMaxPacketSize; + int ep_out = intf_desc_found->endpoint[0].bEndpointAddress; + int ep_in = intf_desc_found->endpoint[1].bEndpointAddress; + libusb_free_config_descriptor(config_desc); + libusb_free_device_list(device_list, true); + + LOG_INFO("Using CMSIS-DAPv2 interface with VID:PID=0x%04x:0x%04x, serial=%s", + dev_desc.idVendor, dev_desc.idProduct, dev_serial); + + int current_config; + err = libusb_get_configuration(dev_handle, ¤t_config); + if (err) { + LOG_ERROR("could not find current configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + if (config_num != current_config) { + err = libusb_set_configuration(dev_handle, config_num); + if (err) { + LOG_ERROR("could not set configuration: %s", libusb_strerror(err)); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + } + + err = libusb_claim_interface(dev_handle, interface_num); + if (err) + LOG_WARNING("could not claim interface: %s", libusb_strerror(err)); + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (dap->bdata == NULL) { + LOG_ERROR("unable to allocate memory"); + libusb_release_interface(dev_handle, interface_num); + libusb_close(dev_handle); + libusb_exit(ctx); + return ERROR_FAIL; + } + + dap->packet_size = packet_size + 1; /* "+ 1" for compatibility with the HID backend */ + dap->bdata->usb_ctx = ctx; + dap->bdata->dev_handle = dev_handle; + dap->bdata->ep_out = ep_out; + dap->bdata->ep_in = ep_in; + dap->bdata->interface = interface_num; + return ERROR_OK; } libusb_close(dev_handle); From 9c314578750324b8d46cdbe0801d3cdfc25c4a4c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 30 Jul 2020 21:36:39 +0200 Subject: [PATCH 080/113] jtag/drivers/cmsis_dap: fix build with gcc 10.1.0 Avoid multiple definition of cmsis_dap_usb_backend and cmsis_dap_hid_backend using 'extern'. Move the prototypes in cmsis_dap.h. Remove the useless #if/#endif around the prototypes. Change-Id: I8d73fe148e2155620244bc887d4235e9af530e30 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5790 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Tomas Vanek --- src/jtag/drivers/cmsis_dap.c | 9 --------- src/jtag/drivers/cmsis_dap.h | 4 ++++ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 8ddb54179..16480ae1e 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -43,15 +43,6 @@ #include "cmsis_dap.h" -#if BUILD_CMSIS_DAP_USB == 1 -const struct cmsis_dap_backend cmsis_dap_usb_backend; -extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; -#endif - -#if BUILD_CMSIS_DAP_HID == 1 -const struct cmsis_dap_backend cmsis_dap_hid_backend; -#endif - static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { #if BUILD_CMSIS_DAP_USB == 1 &cmsis_dap_usb_backend, diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h index 8cbb8dd07..054621cd5 100644 --- a/src/jtag/drivers/cmsis_dap.h +++ b/src/jtag/drivers/cmsis_dap.h @@ -25,4 +25,8 @@ struct cmsis_dap_backend { int (*write)(struct cmsis_dap *dap, int len, int timeout_ms); }; +extern const struct cmsis_dap_backend cmsis_dap_hid_backend; +extern const struct cmsis_dap_backend cmsis_dap_usb_backend; +extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; + #endif From 0e0283e582ddc06b34f3d7e3b09d1754dd501794 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 8 Nov 2020 22:34:26 +0100 Subject: [PATCH 081/113] doc: document CMSIS-DAP v2 Change-Id: Ie54e855901c079b456c26a6239177c7678cdcac7 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5930 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- doc/openocd.texi | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 84ed32060..292bbd77c 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2429,7 +2429,8 @@ and a specific set of GPIOs is used. @end deffn @deffn {Interface Driver} {cmsis-dap} -ARM CMSIS-DAP compliant based adapter. +ARM CMSIS-DAP compliant based adapter v1 (USB HID based) +or v2 (USB bulk). @deffn {Config Command} {cmsis_dap_vid_pid} [vid pid]+ The vendor ID and product ID of the CMSIS-DAP device. If not specified @@ -2445,6 +2446,23 @@ Specifies the @var{serial} of the CMSIS-DAP device to use. If not specified, serial numbers are not considered. @end deffn +@deffn {Config Command} {cmsis_dap_backend} [@option{auto}|@option{usb_bulk}|@option{hid}] +Specifies how to communicate with the adapter: + +@itemize @minus +@item @option{hid} Use HID generic reports - CMSIS-DAP v1 +@item @option{usb_bulk} Use USB bulk - CMSIS-DAP v2 +@item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1. +This is the default if @command{cmsis_dap_backend} is not specified. +@end itemize +@end deffn + +@deffn {Config Command} {cmsis_dap_usb interface} [number] +Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk). +In most cases need not to be specified and interfaces are searched by +interface string or for user class interface. +@end deffn + @deffn {Command} {cmsis-dap info} Display various device information, like hardware version, firmware version, current bus status. @end deffn From 44cf202ef585ea5e2dda78e65cc5d04e08129eff Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Fri, 6 Nov 2020 12:33:14 +0100 Subject: [PATCH 082/113] 60-openocd.rules: add ULINKplus CMSIS-DAP based adapter Change-Id: I5935e0a184b8995122d197046ef8fb4e7eefb884 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5926 Reviewed-by: Tarek BOCHKATI Reviewed-by: Tomas Vanek Tested-by: jenkins --- contrib/60-openocd.rules | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 53f97dd83..fe57364d7 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -167,6 +167,7 @@ ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="660", GROUP="plugdev", # Keil Software, Inc. ULink ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2750", MODE="660", GROUP="plugdev", TAG+="uaccess" # CMSIS-DAP compatible adapters ATTRS{product}=="*CMSIS-DAP*", MODE="660", GROUP="plugdev", TAG+="uaccess" From dc43ecce5a7ee5722ea851707ad3acd08a42b5aa Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Tue, 3 Nov 2020 01:58:59 +0100 Subject: [PATCH 083/113] flash/stm32l4x: introduce table with register offsets This change is a preparation for STM32L5 support on top of L4 driver STM32L5 flash is quite similar to L4 flash, mainly register names and offsets and some bits are changed. flash_regs table is introduced within stm32l4_flash_bank struct in order to get correct register offsets, by using the driver internal function 'stm32l4_get_flash_reg_by_index'. To use efficiently register indexes, stm32l4 _[get|read|write]_flash_reg functions are surcharged to accept register indexes. IMPORTANT: stm32l4_write_option is not surcharged, and they always accept the option register offset. tested on NUCLEO-G474RE and STM32L4R9I-DISCO Change-Id: I739d3e97d63b831af6aa569c5629db0000209551 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5509 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- src/flash/nor/stm32l4x.c | 141 +++++++++++++++++++++++++++++---------- src/flash/nor/stm32l4x.h | 12 ---- 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 9bdc2dbca..ca8a3b81d 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -81,8 +81,7 @@ * http://www.st.com/resource/en/reference_manual/dm00530369.pdf */ -/* - * STM32G0xxx series for reference. +/* STM32G0xxx series for reference. * * RM0444 (STM32G0x1) * http://www.st.com/resource/en/reference_manual/dm00371828.pdf @@ -91,8 +90,7 @@ * http://www.st.com/resource/en/reference_manual/dm00463896.pdf */ -/* - * STM32G4xxx series for reference. +/* STM32G4xxx series for reference. * * RM0440 (STM32G43x/44x/47x/48x/49x/4Ax) * http://www.st.com/resource/en/reference_manual/dm00355726.pdf @@ -112,6 +110,33 @@ #define FLASH_ERASE_TIMEOUT 250 +enum stm32l4_flash_reg_index { + STM32_FLASH_ACR_INDEX, + STM32_FLASH_KEYR_INDEX, + STM32_FLASH_OPTKEYR_INDEX, + STM32_FLASH_SR_INDEX, + STM32_FLASH_CR_INDEX, + STM32_FLASH_OPTR_INDEX, + STM32_FLASH_WRP1AR_INDEX, + STM32_FLASH_WRP1BR_INDEX, + STM32_FLASH_WRP2AR_INDEX, + STM32_FLASH_WRP2BR_INDEX, + STM32_FLASH_REG_INDEX_NUM, +}; + +static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x008, + [STM32_FLASH_OPTKEYR_INDEX] = 0x00C, + [STM32_FLASH_SR_INDEX] = 0x010, + [STM32_FLASH_CR_INDEX] = 0x014, + [STM32_FLASH_OPTR_INDEX] = 0x020, + [STM32_FLASH_WRP1AR_INDEX] = 0x02C, + [STM32_FLASH_WRP1BR_INDEX] = 0x030, + [STM32_FLASH_WRP2AR_INDEX] = 0x04C, + [STM32_FLASH_WRP2BR_INDEX] = 0x050, +}; + struct stm32l4_rev { const uint16_t rev; const char *str; @@ -125,6 +150,7 @@ struct stm32l4_part_info { const uint16_t max_flash_size_kb; const bool has_dual_bank; const uint32_t flash_regs_base; + const uint32_t *default_flash_regs; const uint32_t fsize_addr; }; @@ -137,10 +163,11 @@ struct stm32l4_flash_bank { uint32_t user_bank_size; uint32_t wrpxxr_mask; const struct stm32l4_part_info *part_info; + const uint32_t *flash_regs; }; -/* human readable list of families this drivers supports */ -static const char *device_families = "STM32L4/L4+/WB/WL/G4/G0"; +/* human readable list of families this drivers supports (sorted alphabetically) */ +static const char *device_families = "STM32G0/G4/L4/L4+/WB/WL"; static const struct stm32l4_rev stm32_415_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } @@ -211,6 +238,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 1024, .has_dual_bank = true, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -221,6 +249,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 256, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -231,6 +260,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 128, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -241,6 +271,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 1024, .has_dual_bank = true, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -251,6 +282,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 512, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -261,6 +293,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 128, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -271,6 +304,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 64, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -281,6 +315,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 128, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -291,6 +326,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 512, .has_dual_bank = true, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -301,6 +337,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 2048, .has_dual_bank = true, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -311,6 +348,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 1024, .has_dual_bank = true, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -321,6 +359,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 512, .has_dual_bank = false, .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -331,6 +370,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 1024, .has_dual_bank = false, .flash_regs_base = 0x58004000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -341,6 +381,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 512, .has_dual_bank = false, .flash_regs_base = 0x58004000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, { @@ -351,6 +392,7 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .max_flash_size_kb = 256, .has_dual_bank = false, .flash_regs_base = 0x58004000, + .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, }; @@ -384,16 +426,37 @@ static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t r return stm32l4_info->part_info->flash_regs_base + reg_offset; } +static inline uint32_t stm32l4_get_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_get_flash_reg(bank, stm32l4_info->flash_regs[reg_index]); +} + static inline int stm32l4_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value) { return target_read_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } +static inline int stm32l4_read_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index, uint32_t *value) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_read_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); +} + static inline int stm32l4_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value) { return target_write_u32(bank->target, stm32l4_get_flash_reg(bank, reg_offset), value); } +static inline int stm32l4_write_flash_reg_by_index(struct flash_bank *bank, + enum stm32l4_flash_reg_index reg_index, uint32_t value) +{ + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + return stm32l4_write_flash_reg(bank, stm32l4_info->flash_regs[reg_index], value); +} + static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) { uint32_t status; @@ -401,7 +464,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* wait for busy to clear */ for (;;) { - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_SR, &status); + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); @@ -427,7 +490,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) /* If this operation fails, we ignore it and report the original * retval */ - stm32l4_write_flash_reg(bank, STM32_FLASH_SR, status & FLASH_ERROR); + stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status & FLASH_ERROR); } return retval; @@ -440,7 +503,7 @@ static int stm32l4_unlock_reg(struct flash_bank *bank) /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ - int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -448,15 +511,15 @@ static int stm32l4_unlock_reg(struct flash_bank *bank) return ERROR_OK; /* unlock flash registers */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY1); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1); if (retval != ERROR_OK) return retval; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_KEYR, KEY2); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2); if (retval != ERROR_OK) return retval; - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -472,7 +535,7 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank) { uint32_t ctrl; - int retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -480,15 +543,15 @@ static int stm32l4_unlock_option_reg(struct flash_bank *bank) return ERROR_OK; /* unlock option registers */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY1); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1); if (retval != ERROR_OK) return retval; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_OPTKEYR, OPTKEY2); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2); if (retval != ERROR_OK) return retval; - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_CR, &ctrl); + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl); if (retval != ERROR_OK) return retval; @@ -524,14 +587,14 @@ static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OPTSTRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK | FLASH_OPTLOCK); if (retval != ERROR_OK) return retval; @@ -544,11 +607,11 @@ static int stm32l4_protect_check(struct flash_bank *bank) struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br; - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1AR, &wrp1ar); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP1BR, &wrp1br); + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1AR_INDEX, &wrp1ar); + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP1BR_INDEX, &wrp1br); if (stm32l4_info->part_info->has_dual_bank) { - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2AR, &wrp2ar); - stm32l4_read_flash_reg(bank, STM32_FLASH_WRP2BR, &wrp2br); + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2AR_INDEX, &wrp2ar); + stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_WRP2BR_INDEX, &wrp2br); } else { /* prevent uninitialized errors */ wrp2ar = 0; @@ -627,7 +690,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; } else erase_flags |= i << FLASH_PAGE_SHIFT; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, erase_flags); if (retval != ERROR_OK) break; @@ -639,7 +702,7 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, } err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK); if (retval != ERROR_OK) return retval; @@ -667,7 +730,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, reg_value = ((last & 0xFF) << 16) | begin; } - ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 0xffffffff); + ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP2AR_INDEX], reg_value, 0xffffffff); } /* Bank 1 */ reg_value = 0xFF; /* Default to bank un-protected */ @@ -677,7 +740,7 @@ static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, reg_value = (end << 16) | (first & 0xFF); } - ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 0xffffffff); + ret = stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_WRP1AR_INDEX], reg_value, 0xffffffff); } return ret; @@ -743,8 +806,8 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); - buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_SR)); - buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg(bank, STM32_FLASH_CR)); + buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX)); + buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX)); retval = target_run_flash_async_algorithm(target, buffer, count, 8, 0, NULL, @@ -764,7 +827,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) { LOG_ERROR("flash write failed = %08" PRIx32, error); /* Clear but report errors */ - stm32l4_write_flash_reg(bank, STM32_FLASH_SR, error); + stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, error); retval = ERROR_FAIL; } } @@ -841,7 +904,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, retval = stm32l4_write_block(bank, buffer, offset, count / 8); err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK); if (retval != ERROR_OK) { LOG_ERROR("block write failed"); @@ -896,6 +959,7 @@ static int stm32l4_probe(struct flash_bank *bank) } part_info = stm32l4_info->part_info; + stm32l4_info->flash_regs = stm32l4_info->part_info->default_flash_regs; char device_info[1024]; retval = bank->driver->info(bank, device_info, sizeof(device_info)); @@ -929,7 +993,7 @@ static int stm32l4_probe(struct flash_bank *bank) assert((flash_size_kb != 0xffff) && flash_size_kb); /* read flash option register */ - retval = stm32l4_read_flash_reg(bank, STM32_FLASH_OPTR, &options); + retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &options); if (retval != ERROR_OK) return retval; @@ -1150,18 +1214,18 @@ static int stm32l4_mass_erase(struct flash_bank *bank) if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action); if (retval != ERROR_OK) goto err_lock; - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, action | FLASH_STRT); if (retval != ERROR_OK) goto err_lock; retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); err_lock: - retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK); + retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK); if (retval != ERROR_OK) return retval; @@ -1274,7 +1338,7 @@ COMMAND_HANDLER(stm32l4_handle_option_load_command) * "Note: If the read protection is set while the debugger is still * connected through JTAG/SWD, apply a POR (power-on reset) instead of a system reset." */ - retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OBL_LAUNCH); + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_OBL_LAUNCH); command_print(CMD, "stm32l4x option load completed. Power-on reset might be required"); @@ -1305,7 +1369,8 @@ COMMAND_HANDLER(stm32l4_handle_lock_command) } /* set readout protection level 1 by erasing the RDP option byte */ - if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], 0, 0x000000FF) != ERROR_OK) { command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } @@ -1332,7 +1397,9 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command) return ERROR_TARGET_NOT_HALTED; } - if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) { + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + if (stm32l4_write_option(bank, stm32l4_info->flash_regs[STM32_FLASH_OPTR_INDEX], + RDP_LEVEL_0, 0x000000FF) != ERROR_OK) { command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index abd8010fc..3e810a03c 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -19,18 +19,6 @@ #ifndef OPENOCD_FLASH_NOR_STM32L4X #define OPENOCD_FLASH_NOR_STM32L4X -/* Flash registers offsets */ -#define STM32_FLASH_ACR 0x00 -#define STM32_FLASH_KEYR 0x08 -#define STM32_FLASH_OPTKEYR 0x0c -#define STM32_FLASH_SR 0x10 -#define STM32_FLASH_CR 0x14 -#define STM32_FLASH_OPTR 0x20 -#define STM32_FLASH_WRP1AR 0x2c -#define STM32_FLASH_WRP1BR 0x30 -#define STM32_FLASH_WRP2AR 0x4c -#define STM32_FLASH_WRP2BR 0x50 - /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_PER (1 << 1) From 3d736e0488bc498358e3d49d7ce728b17955c8fe Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Wed, 25 Mar 2020 16:33:30 +0100 Subject: [PATCH 084/113] flash/stm32l4x: STM32L55/L56xx basic support (non-secure mode) STM32L5 have 512 Kbytes of Flash memory with dual bank architecture. STM32L5 flash is quite similar to L4 flash, mainly register names and offsets and some bits are changed. NON-SECURE flash is located at 0x8000000 like L4 devices, so no big change is needed (secure flash will be subject of another change). Note: flash driver name is set stm32l5x, in order to extend the commands with specific L5 commands (to manage TZEN for example ...) Note: this works only when TZEN=0 Change-Id: Ie758abb4aa19a3f29eeb0702d7dcb43992e4c639 Signed-off-by: Michael Jung Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5510 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- doc/openocd.texi | 5 +- src/flash/nor/stm32l4x.c | 75 +++++++++++++++++---- src/flash/startup.tcl | 1 + tcl/board/st_nucleo_l5.cfg | 13 ++++ tcl/target/stm32l5x.cfg | 130 +++++++++++++++++++++++++++++++++++++ 5 files changed, 209 insertions(+), 15 deletions(-) create mode 100644 tcl/board/st_nucleo_l5.cfg create mode 100644 tcl/target/stm32l5x.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 292bbd77c..65b5d65b2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7134,10 +7134,9 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn {Flash Driver} stm32l4x -All members of the STM32L4, STM32L4+, STM32WB, STM32WL and STM32G4 +All members of the STM32 G0, G4, L4, L4+, L5, WB and WL microcontroller families from STMicroelectronics include internal flash -and use ARM Cortex-M4 cores. -Additionally this driver supports STM32G0 family with ARM Cortex-M0+ core. +and use ARM Cortex-M0+, M4 and M33 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index ca8a3b81d..2bf291368 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -106,6 +106,12 @@ * Cat. 4 devices have single bank only, page size is 2kByte. */ +/* STM32L5xxx series for reference. + * + * RM0428 (STM32L552xx/STM32L562xx) + * http://www.st.com/resource/en/reference_manual/dm00346336.pdf + */ + /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 @@ -137,6 +143,19 @@ static const uint32_t stm32l4_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { [STM32_FLASH_WRP2BR_INDEX] = 0x050, }; +static const uint32_t stm32l5_ns_flash_regs[STM32_FLASH_REG_INDEX_NUM] = { + [STM32_FLASH_ACR_INDEX] = 0x000, + [STM32_FLASH_KEYR_INDEX] = 0x008, + [STM32_FLASH_OPTKEYR_INDEX] = 0x010, + [STM32_FLASH_SR_INDEX] = 0x020, + [STM32_FLASH_CR_INDEX] = 0x028, + [STM32_FLASH_OPTR_INDEX] = 0x040, + [STM32_FLASH_WRP1AR_INDEX] = 0x058, + [STM32_FLASH_WRP1BR_INDEX] = 0x05C, + [STM32_FLASH_WRP2AR_INDEX] = 0x068, + [STM32_FLASH_WRP2BR_INDEX] = 0x06C, +}; + struct stm32l4_rev { const uint16_t rev; const char *str; @@ -167,7 +186,7 @@ struct stm32l4_flash_bank { }; /* human readable list of families this drivers supports (sorted alphabetically) */ -static const char *device_families = "STM32G0/G4/L4/L4+/WB/WL"; +static const char *device_families = "STM32G0/G4/L4/L4+/L5/WB/WL"; static const struct stm32l4_rev stm32_415_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } @@ -213,6 +232,10 @@ static const struct stm32l4_rev stm32_471_revs[] = { { 0x1001, "Z" }, }; +static const struct stm32l4_rev stm32_472_revs[] = { + { 0x1000, "A" }, { 0x2000, "B" }, +}; + static const struct stm32l4_rev stm32_479_revs[] = { { 0x1000, "A" }, }; @@ -351,6 +374,17 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .default_flash_regs = stm32l4_flash_regs, .fsize_addr = 0x1FFF75E0, }, + { + .id = 0x472, + .revs = stm32_472_revs, + .num_revs = ARRAY_SIZE(stm32_472_revs), + .device_str = "STM32L55/L56xx", + .max_flash_size_kb = 512, + .has_dual_bank = true, + .flash_regs_base = 0x40022000, + .default_flash_regs = stm32l5_ns_flash_regs, + .fsize_addr = 0x0BFA05E0, + }, { .id = 0x479, .revs = stm32_479_revs, @@ -477,7 +511,6 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) alive_sleep(1); } - if (status & FLASH_WRPERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; @@ -917,17 +950,17 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id) { int retval; - /* try stm32l4/l4+/wb/g4 id register first, then stm32g0 id register */ - retval = target_read_u32(bank->target, DBGMCU_IDCODE_L4_G4, id); - if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { - retval = target_read_u32(bank->target, DBGMCU_IDCODE_G0, id); - if ((retval != ERROR_OK) || ((*id & 0xfff) == 0) || ((*id & 0xfff) == 0xfff)) { - LOG_ERROR("can't get device id"); - return (retval == ERROR_OK) ? ERROR_FAIL : retval; - } + /* try reading possible IDCODE registers, in the following order */ + uint32_t DBGMCU_IDCODE[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5}; + + for (unsigned int i = 0; i < ARRAY_SIZE(DBGMCU_IDCODE); i++) { + retval = target_read_u32(bank->target, DBGMCU_IDCODE[i], id); + if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff)) + return ERROR_OK; } - return retval; + LOG_ERROR("can't get the device id"); + return (retval == ERROR_OK) ? ERROR_FAIL : retval; } static int stm32l4_probe(struct flash_bank *bank) @@ -1004,6 +1037,7 @@ static int stm32l4_probe(struct flash_bank *bank) int page_size_kb = 0; stm32l4_info->dual_bank_mode = false; + bool use_dbank_bit = false; switch (device_id) { case 0x415: /* STM32L47/L48xx */ @@ -1070,7 +1104,7 @@ static int stm32l4_probe(struct flash_bank *bank) page_size_kb = 8; num_pages = flash_size_kb / page_size_kb; stm32l4_info->bank1_sectors = num_pages; - const bool use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; + use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; if ((use_dbank_bit && (options & BIT(22))) || (!use_dbank_bit && (options & BIT(21)))) { stm32l4_info->dual_bank_mode = true; @@ -1079,6 +1113,23 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case 0x472: /* STM32L55/L56xx */ + /* STM32L55/L56xx can be single/dual bank: + * if size = 512K check DBANK bit(22) + * if size = 256K check DB256K bit(21) + */ + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + use_dbank_bit = flash_size_kb == part_info->max_flash_size_kb; + if ((use_dbank_bit && (options & BIT(22))) || + (!use_dbank_bit && (options & BIT(21)))) { + stm32l4_info->dual_bank_mode = true; + page_size_kb = 2; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; case 0x495: /* STM32WB5x */ case 0x496: /* STM32WB3x */ /* single bank flash */ diff --git a/src/flash/startup.tcl b/src/flash/startup.tcl index aafb939cd..280a059a3 100644 --- a/src/flash/startup.tcl +++ b/src/flash/startup.tcl @@ -116,6 +116,7 @@ proc stm32l1x args { eval stm32lx $args } # stm32[g0|g4|wb|wl] uses the same flash driver as the stm32l4x proc stm32g0x args { eval stm32l4x $args } proc stm32g4x args { eval stm32l4x $args } +proc stm32l5x args { eval stm32l4x $args } proc stm32wbx args { eval stm32l4x $args } proc stm32wlx args { eval stm32l4x $args } diff --git a/tcl/board/st_nucleo_l5.cfg b/tcl/board/st_nucleo_l5.cfg new file mode 100644 index 000000000..6450f08b8 --- /dev/null +++ b/tcl/board/st_nucleo_l5.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is for STM32L5 Nucleo Dev Boards. +# http://www.st.com/en/evaluation-tools/stm32-mcu-nucleo.html + +source [find interface/stlink-dap.cfg] + +transport select dapdirect_swd + +source [find target/stm32l5x.cfg] + +# use hardware reset +reset_config srst_only srst_nogate diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg new file mode 100644 index 000000000..bf5636094 --- /dev/null +++ b/tcl/target/stm32l5x.cfg @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32l5x family + +# +# stm32l5 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32l5x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + # See STM Document RM0438 + # RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # Corresponds to Cortex®-M33 JTAG debug port ID code + set _CPUTAPID 0x0ba04477 + } { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0be12477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +if {[using_jtag]} { + jtag newtap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +# use non-secure RAM by default +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +# declare non-secure flash +flash bank $_CHIPNAME.flash_ns stm32l4x 0 0 0 0 $_TARGETNAME + +# Common knowledges tells JTAG speed should be <= F_CPU/6. +# F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on +# the safe side. +# +# Note that there is a pretty wide band where things are +# more or less stable, see http://openocd.zylin.com/#/c/3366/ +adapter speed 500 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +reset_config srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +proc clock_config_110_mhz {} { + # MCU clock is MSI (4MHz) after reset, set MCU freq at 110 MHz with PLL + # RCC_APB1ENR1 = PWREN + mww 0x40021058 0x10000000 + # delay for register clock enable (read back reg) + mrw 0x40021058 + # PWR_CR1 : VOS Range 0 + mww 0x40007000 0 + # while (PWR_SR2 & VOSF) + while {([mrw 0x40007014] & 0x0400)} {} + # FLASH_ACR : 5 WS for 110 MHz HCLK + mww 0x40022000 0x00000005 + # RCC_PLLCFGR = PLLP=PLLQ=0, PLLR=00=2, PLLREN=1, PLLN=55, PLLM=0000=1, PLLSRC=MSI 4MHz + # fVCO = 4 x 55 /1 = 220 + # SYSCLOCK = fVCO/PLLR = 220/2 = 110 MHz + mww 0x4002100C 0x01003711 + # RCC_CR |= PLLON + mmw 0x40021000 0x01000000 0 + # while !(RCC_CR & PLLRDY) + while {!([mrw 0x40021000] & 0x02000000)} {} + # RCC_CFGR |= SW_PLL + mmw 0x40021008 0x00000003 0 + # while ((RCC_CFGR & SWS) != PLL) + while {([mrw 0x40021008] & 0x0C) != 0x0C} {} +} + +$_TARGETNAME configure -event reset-init { + clock_config_110_mhz + # Boost JTAG frequency + adapter speed 4000 +} + +$_TARGETNAME configure -event reset-start { + # Reset clock is MSI (4 MHz) + adapter speed 480 +} + +$_TARGETNAME configure -event examine-end { + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP + mmw 0xE0044004 0x00000006 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0044008 0x00001800 0 +} + +$_TARGETNAME configure -event trace-config { + # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0xE0044004 0x00000020 0 +} From 726b0c592884566a7580780418ba763ffc51c745 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Sun, 22 Mar 2020 19:36:12 +0100 Subject: [PATCH 085/113] stm32l4x: cosmetic simplification of get_stm32l4_info Change-Id: I2542f946f64388d908b1502f869643080fce9f9e Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5536 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Andreas Bolsch Reviewed-by: Tomas Vanek --- src/flash/nor/stm32l4x.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index 2bf291368..55a8d8ff3 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -1218,19 +1218,17 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size) for (unsigned int i = 0; i < part_info->num_revs; i++) { if (rev_id == part_info->revs[i].rev) { rev_str = part_info->revs[i].str; - - if (rev_str != NULL) { - snprintf(buf, buf_size, "%s - Rev: %s%s", - part_info->device_str, rev_str, stm32l4_info->probed ? - (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); - return ERROR_OK; - } + break; } } - snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)%s", - part_info->device_str, rev_id, stm32l4_info->probed ? - (stm32l4_info->dual_bank_mode ? " dual-bank" : " single-bank") : ""); + int buf_len = snprintf(buf, buf_size, "%s - Rev %s : 0x%04x", + part_info->device_str, rev_str ? rev_str : "'unknown'", rev_id); + + if (stm32l4_info->probed) + snprintf(buf + buf_len, buf_size - buf_len, " - %s-bank", + stm32l4_info->dual_bank_mode ? "Flash dual" : "Flash single"); + return ERROR_OK; } else { snprintf(buf, buf_size, "Cannot identify target as an %s device", device_families); From 61326940361b2242feb8adfefb9ca12727154693 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 8 Nov 2020 10:09:33 +0100 Subject: [PATCH 086/113] flash/nor/stm32f1x: fix error message Backported from gd32vf103.c Change-Id: I9c5bb7b36e6efcee0473c97047058ef26cc46eb7 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5927 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/flash/nor/stm32f1x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 78efc8b47..9cd282d65 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -215,7 +215,7 @@ static int stm32x_check_operation_supported(struct flash_bank *bank) /* if we have a dual flash bank device then * we need to perform option byte stuff on bank0 only */ if (stm32x_info->register_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Operation's must use bank0"); + LOG_ERROR("Option byte operations must use bank 0"); return ERROR_FLASH_OPERATION_FAILED; } From a03ac1ba3087ffedb3064e926624eda6cda8f808 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 8 Nov 2020 13:46:39 +0100 Subject: [PATCH 087/113] helper/command: disable logging of registered commands [RFC] Every debug log of OpenOCD contains approximately 130 lines like: Debug: 264 147 command.c:354 register_command_handler(): registering 'flash'... Because only root name of the command is logged, most of lines is not too informative. E.g. registering 'flash' is repeated 14 times. Karl Passon submitted the patch [1] changing the logged cmd name from root to lowest level. It makes the log better. Unfortunately we also have 'reset_config' and 'cortex_m reset_config' and similar which looks equal in the log after [1]. Moreover [1] has not been reviewed for 5 years. So my guess is that nobody uses that crap in debug log. Save more than 10 kbytes in any debug log and make log analyse easier by blocking log command in #if 0 block. If some developer eventually needs to debug cmd registering he can easily enable logging again. [1] http://openocd.zylin.com/2765 Change-Id: Ib7e528aadd692fd0da2e3c005b4c5a484551b728 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5928 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Christopher Head --- src/helper/command.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper/command.c b/src/helper/command.c index 773195e2f..0a711e514 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -349,7 +349,9 @@ static int register_command_handler(struct command_context *cmd_ctx, { Jim_Interp *interp = cmd_ctx->interp; +#if 0 LOG_DEBUG("registering '%s'...", c->name); +#endif Jim_CmdProc *func = c->handler ? &script_command : &command_unknown; int retval = Jim_CreateCommand(interp, c->name, func, c, NULL); From a8edbd0200560bfd412c5c563908d860ed2c96a6 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Sun, 8 Nov 2020 21:48:14 +0100 Subject: [PATCH 088/113] tcl/target: remove deprecated ${target}_${adapter}.cfg files Change-Id: Ic4837ad3bd06eb353020e44638306f341a923c05 Signed-off-by: Tarek BOCHKATI Reviewed-on: http://openocd.zylin.com/5929 Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Tomas Vanek --- tcl/target/efm32_stlink.cfg | 2 -- tcl/target/kl25z_hla.cfg | 2 -- tcl/target/nrf51_stlink.tcl | 2 -- tcl/target/stellaris_icdi.cfg | 2 -- tcl/target/stm32_stlink.cfg | 1 - tcl/target/stm32f0x_stlink.cfg | 2 -- tcl/target/stm32f1x_stlink.cfg | 2 -- tcl/target/stm32f2x_stlink.cfg | 2 -- tcl/target/stm32f3x_stlink.cfg | 2 -- tcl/target/stm32f4x_stlink.cfg | 2 -- tcl/target/stm32lx_stlink.cfg | 2 -- tcl/target/stm32w108_stlink.cfg | 2 -- 12 files changed, 23 deletions(-) delete mode 100644 tcl/target/efm32_stlink.cfg delete mode 100644 tcl/target/kl25z_hla.cfg delete mode 100644 tcl/target/nrf51_stlink.tcl delete mode 100644 tcl/target/stellaris_icdi.cfg delete mode 100644 tcl/target/stm32_stlink.cfg delete mode 100644 tcl/target/stm32f0x_stlink.cfg delete mode 100644 tcl/target/stm32f1x_stlink.cfg delete mode 100644 tcl/target/stm32f2x_stlink.cfg delete mode 100644 tcl/target/stm32f3x_stlink.cfg delete mode 100644 tcl/target/stm32f4x_stlink.cfg delete mode 100644 tcl/target/stm32lx_stlink.cfg delete mode 100644 tcl/target/stm32w108_stlink.cfg diff --git a/tcl/target/efm32_stlink.cfg b/tcl/target/efm32_stlink.cfg deleted file mode 100644 index 230155ea0..000000000 --- a/tcl/target/efm32_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/efm32_stlink.cfg is deprecated, please switch to target/efm32.cfg" -source [find target/efm32.cfg] diff --git a/tcl/target/kl25z_hla.cfg b/tcl/target/kl25z_hla.cfg deleted file mode 100644 index e4deac615..000000000 --- a/tcl/target/kl25z_hla.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/kl25z_hla.cfg is deprecated, please switch to target/kl25.cfg" -source [find target/kl25.cfg] diff --git a/tcl/target/nrf51_stlink.tcl b/tcl/target/nrf51_stlink.tcl deleted file mode 100644 index 7e23c5a74..000000000 --- a/tcl/target/nrf51_stlink.tcl +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/nrf51_stlink.cfg is deprecated, please switch to target/nrf51.cfg" -source [find target/nrf51.cfg] diff --git a/tcl/target/stellaris_icdi.cfg b/tcl/target/stellaris_icdi.cfg deleted file mode 100644 index f856a7a8d..000000000 --- a/tcl/target/stellaris_icdi.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stellaris_icdi.cfg is deprecated, please switch to target/stellaris.cfg" -source [find target/stellaris.cfg] diff --git a/tcl/target/stm32_stlink.cfg b/tcl/target/stm32_stlink.cfg deleted file mode 100644 index 295292e3e..000000000 --- a/tcl/target/stm32_stlink.cfg +++ /dev/null @@ -1 +0,0 @@ -echo "WARNING: stm32_stlink.cfg is deprecated (and does nothing, you can safely remove it.)" diff --git a/tcl/target/stm32f0x_stlink.cfg b/tcl/target/stm32f0x_stlink.cfg deleted file mode 100644 index cecfb7a78..000000000 --- a/tcl/target/stm32f0x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f0x_stlink.cfg is deprecated, please switch to target/stm32f0x.cfg" -source [find target/stm32f0x.cfg] diff --git a/tcl/target/stm32f1x_stlink.cfg b/tcl/target/stm32f1x_stlink.cfg deleted file mode 100644 index 0a3e6430e..000000000 --- a/tcl/target/stm32f1x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f1x_stlink.cfg is deprecated, please switch to target/stm32f1x.cfg" -source [find target/stm32f1x.cfg] diff --git a/tcl/target/stm32f2x_stlink.cfg b/tcl/target/stm32f2x_stlink.cfg deleted file mode 100644 index 451b2b5e2..000000000 --- a/tcl/target/stm32f2x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f2x_stlink.cfg is deprecated, please switch to target/stm32f2x.cfg" -source [find target/stm32f2x.cfg] diff --git a/tcl/target/stm32f3x_stlink.cfg b/tcl/target/stm32f3x_stlink.cfg deleted file mode 100644 index 87693586d..000000000 --- a/tcl/target/stm32f3x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f3x_stlink.cfg is deprecated, please switch to target/stm32f3x.cfg" -source [find target/stm32f3x.cfg] diff --git a/tcl/target/stm32f4x_stlink.cfg b/tcl/target/stm32f4x_stlink.cfg deleted file mode 100644 index af3e8a098..000000000 --- a/tcl/target/stm32f4x_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32f4x_stlink.cfg is deprecated, please switch to target/stm32f4x.cfg" -source [find target/stm32f4x.cfg] diff --git a/tcl/target/stm32lx_stlink.cfg b/tcl/target/stm32lx_stlink.cfg deleted file mode 100644 index 5f694b546..000000000 --- a/tcl/target/stm32lx_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32lx_stlink.cfg is deprecated, please switch to target/stm32l1.cfg" -source [find target/stm32l1.cfg] diff --git a/tcl/target/stm32w108_stlink.cfg b/tcl/target/stm32w108_stlink.cfg deleted file mode 100644 index 120feea94..000000000 --- a/tcl/target/stm32w108_stlink.cfg +++ /dev/null @@ -1,2 +0,0 @@ -echo "WARNING: target/stm32w108xx_stlink.cfg is deprecated, please switch to target/stm32w108xx.cfg" -source [find target/stm32w108xx.cfg] From 646c3c99020f8fdf7ee0adf821582238aac4a80c Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Mon, 29 Jun 2020 13:34:07 +0200 Subject: [PATCH 089/113] arm_adi_v5: prevent possibly endless recursion in dap_dp_init() If dap_dp_read_atomic() in 30 trials loop fails, dap->do_reconnect is set. Following dap_dp_read_atomic() calls dap_queue_dp_read() which in case of SWD transport calls swd_queue_dp_read(). It starts with swd_check_reconnect() and it calls swd_connect() because dap->do_reconnect is set. swd_connect() does some initialization, reads DPIDR and calls dap_dp_init() again! Moreover if dap_dp_init() is called from cortex_m_reset_(de)assert() one level of recursion is necessary to reconnect the target. Introduce dap_dp_init_or_reconnect() for use in cortex_m reset and similar. Remove loop of 30 atomic reads of DP_STAT to prevent unwanted recursion. Change-Id: I54052fdefe50bf5f7c7b59fe751fe2063d5710c9 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5729 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Andreas Fritiofson --- src/target/arm_adi_v5.c | 52 +++++++++++++++++++++++++++-------------- src/target/arm_adi_v5.h | 1 + src/target/cortex_m.c | 13 +++++++---- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 31c14597b..59bb186c6 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -652,35 +652,22 @@ int dap_dp_init(struct adiv5_dap *dap) LOG_DEBUG("%s", adiv5_dap_name(dap)); + dap->do_reconnect = false; dap_invalidate_cache(dap); /* * Early initialize dap->dp_ctrl_stat. - * In jtag mode only, if the following atomic reads fail and set the - * sticky error, it will trigger the clearing of the sticky. Without this - * initialization system and debug power would be disabled while clearing - * the sticky error bit. + * In jtag mode only, if the following queue run (in dap_dp_poll_register) + * fails and sets the sticky error, it will trigger the clearing + * of the sticky. Without this initialization system and debug power + * would be disabled while clearing the sticky error bit. */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; - for (size_t i = 0; i < 30; i++) { - /* DP initialization */ - - retval = dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL); - if (retval == ERROR_OK) - break; - } - /* * This write operation clears the sticky error bit in jtag mode only and * is ignored in swd mode. It also powers-up system and debug domains in * both jtag and swd modes, if not done before. - * Actually we do not need to clear the sticky error here because it has - * been already cleared (if it was set) in the previous atomic read. This - * write could be removed, but this initial part of dap_dp_init() is the - * result of years of fine tuning and there are strong concerns about any - * unnecessary code change. It doesn't harm, so let's keep it here and - * preserve the historical sequence of read/write operations! */ retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); if (retval != ERROR_OK) @@ -731,6 +718,35 @@ int dap_dp_init(struct adiv5_dap *dap) return retval; } +/** + * Initialize a DAP or do reconnect if DAP is not accessible. + * + * @param dap The DAP being initialized. + */ +int dap_dp_init_or_reconnect(struct adiv5_dap *dap) +{ + LOG_DEBUG("%s", adiv5_dap_name(dap)); + + /* + * Early initialize dap->dp_ctrl_stat. + * In jtag mode only, if the following atomic reads fail and set the + * sticky error, it will trigger the clearing of the sticky. Without this + * initialization system and debug power would be disabled while clearing + * the sticky error bit. + */ + dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; + + dap->do_reconnect = false; + + dap_dp_read_atomic(dap, DP_CTRL_STAT, NULL); + if (dap->do_reconnect) { + /* dap connect calls dap_dp_init() after transport dependent initialization */ + return dap->ops->connect(dap); + } else { + return dap_dp_init(dap); + } +} + /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use, and arranges to use AP #0 for all AP operations diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index f319a062d..8edfaa816 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -550,6 +550,7 @@ int mem_ap_write_buf_noincr(struct adiv5_ap *ap, /* Initialisation of the debug system, power domains and registers */ int dap_dp_init(struct adiv5_dap *dap); +int dap_dp_init_or_reconnect(struct adiv5_dap *dap); int mem_ap_init(struct adiv5_ap *ap); /* Invalidate cached DP select and cached TAR and CSW of all APs */ diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 94cf82489..fae2aac5d 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1202,11 +1202,13 @@ static int cortex_m_assert_reset(struct target *target) if (retval3 != ERROR_OK) LOG_DEBUG("Ignoring AP write error right after reset"); - retval3 = dap_dp_init(armv7m->debug_ap->dap); - if (retval3 != ERROR_OK) + retval3 = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); + if (retval3 != ERROR_OK) { LOG_ERROR("DP initialisation failed"); - - else { + /* The error return value must not be propagated in this case. + * SYSRESETREQ or VECTRESET have been possibly triggered + * so reset processing should continue */ + } else { /* I do not know why this is necessary, but it * fixes strange effects (step/resume cause NMI * after reset) on LM3S6918 -- Michael Schwingen @@ -1249,7 +1251,8 @@ static int cortex_m_deassert_reset(struct target *target) if ((jtag_reset_config & RESET_HAS_SRST) && !(jtag_reset_config & RESET_SRST_NO_GATING) && target_was_examined(target)) { - int retval = dap_dp_init(armv7m->debug_ap->dap); + + int retval = dap_dp_init_or_reconnect(armv7m->debug_ap->dap); if (retval != ERROR_OK) { LOG_ERROR("DP initialisation failed"); return retval; From d459a2d27df52643dc8932827a63467a14f7c162 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Fri, 1 Mar 2019 21:44:27 +0100 Subject: [PATCH 090/113] adi_v5_swd: wait for readable DPIDR, ABORT if stalled Reading of DPIDR is the very first operation after JTAG to SWD sequence. Without this change if DPIDR read fails then swd connect fails. Keep trying JTAG to SWD sequence and DPIDR read until success or timeout 0.5 sec. It makes setting of adapter srst delay on SWD transport mostly unnecessary. Also test for ERROR_WAIT (which should not occur according to IHI 0031E B4.3.2 but a quirk is known) and if bus is kept stalled then issue abort to make the next connect possible. Change-Id: Id8fe6618605bbeb4fed5061e987ed55de90a35f2 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/5730 Tested-by: jenkins Reviewed-by: Antonio Borneo Reviewed-by: Andreas Fritiofson --- src/target/adi_v5_swd.c | 73 ++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index ee30ff7ba..b25181e21 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -118,26 +118,69 @@ static int swd_connect(struct adiv5_dap *dap) } } - /* Note, debugport_init() does setup too */ - swd->switch_seq(JTAG_TO_SWD); - /* Clear link state, including the SELECT cache. */ - dap->do_reconnect = false; - dap_invalidate_cache(dap); + int64_t timeout = timeval_ms() + 500; - swd_queue_dp_read(dap, DP_DPIDR, &dpidr); + do { + /* Note, debugport_init() does setup too */ + swd->switch_seq(JTAG_TO_SWD); - /* force clear all sticky faults */ - swd_clear_sticky_errors(dap); - - status = swd_run_inner(dap); - - if (status == ERROR_OK) { - LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); + /* Clear link state, including the SELECT cache. */ dap->do_reconnect = false; + dap_invalidate_cache(dap); + + status = swd_queue_dp_read(dap, DP_DPIDR, &dpidr); + if (status == ERROR_OK) { + status = swd_run_inner(dap); + if (status == ERROR_OK) + break; + } + + alive_sleep(1); + + } while (timeval_ms() < timeout); + + if (status != ERROR_OK) { + LOG_ERROR("Error connecting DP: cannot read IDR"); + return status; + } + + LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr); + + do { + dap->do_reconnect = false; + + /* force clear all sticky faults */ + swd_clear_sticky_errors(dap); + + status = swd_run_inner(dap); + if (status != ERROR_WAIT) + break; + + alive_sleep(10); + + } while (timeval_ms() < timeout); + + /* IHI 0031E B4.3.2: + * "A WAIT response must not be issued to the ... + * ... writes to the ABORT register" + * swd_clear_sticky_errors() writes to the ABORT register only. + * + * Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT + * in a corner case. Just try if ABORT resolves the problem. + */ + if (status == ERROR_WAIT) { + LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT"); + + dap->do_reconnect = false; + + swd->write_reg(swd_cmd(false, false, DP_ABORT), + DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); + status = swd_run_inner(dap); + } + + if (status == ERROR_OK) status = dap_dp_init(dap); - } else - dap->do_reconnect = true; return status; } From 7b641d3d4e9b0407e5410267459fcbc64f075fde Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 17 Sep 2020 15:23:31 +0200 Subject: [PATCH 091/113] Add initial RTT support Real Time Transfer (RTT) is an interface specified by SEGGER based on basic memory reads and writes to transfer data bidirectionally between target and host. Every target that supports so called "background memory access", which means that the target memory can be accessed by the debugger while the target is running, can be used. RTT is especially of interest for targets which do not support Serial Wire Output (SWO) (e.g. ARM Cortex-M0) or where using semihosting is not possible (e.g. real-time applications) [1]. The data transfer is organized in channels where each channel consists of an up- and/or down-channel. See [2] for more details. Channels are exposed via TCP connections. One or more RTT server can be assigned to each channel to make them accessible to an unlimited number of TCP connections. The current implementation does not respect buffer flags which are used to determine what happens when writing to a full buffer. Note that the implementation is designed in a way that the RTT operations can be directly performed by an adapter (e.g. J-Link). [1] https://devzone.nordicsemi.com/tutorials/6/ [2] https://www.segger.com/jlink-rtt.html Change-Id: I8bc8a1b381fb74e08b8752d5cf53804cc573c1e0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4055 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo --- doc/openocd.texi | 88 +++++++++ src/Makefile.am | 4 +- src/openocd.c | 7 + src/rtt/Makefile.am | 2 + src/rtt/rtt.c | 332 +++++++++++++++++++++++++++++++ src/rtt/rtt.h | 287 +++++++++++++++++++++++++++ src/rtt/tcl.c | 311 +++++++++++++++++++++++++++++ src/server/Makefile.am | 4 +- src/server/rtt_server.c | 192 ++++++++++++++++++ src/server/rtt_server.h | 25 +++ src/target/Makefile.am | 6 +- src/target/cortex_m.c | 4 + src/target/hla_target.c | 4 + src/target/rtt.c | 424 ++++++++++++++++++++++++++++++++++++++++ src/target/rtt.h | 46 +++++ 15 files changed, 1732 insertions(+), 4 deletions(-) create mode 100644 src/rtt/Makefile.am create mode 100644 src/rtt/rtt.c create mode 100644 src/rtt/rtt.h create mode 100644 src/rtt/tcl.c create mode 100644 src/server/rtt_server.c create mode 100644 src/server/rtt_server.h create mode 100644 src/target/rtt.c create mode 100644 src/target/rtt.h diff --git a/doc/openocd.texi b/doc/openocd.texi index 65b5d65b2..cc7b6b22e 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8423,6 +8423,94 @@ the watchpoint should trigger. The value may be first be masked using @var{mask} to mark ``don't care'' fields. @end deffn + +@section Real Time Transfer (RTT) + +Real Time Transfer (RTT) is an interface specified by SEGGER based on basic +memory reads and writes to transfer data bidirectionally between target and host. +The specification is independent of the target architecture. +Every target that supports so called "background memory access", which means +that the target memory can be accessed by the debugger while the target is +running, can be used. +This interface is especially of interest for targets without +Serial Wire Output (SWO), such as ARM Cortex-M0, or where semihosting is not +applicable because of real-time constraints. + +@quotation Note +The current implementation supports only single target devices. +@end quotation + +The data transfer between host and target device is organized through +unidirectional up/down-channels for target-to-host and host-to-target +communication, respectively. + +@quotation Note +The current implementation does not respect channel buffer flags. +They are used to determine what happens when writing to a full buffer, for +example. +@end quotation + +Channels are exposed via raw TCP/IP connections. One or more RTT servers can be +assigned to each channel to make them accessible to an unlimited number +of TCP/IP connections. + +@deffn Command {rtt setup} address size ID +Configure RTT for the currently selected target. +Once RTT is started, OpenOCD searches for a control block with the +identifier @var{ID} starting at the memory address @var{address} within the next +@var{size} bytes. +@end deffn + +@deffn Command {rtt start} +Start RTT. +If the control block location is not known, OpenOCD starts searching for it. +@end deffn + +@deffn Command {rtt stop} +Stop RTT. +@end deffn + +@deffn Command {rtt polling_interval [interval]} +Display the polling interval. +If @var{interval} is provided, set the polling interval. +The polling interval determines (in milliseconds) how often the up-channels are +checked for new data. +@end deffn + +@deffn Command {rtt channels} +Display a list of all channels and their properties. +@end deffn + +@deffn Command {rtt channellist} +Return a list of all channels and their properties as Tcl list. +The list can be manipulated easily from within scripts. +@end deffn + +@deffn Command {rtt server start} port channel +Start a TCP server on @var{port} for the channel @var{channel}. +@end deffn + +@deffn Command {rtt server stop} port +Stop the TCP sever with port @var{port}. +@end deffn + +The following example shows how to setup RTT using the SEGGER RTT implementation +on the target device. + +@example +resume + +rtt setup 0x20000000 2048 "SEGGER RTT" +rtt start + +rtt server start 9090 0 +@end example + +In this example, OpenOCD searches the control block with the ID "SEGGER RTT" +starting at 0x20000000 for 2048 bytes. The RTT channel 0 is exposed through the +TCP/IP port 9090. + + @section Misc Commands @cindex profiling diff --git a/src/Makefile.am b/src/Makefile.am index 07981aa67..781c1e74f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,8 @@ endif %D%/target/libtarget.la \ %D%/server/libserver.la \ %D%/rtos/librtos.la \ - %D%/helper/libhelper.la + %D%/helper/libhelper.la \ + %D%/rtt/librtt.la BIN2C = $(srcdir)/%D%/helper/bin2char.sh @@ -83,3 +84,4 @@ include %D%/rtos/Makefile.am include %D%/server/Makefile.am include %D%/flash/Makefile.am include %D%/pld/Makefile.am +include %D%/rtt/Makefile.am diff --git a/src/openocd.c b/src/openocd.c index 604b36d21..83c35458b 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -38,9 +38,11 @@ #include #include #include +#include #include #include +#include #ifdef HAVE_STRINGS_H #include @@ -244,6 +246,7 @@ static struct command_context *setup_command_handler(Jim_Interp *interp) &server_register_commands, &gdb_register_commands, &log_register_commands, + &rtt_server_register_commands, &transport_register_commands, &interface_register_commands, &target_register_commands, @@ -335,6 +338,9 @@ int openocd_main(int argc, char *argv[]) if (ioutil_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; + if (rtt_init() != ERROR_OK) + return EXIT_FAILURE; + LOG_OUTPUT("For bug reports, read\n\t" "http://openocd.org/doc/doxygen/bugs.html" "\n"); @@ -364,6 +370,7 @@ int openocd_main(int argc, char *argv[]) /* Shutdown commandline interface */ command_exit(cmd_ctx); + rtt_exit(); free_config(); if (ERROR_FAIL == ret) diff --git a/src/rtt/Makefile.am b/src/rtt/Makefile.am new file mode 100644 index 000000000..e3fcefdbf --- /dev/null +++ b/src/rtt/Makefile.am @@ -0,0 +1,2 @@ +noinst_LTLIBRARIES += %D%/librtt.la +%C%_librtt_la_SOURCES = %D%/rtt.c %D%/rtt.h %D%/tcl.c diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c new file mode 100644 index 000000000..bf3cca51b --- /dev/null +++ b/src/rtt/rtt.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2016-2020 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "rtt.h" + +static struct { + struct rtt_source source; + /** Control block. */ + struct rtt_control ctrl; + struct target *target; + /** Start address to search for the control block. */ + target_addr_t addr; + /** Size of the control block search area. */ + size_t size; + /** Control block identifier. */ + char id[RTT_CB_MAX_ID_LENGTH]; + /** Whether RTT is configured. */ + bool configured; + /** Whether RTT is started. */ + bool started; + /** Whether configuration changed. */ + bool changed; + /** Whether the control block was found. */ + bool found_cb; + + struct rtt_sink_list **sink_list; + size_t sink_list_length; + + unsigned int polling_interval; +} rtt; + +int rtt_init(void) +{ + rtt.sink_list_length = 1; + rtt.sink_list = calloc(rtt.sink_list_length, + sizeof(struct rtt_sink_list *)); + + if (!rtt.sink_list) + return ERROR_FAIL; + + rtt.sink_list[0] = NULL; + rtt.started = false; + + rtt.polling_interval = 100; + + return ERROR_OK; +} + +int rtt_exit(void) +{ + free(rtt.sink_list); + + return ERROR_OK; +} + +static int read_channel_callback(void *user_data) +{ + int ret; + + ret = rtt.source.read(rtt.target, &rtt.ctrl, rtt.sink_list, + rtt.sink_list_length, NULL); + + if (ret != ERROR_OK) { + target_unregister_timer_callback(&read_channel_callback, NULL); + rtt.source.stop(rtt.target, NULL); + return ret; + } + + return ERROR_OK; +} + +int rtt_setup(target_addr_t address, size_t size, const char *id) +{ + size_t id_length = strlen(id); + + if (!id_length || id_length >= RTT_CB_MAX_ID_LENGTH) { + LOG_ERROR("rtt: Invalid control block ID"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + rtt.addr = address; + rtt.size = size; + strncpy(rtt.id, id, id_length + 1); + rtt.changed = true; + rtt.configured = true; + + return ERROR_OK; +} + +int rtt_register_source(const struct rtt_source source, + struct target *target) +{ + if (!source.find_cb || !source.read_cb || !source.read_channel_info) + return ERROR_FAIL; + + if (!source.start || !source.stop) + return ERROR_FAIL; + + if (!source.read || !source.write) + return ERROR_FAIL; + + rtt.source = source; + rtt.target = target; + + return ERROR_OK; +} + +int rtt_start(void) +{ + int ret; + target_addr_t addr = rtt.addr; + + if (rtt.started) + return ERROR_OK; + + if (!rtt.found_cb || rtt.changed) { + rtt.source.find_cb(rtt.target, &addr, rtt.size, rtt.id, + &rtt.found_cb, NULL); + + rtt.changed = false; + + if (rtt.found_cb) { + LOG_INFO("rtt: Control block found at 0x%" TARGET_PRIxADDR, + addr); + rtt.ctrl.address = addr; + } else { + LOG_INFO("rtt: No control block found"); + return ERROR_OK; + } + } + + ret = rtt.source.read_cb(rtt.target, rtt.ctrl.address, &rtt.ctrl, NULL); + + if (ret != ERROR_OK) + return ret; + + ret = rtt.source.start(rtt.target, &rtt.ctrl, NULL); + + if (ret != ERROR_OK) + return ret; + + target_register_timer_callback(&read_channel_callback, + rtt.polling_interval, 1, NULL); + rtt.started = true; + + return ERROR_OK; +} + +int rtt_stop(void) +{ + int ret; + + if (!rtt.configured) { + LOG_ERROR("rtt: Not configured"); + return ERROR_FAIL; + } + + target_unregister_timer_callback(&read_channel_callback, NULL); + rtt.started = false; + + ret = rtt.source.stop(rtt.target, NULL); + + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int adjust_sink_list(size_t length) +{ + struct rtt_sink_list **tmp; + + if (length <= rtt.sink_list_length) + return ERROR_OK; + + tmp = realloc(rtt.sink_list, sizeof(struct rtt_sink_list *) * length); + + if (!tmp) + return ERROR_FAIL; + + for (size_t i = rtt.sink_list_length; i < length; i++) + tmp[i] = NULL; + + rtt.sink_list = tmp; + rtt.sink_list_length = length; + + return ERROR_OK; +} + +int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data) +{ + struct rtt_sink_list *tmp; + + if (channel_index >= rtt.sink_list_length) { + if (adjust_sink_list(channel_index + 1) != ERROR_OK) + return ERROR_FAIL; + } + + LOG_DEBUG("rtt: Registering sink for channel %u", channel_index); + + tmp = malloc(sizeof(struct rtt_sink_list)); + + if (!tmp) + return ERROR_FAIL; + + tmp->read = read; + tmp->user_data = user_data; + tmp->next = rtt.sink_list[channel_index]; + + rtt.sink_list[channel_index] = tmp; + + return ERROR_OK; +} + +int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data) +{ + struct rtt_sink_list *prev_sink; + + LOG_DEBUG("rtt: Unregistering sink for channel %u", channel_index); + + if (channel_index >= rtt.sink_list_length) + return ERROR_FAIL; + + prev_sink = rtt.sink_list[channel_index]; + + for (struct rtt_sink_list *sink = rtt.sink_list[channel_index]; sink; + prev_sink = sink, sink = sink->next) { + if (sink->read == read && sink->user_data == user_data) { + + if (sink == rtt.sink_list[channel_index]) + rtt.sink_list[channel_index] = sink->next; + else + prev_sink->next = sink->next; + + free(sink); + + return ERROR_OK; + } + } + + return ERROR_OK; +} + +int rtt_get_polling_interval(unsigned int *interval) +{ + if (!interval) + return ERROR_FAIL; + + *interval = rtt.polling_interval; + + return ERROR_OK; +} + +int rtt_set_polling_interval(unsigned int interval) +{ + if (!interval) + return ERROR_FAIL; + + if (rtt.polling_interval != interval) { + target_unregister_timer_callback(&read_channel_callback, NULL); + target_register_timer_callback(&read_channel_callback, interval, 1, + NULL); + } + + rtt.polling_interval = interval; + + return ERROR_OK; +} + +int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, + size_t *length) +{ + if (channel_index >= rtt.ctrl.num_up_channels) { + LOG_WARNING("rtt: Down-channel %u is not available", channel_index); + return ERROR_OK; + } + + return rtt.source.write(rtt.target, &rtt.ctrl, channel_index, buffer, + length, NULL); +} + +bool rtt_started(void) +{ + return rtt.started; +} + +bool rtt_configured(void) +{ + return rtt.configured; +} + +bool rtt_found_cb(void) +{ + return rtt.found_cb; +} + +const struct rtt_control *rtt_get_control(void) +{ + return &rtt.ctrl; +} + +int rtt_read_channel_info(unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info) +{ + return rtt.source.read_channel_info(rtt.target, &rtt.ctrl, + channel_index, type, info, NULL); +} diff --git a/src/rtt/rtt.h b/src/rtt/rtt.h new file mode 100644 index 000000000..597c83829 --- /dev/null +++ b/src/rtt/rtt.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016-2020 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OPENOCD_RTT_RTT_H +#define OPENOCD_RTT_RTT_H + +#include +#include + +#include +#include + +/** + * Control block ID length in bytes, including the trailing null-terminator. + */ +#define RTT_CB_MAX_ID_LENGTH 16 + +/* Control block size in bytes. */ +#define RTT_CB_SIZE (RTT_CB_MAX_ID_LENGTH + 2 * sizeof(uint32_t)) + +/* Channel structure size in bytes. */ +#define RTT_CHANNEL_SIZE 24 + +/* Minimal channel buffer size in bytes. */ +#define RTT_CHANNEL_BUFFER_MIN_SIZE 2 + +/** RTT control block. */ +struct rtt_control { + /** Control block address on the target. */ + target_addr_t address; + /** Control block identifier, including trailing null-terminator. */ + char id[RTT_CB_MAX_ID_LENGTH]; + /** Maximum number of up-channels. */ + uint32_t num_up_channels; + /** Maximum number of down-channels. */ + uint32_t num_down_channels; +}; + +/** RTT channel. */ +struct rtt_channel { + /** Channel structure address on the target. */ + target_addr_t address; + /** Channel name address on the target. */ + uint32_t name_addr; + /** Buffer address on the target. */ + uint32_t buffer_addr; + /** Channel buffer size in bytes. */ + uint32_t size; + /** Write position within the buffer in bytes. */ + uint32_t write_pos; + /** Read position within the buffer in bytes. */ + uint32_t read_pos; + /** + * Buffer flags. + * + * @note: Not used at the moment. + */ + uint32_t flags; +}; + +/** RTT channel information. */ +struct rtt_channel_info { + /** Channel name. */ + char *name; + /** Length of the name in bytes, including the trailing null-terminator. */ + size_t name_length; + /** Buffer size in bytes. */ + uint32_t size; + /** + * Buffer flags. + * + * @note: Not used at the moment. + */ + uint32_t flags; +}; + +typedef int (*rtt_sink_read)(unsigned int channel, const uint8_t *buffer, + size_t length, void *user_data); + +struct rtt_sink_list { + rtt_sink_read read; + void *user_data; + + struct rtt_sink_list *next; +}; + +/** Channel type. */ +enum rtt_channel_type { + /** Up channel (target to host). */ + RTT_CHANNEL_TYPE_UP, + /** Down channel (host to target). */ + RTT_CHANNEL_TYPE_DOWN +}; + +typedef int (*rtt_source_find_ctrl_block)(struct target *target, + target_addr_t *address, size_t size, const char *id, bool *found, + void *user_data); +typedef int (*rtt_source_read_ctrl_block)(struct target *target, + target_addr_t address, struct rtt_control *ctrl_block, + void *user_data); +typedef int (*rtt_source_read_channel_info)(struct target *target, + const struct rtt_control *ctrl, unsigned int channel, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data); +typedef int (*rtt_source_start)(struct target *target, + const struct rtt_control *ctrl, void *user_data); +typedef int (*rtt_source_stop)(struct target *target, void *user_data); +typedef int (*rtt_source_read)(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t num_channels, void *user_data); +typedef int (*rtt_source_write)(struct target *target, + struct rtt_control *ctrl, unsigned int channel, + const uint8_t *buffer, size_t *length, void *user_data); + +/** RTT source. */ +struct rtt_source { + rtt_source_find_ctrl_block find_cb; + rtt_source_read_ctrl_block read_cb; + rtt_source_read_channel_info read_channel_info; + rtt_source_start start; + rtt_source_stop stop; + rtt_source_read read; + rtt_source_write write; +}; + +/** + * Initialize Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_init(void); + +/** + * Shutdown Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_exit(void); + +/** + * Register an RTT source for a target. + * + * @param[in] source RTT source. + * @param[in,out] target Target. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_register_source(const struct rtt_source source, + struct target *target); + +/** + * Setup RTT. + * + * @param[in] address Start address to search for the control block. + * @param[in] size Size of the control block search area. + * @param[in] id Identifier of the control block. Must be null-terminated. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_setup(target_addr_t address, size_t size, const char *id); + +/** + * Start Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_start(void); + +/** + * Stop Real-Time Transfer (RTT). + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_stop(void); + +/** + * Get the polling interval. + * + * @param[out] interval Polling interval in milliseconds. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_get_polling_interval(unsigned int *interval); + +/** + * Set the polling interval. + * + * @param[in] interval Polling interval in milliseconds. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_set_polling_interval(unsigned int interval); + +/** + * Get whether RTT is started. + * + * @returns Whether RTT is started. + */ +bool rtt_started(void); + +/** + * Get whether RTT is configured. + * + * @returns Whether RTT is configured. + */ +bool rtt_configured(void); + +/** + * Get whether RTT control block was found. + * + * @returns Whether RTT was found. + */ +bool rtt_found_cb(void); + +/** + * Get the RTT control block. + * + * @returns The RTT control block. + */ +const struct rtt_control *rtt_get_control(void); + +/** + * Read channel information. + * + * @param[in] channel_index Channel index. + * @param[in] channel_type Channel type. + * @param[out] info Channel information. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_read_channel_info(unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info); + +/** + * Register an RTT sink. + * + * @param[in] channel_index Channel index. + * @param[in] read Read callback function. + * @param[in,out] user_data User data to be passed to the callback function. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_register_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data); + +/** + * Unregister an RTT sink. + * + * @param[in] channel_index Channel index. + * @param[in] read Read callback function. + * @param[in,out] user_data User data to be passed to the callback function. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_unregister_sink(unsigned int channel_index, rtt_sink_read read, + void *user_data); + +/** + * Write to an RTT channel. + * + * @param[in] channel_index Channel index. + * @param[in] buffer Buffer with data that should be written to the channel. + * @param[in,out] length Number of bytes to write. On success, the argument gets + * updated with the actual number of written bytes. + * + * @returns ERROR_OK on success, an error code on failure. + */ +int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, + size_t *length); + +extern const struct command_registration rtt_target_command_handlers[]; + +#endif /* OPENOCD_RTT_RTT_H */ diff --git a/src/rtt/tcl.c b/src/rtt/tcl.c new file mode 100644 index 000000000..f5abf2e5e --- /dev/null +++ b/src/rtt/tcl.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2019-2020 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "rtt.h" + +#define CHANNEL_NAME_SIZE 128 + +COMMAND_HANDLER(handle_rtt_setup_command) +{ +struct rtt_source source; + + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + source.find_cb = &target_rtt_find_control_block; + source.read_cb = &target_rtt_read_control_block; + source.start = &target_rtt_start; + source.stop = &target_rtt_stop; + source.read = &target_rtt_read_callback; + source.write = &target_rtt_write_callback; + source.read_channel_info = &target_rtt_read_channel_info; + + target_addr_t address; + uint32_t size; + + COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], size); + + rtt_register_source(source, get_current_target(CMD_CTX)); + + if (rtt_setup(address, size, CMD_ARGV[2]) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_start_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!rtt_configured()) { + command_print(CMD, "RTT is not configured"); + return ERROR_FAIL; + } + + return rtt_start(); +} + +COMMAND_HANDLER(handle_rtt_stop_command) +{ + if (CMD_ARGC > 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + return rtt_stop(); +} + +COMMAND_HANDLER(handle_rtt_polling_interval_command) +{ + if (CMD_ARGC == 0) { + int ret; + unsigned int interval; + + ret = rtt_get_polling_interval(&interval); + + if (ret != ERROR_OK) { + command_print(CMD, "Failed to get polling interval"); + return ret; + } + + command_print(CMD, "%u ms", interval); + } else if (CMD_ARGC == 1) { + int ret; + unsigned int interval; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], interval); + ret = rtt_set_polling_interval(interval); + + if (ret != ERROR_OK) { + command_print(CMD, "Failed to set polling interval"); + return ret; + } + } else { + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_channels_command) +{ + int ret; + char channel_name[CHANNEL_NAME_SIZE]; + const struct rtt_control *ctrl; + struct rtt_channel_info info; + + if (!rtt_found_cb()) { + command_print(CMD, "rtt: Control block not available"); + return ERROR_FAIL; + } + + ctrl = rtt_get_control(); + + command_print(CMD, "Channels: up=%u, down=%u", ctrl->num_up_channels, + ctrl->num_down_channels); + + command_print(CMD, "Up-channels:"); + + info.name = channel_name; + info.name_length = sizeof(channel_name); + + for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + info.flags); + } + + command_print(CMD, "Down-channels:"); + + for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + command_print(CMD, "%u: %s %u %u", i, info.name, info.size, + info.flags); + } + + return ERROR_OK; +} + +static int jim_channel_list(Jim_Interp *interp, int argc, + Jim_Obj * const *argv) +{ + Jim_Obj *list; + Jim_Obj *channel_list; + char channel_name[CHANNEL_NAME_SIZE]; + const struct rtt_control *ctrl; + struct rtt_channel_info info; + + if (!rtt_found_cb()) { + Jim_SetResultFormatted(interp, "rtt: Control block not available"); + return ERROR_FAIL; + } + + ctrl = rtt_get_control(); + + info.name = channel_name; + info.name_length = sizeof(channel_name); + + list = Jim_NewListObj(interp, NULL, 0); + channel_list = Jim_NewListObj(interp, NULL, 0); + + for (unsigned int i = 0; i < ctrl->num_up_channels; i++) { + int ret; + Jim_Obj *tmp; + + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_UP, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + tmp = Jim_NewListObj(interp, NULL, 0); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "name", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + info.name, -1)); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "size", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, + info.size)); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "flags", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, + info.flags)); + + Jim_ListAppendElement(interp, channel_list, tmp); + } + + Jim_ListAppendElement(interp, list, channel_list); + + channel_list = Jim_NewListObj(interp, NULL, 0); + + for (unsigned int i = 0; i < ctrl->num_down_channels; i++) { + int ret; + Jim_Obj *tmp; + + ret = rtt_read_channel_info(i, RTT_CHANNEL_TYPE_DOWN, &info); + + if (ret != ERROR_OK) + return ret; + + if (!info.size) + continue; + + tmp = Jim_NewListObj(interp, NULL, 0); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "name", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + info.name, -1)); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "size", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, + info.size)); + + Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp, + "flags", -1)); + Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp, + info.flags)); + + Jim_ListAppendElement(interp, channel_list, tmp); + } + + Jim_ListAppendElement(interp, list, channel_list); + Jim_SetResult(interp, list); + + return JIM_OK; +} + +static const struct command_registration rtt_subcommand_handlers[] = { + { + .name = "setup", + .handler = handle_rtt_setup_command, + .mode = COMMAND_ANY, + .help = "setup RTT", + .usage = "
" + }, + { + .name = "start", + .handler = handle_rtt_start_command, + .mode = COMMAND_EXEC, + .help = "start RTT", + .usage = "" + }, + { + .name = "stop", + .handler = handle_rtt_stop_command, + .mode = COMMAND_EXEC, + .help = "stop RTT", + .usage = "" + }, + { + .name = "polling_interval", + .handler = handle_rtt_polling_interval_command, + .mode = COMMAND_EXEC, + .help = "show or set polling interval in ms", + .usage = "[interval]" + }, + { + .name = "channels", + .handler = handle_rtt_channels_command, + .mode = COMMAND_EXEC, + .help = "list available channels", + .usage = "" + }, + { + .name = "channellist", + .jim_handler = jim_channel_list, + .mode = COMMAND_EXEC, + .help = "list available channels", + .usage = "" + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration rtt_target_command_handlers[] = { + { + .name = "rtt", + .mode = COMMAND_EXEC, + .help = "RTT target commands", + .usage = "", + .chain = rtt_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/server/Makefile.am b/src/server/Makefile.am index 804efac16..d270ee281 100644 --- a/src/server/Makefile.am +++ b/src/server/Makefile.am @@ -8,7 +8,9 @@ noinst_LTLIBRARIES += %D%/libserver.la %D%/gdb_server.h \ %D%/server_stubs.c \ %D%/tcl_server.c \ - %D%/tcl_server.h + %D%/tcl_server.h \ + %D%/rtt_server.c \ + %D%/rtt_server.h %C%_libserver_la_CFLAGS = $(AM_CFLAGS) if IS_MINGW diff --git a/src/server/rtt_server.c b/src/server/rtt_server.c new file mode 100644 index 000000000..3c885cce0 --- /dev/null +++ b/src/server/rtt_server.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2016-2017 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "server.h" +#include "rtt_server.h" + +/** + * @file + * + * RTT server. + * + * This server allows access to Real Time Transfer (RTT) channels via TCP + * connections. + */ + +struct rtt_service { + unsigned int channel; +}; + +static int read_callback(unsigned int channel, const uint8_t *buffer, + size_t length, void *user_data) +{ + int ret; + struct connection *connection; + size_t offset; + + connection = (struct connection *)user_data; + offset = 0; + + while (offset < length) { + ret = connection_write(connection, buffer + offset, length - offset); + + if (ret < 0) { + LOG_ERROR("Failed to write data to socket."); + return ERROR_FAIL; + } + + offset += ret; + } + + return ERROR_OK; +} + +static int rtt_new_connection(struct connection *connection) +{ + int ret; + struct rtt_service *service; + + service = connection->service->priv; + + LOG_DEBUG("rtt: New connection for channel %u", service->channel); + + ret = rtt_register_sink(service->channel, &read_callback, connection); + + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int rtt_connection_closed(struct connection *connection) +{ + struct rtt_service *service; + + service = (struct rtt_service *)connection->service->priv; + rtt_unregister_sink(service->channel, &read_callback, connection); + + LOG_DEBUG("rtt: Connection for channel %u closed", service->channel); + + return ERROR_OK; +} + +static int rtt_input(struct connection *connection) +{ + int bytes_read; + unsigned char buffer[1024]; + struct rtt_service *service; + size_t length; + + service = (struct rtt_service *)connection->service->priv; + bytes_read = connection_read(connection, buffer, sizeof(buffer)); + + if (!bytes_read) + return ERROR_SERVER_REMOTE_CLOSED; + else if (bytes_read < 0) { + LOG_ERROR("error during read: %s", strerror(errno)); + return ERROR_SERVER_REMOTE_CLOSED; + } + + length = bytes_read; + rtt_write_channel(service->channel, buffer, &length); + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_start_command) +{ + int ret; + struct rtt_service *service; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + service = malloc(sizeof(struct rtt_service)); + + if (!service) + return ERROR_FAIL; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], service->channel); + + ret = add_service("rtt", CMD_ARGV[0], CONNECTION_LIMIT_UNLIMITED, + rtt_new_connection, rtt_input, rtt_connection_closed, service, NULL); + + if (ret != ERROR_OK) { + free(service); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_rtt_stop_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + remove_service("rtt", CMD_ARGV[0]); + + return ERROR_OK; +} + +static const struct command_registration rtt_server_subcommand_handlers[] = { + { + .name = "start", + .handler = handle_rtt_start_command, + .mode = COMMAND_ANY, + .help = "Start a RTT server", + .usage = " " + }, + { + .name = "stop", + .handler = handle_rtt_stop_command, + .mode = COMMAND_ANY, + .help = "Stop a RTT server", + .usage = "" + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rtt_server_command_handlers[] = { + { + .name = "server", + .mode = COMMAND_ANY, + .help = "RTT server", + .usage = "", + .chain = rtt_server_subcommand_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration rtt_command_handlers[] = { + { + .name = "rtt", + .mode = COMMAND_ANY, + .help = "RTT", + .usage = "", + .chain = rtt_server_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +int rtt_server_register_commands(struct command_context *ctx) +{ + return register_commands(ctx, NULL, rtt_command_handlers); +} diff --git a/src/server/rtt_server.h b/src/server/rtt_server.h new file mode 100644 index 000000000..aec6f2222 --- /dev/null +++ b/src/server/rtt_server.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016-2017 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OPENOCD_SERVER_RTT_SERVER_H +#define OPENOCD_SERVER_RTT_SERVER_H + +#include + +int rtt_server_register_commands(struct command_context *ctx); + +#endif /* OPENOCD_SERVER_RTT_SERVER_H */ diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 19ba7714e..1d30747b6 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -48,7 +48,8 @@ TARGET_CORE_SRC = \ %D%/target_request.c \ %D%/testee.c \ %D%/semihosting_common.c \ - %D%/smp.c + %D%/smp.c \ + %D%/rtt.c ARMV4_5_SRC = \ %D%/armv4_5.c \ @@ -259,7 +260,8 @@ ARC_SRC = \ %D%/arc.h \ %D%/arc_cmd.h \ %D%/arc_jtag.h \ - %D%/arc_mem.h + %D%/arc_mem.h \ + %D%/rtt.h include %D%/openrisc/Makefile.am include %D%/riscv/Makefile.am diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index fae2aac5d..316089c35 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -39,6 +39,7 @@ #include "arm_opcodes.h" #include "arm_semihosting.h" #include +#include /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. @@ -2489,6 +2490,9 @@ static const struct command_registration cortex_m_command_handlers[] = { .usage = "", .chain = cortex_m_exec_command_handlers, }, + { + .chain = rtt_target_command_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index 99afccc49..3d41387fd 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -39,6 +39,7 @@ #include "cortex_m.h" #include "arm_semihosting.h" #include "target_request.h" +#include #define savedDCRDR dbgbase /* FIXME: using target->dbgbase to preserve DCRDR */ @@ -626,6 +627,9 @@ static const struct command_registration adapter_command_handlers[] = { { .chain = armv7m_trace_command_handlers, }, + { + .chain = rtt_target_command_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/rtt.c b/src/target/rtt.c new file mode 100644 index 000000000..7e556e1cb --- /dev/null +++ b/src/target/rtt.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2016-2020 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "target.h" + +static int read_rtt_channel(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel *channel) +{ + int ret; + uint8_t buf[RTT_CHANNEL_SIZE]; + target_addr_t address; + + address = ctrl->address + RTT_CB_SIZE + (channel_index * RTT_CHANNEL_SIZE); + + if (type == RTT_CHANNEL_TYPE_DOWN) + address += ctrl->num_up_channels * RTT_CHANNEL_SIZE; + + ret = target_read_buffer(target, address, RTT_CHANNEL_SIZE, buf); + + if (ret != ERROR_OK) + return ret; + + channel->address = address; + channel->name_addr = buf_get_u32(buf + 0, 0, 32); + channel->buffer_addr = buf_get_u32(buf + 4, 0, 32); + channel->size = buf_get_u32(buf + 8, 0, 32); + channel->write_pos = buf_get_u32(buf + 12, 0, 32); + channel->read_pos = buf_get_u32(buf + 16, 0, 32); + channel->flags = buf_get_u32(buf + 20, 0, 32); + + return ERROR_OK; +} + +int target_rtt_start(struct target *target, const struct rtt_control *ctrl, + void *user_data) +{ + return ERROR_OK; +} + +int target_rtt_stop(struct target *target, void *user_data) +{ + return ERROR_OK; +} + +static int read_channel_name(struct target *target, target_addr_t address, + char *name, size_t length) +{ + size_t offset; + + offset = 0; + + while (offset < length) { + int ret; + size_t read_length; + + read_length = MIN(32, length - offset); + ret = target_read_buffer(target, address + offset, read_length, + (uint8_t *)name + offset); + + if (ret != ERROR_OK) + return ret; + + if (memchr(name + offset, '\0', read_length)) + return ERROR_OK; + + offset += read_length; + } + + name[length - 1] = '\0'; + + return ERROR_OK; +} + +static int write_to_channel(struct target *target, + const struct rtt_channel *channel, const uint8_t *buffer, + size_t *length) +{ + int ret; + uint32_t len; + + if (!*length) + return ERROR_OK; + + if (channel->write_pos == channel->read_pos) { + uint32_t first_length; + + len = MIN(*length, channel->size - 1); + first_length = MIN(len, channel->size - channel->write_pos); + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, first_length, + buffer); + + if (ret != ERROR_OK) + return ret; + + ret = target_write_buffer(target, channel->buffer_addr, + len - first_length, buffer + first_length); + + if (ret != ERROR_OK) + return ret; + } else if (channel->write_pos < channel->read_pos) { + len = MIN(*length, channel->read_pos - channel->write_pos - 1); + + if (!len) { + *length = 0; + return ERROR_OK; + } + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, len, buffer); + + if (ret != ERROR_OK) + return ret; + } else { + uint32_t first_length; + + len = MIN(*length, + channel->size - channel->write_pos + channel->read_pos - 1); + + if (!len) { + *length = 0; + return ERROR_OK; + } + + first_length = MIN(len, channel->size - channel->write_pos); + + ret = target_write_buffer(target, + channel->buffer_addr + channel->write_pos, first_length, + buffer); + + if (ret != ERROR_OK) + return ret; + + buffer = buffer + first_length; + + ret = target_write_buffer(target, channel->buffer_addr, + len - first_length, buffer); + + if (ret != ERROR_OK) + return ret; + } + + ret = target_write_u32(target, channel->address + 12, + (channel->write_pos + len) % channel->size); + + if (ret != ERROR_OK) + return ret; + + *length = len; + + return ERROR_OK; +} + +static bool channel_is_active(const struct rtt_channel *channel) +{ + if (!channel) + return false; + + if (!channel->size) + return false; + + return true; +} + +int target_rtt_write_callback(struct target *target, struct rtt_control *ctrl, + unsigned int channel_index, const uint8_t *buffer, size_t *length, + void *user_data) +{ + int ret; + struct rtt_channel channel; + + ret = read_rtt_channel(target, ctrl, channel_index, + RTT_CHANNEL_TYPE_DOWN, &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read down-channel %u description", + channel_index); + return ret; + } + + if (!channel_is_active(&channel)) { + LOG_WARNING("rtt: Down-channel %u is not active", channel_index); + return ERROR_OK; + } + + if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { + LOG_WARNING("rtt: Down-channel %u is not large enough", + channel_index); + return ERROR_OK; + } + + ret = write_to_channel(target, &channel, buffer, length); + + if (ret != ERROR_OK) + return ret; + + LOG_DEBUG("rtt: Wrote %zu bytes into down-channel %u", *length, + channel_index); + + return ERROR_OK; +} + +int target_rtt_read_control_block(struct target *target, + target_addr_t address, struct rtt_control *ctrl, void *user_data) +{ + int ret; + uint8_t buf[RTT_CB_SIZE]; + + ret = target_read_buffer(target, address, RTT_CB_SIZE, buf); + + if (ret != ERROR_OK) + return ret; + + memcpy(ctrl->id, buf, RTT_CB_MAX_ID_LENGTH); + ctrl->id[RTT_CB_MAX_ID_LENGTH - 1] = '\0'; + ctrl->num_up_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 0, + 0, 32); + ctrl->num_down_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 4, + 0, 32); + + return ERROR_OK; +} + +int target_rtt_find_control_block(struct target *target, + target_addr_t *address, size_t size, const char *id, bool *found, + void *user_data) +{ + uint8_t buf[1024]; + + *found = false; + + size_t j = 0; + size_t cb_offset = 0; + const size_t id_length = strlen(id); + + LOG_INFO("rtt: Searching for control block '%s'", id); + + for (target_addr_t addr = 0; addr < size; addr = addr + sizeof(buf)) { + int ret; + + const size_t buf_size = MIN(sizeof(buf), size - addr); + ret = target_read_buffer(target, *address + addr, buf_size, buf); + + if (ret != ERROR_OK) + return ret; + + size_t start = 0; + size_t i = 0; + + while (i < buf_size) { + if (buf[i] != id[j]) { + start++; + cb_offset++; + i = start; + j = 0; + + continue; + } + + i++; + j++; + + if (j == id_length) { + *address = *address + cb_offset; + *found = true; + return ERROR_OK; + } + } + } + + return ERROR_OK; +} + +int target_rtt_read_channel_info(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data) +{ + int ret; + struct rtt_channel channel; + + ret = read_rtt_channel(target, ctrl, channel_index, type, &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read channel %u description", + channel_index); + return ret; + } + + ret = read_channel_name(target, channel.name_addr, info->name, + info->name_length); + + if (ret != ERROR_OK) + return ret; + + info->size = channel.size; + info->flags = channel.flags; + + return ERROR_OK; +} + +static int read_from_channel(struct target *target, + const struct rtt_channel *channel, uint8_t *buffer, + size_t *length) +{ + int ret; + uint32_t len; + + if (!*length) + return ERROR_OK; + + if (channel->read_pos == channel->write_pos) { + len = 0; + } else if (channel->read_pos < channel->write_pos) { + len = MIN(*length, channel->write_pos - channel->read_pos); + + ret = target_read_buffer(target, + channel->buffer_addr + channel->read_pos, len, buffer); + + if (ret != ERROR_OK) + return ret; + } else { + uint32_t first_length; + + len = MIN(*length, + channel->size - channel->read_pos + channel->write_pos); + first_length = MIN(len, channel->size - channel->read_pos); + + ret = target_read_buffer(target, + channel->buffer_addr + channel->read_pos, first_length, buffer); + + if (ret != ERROR_OK) + return ret; + + ret = target_read_buffer(target, channel->buffer_addr, + len - first_length, buffer + first_length); + + if (ret != ERROR_OK) + return ret; + } + + if (len > 0) { + ret = target_write_u32(target, channel->address + 16, + (channel->read_pos + len) % channel->size); + + if (ret != ERROR_OK) + return ret; + } + + *length = len; + + return ERROR_OK; +} + +int target_rtt_read_callback(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t num_channels, void *user_data) +{ + num_channels = MIN(num_channels, ctrl->num_up_channels); + + for (size_t i = 0; i < num_channels; i++) { + int ret; + struct rtt_channel channel; + uint8_t buffer[1024]; + size_t length; + + if (!sinks[i]) + continue; + + ret = read_rtt_channel(target, ctrl, i, RTT_CHANNEL_TYPE_UP, + &channel); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read up-channel %zu description", i); + return ret; + } + + if (!channel_is_active(&channel)) { + LOG_WARNING("rtt: Up-channel %zu is not active", i); + continue; + } + + if (channel.size < RTT_CHANNEL_BUFFER_MIN_SIZE) { + LOG_WARNING("rtt: Up-channel %zu is not large enough", i); + continue; + } + + length = sizeof(buffer); + ret = read_from_channel(target, &channel, buffer, &length); + + if (ret != ERROR_OK) { + LOG_ERROR("rtt: Failed to read from up-channel %zu", i); + return ret; + } + + for (struct rtt_sink_list *sink = sinks[i]; sink; sink = sink->next) + sink->read(i, buffer, length, sink->user_data); + } + + return ERROR_OK; +} diff --git a/src/target/rtt.h b/src/target/rtt.h new file mode 100644 index 000000000..01224750f --- /dev/null +++ b/src/target/rtt.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016-2020 by Marc Schink + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef OPENOCD_TARGET_RTT_H +#define OPENOCD_TARGET_RTT_H + +#include +#include + +#include +#include + +int target_rtt_start(struct target *target, const struct rtt_control *ctrl, + void *user_data); +int target_rtt_stop(struct target *target, void *user_data); +int target_rtt_find_control_block(struct target *target, + target_addr_t *address, size_t size, const char *id, bool *found, + void *user_data); +int target_rtt_read_control_block(struct target *target, + target_addr_t address, struct rtt_control *ctrl, void *user_data); +int target_rtt_write_callback(struct target *target, + struct rtt_control *ctrl, unsigned int channel_index, + const uint8_t *buffer, size_t *length, void *user_data); +int target_rtt_read_callback(struct target *target, + const struct rtt_control *ctrl, struct rtt_sink_list **sinks, + size_t length, void *user_data); +int target_rtt_read_channel_info(struct target *target, + const struct rtt_control *ctrl, unsigned int channel_index, + enum rtt_channel_type type, struct rtt_channel_info *info, + void *user_data); + +#endif /* OPENOCD_TARGET_RTT_H */ From ba58d90f6fed652d94c8c6262a43e1d836241e00 Mon Sep 17 00:00:00 2001 From: Boran Car Date: Fri, 21 Jun 2019 18:42:17 +0100 Subject: [PATCH 092/113] jep106: Add new IDs from JEDEC From JEP106AZ, released on May 24, 2019. Change-Id: I768b7077ec6abcd19ae1530b5715c7ea993add67 Signed-off-by: Boran Car Reviewed-on: http://openocd.zylin.com/5244 Tested-by: jenkins Reviewed-by: Jonathan McDowell Reviewed-by: Tarek BOCHKATI Reviewed-by: Tomas Vanek Reviewed-by: Jiri Kastner Reviewed-by: Antonio Borneo --- src/helper/jep106.inc | 746 ++++++++++++++++++++++++++++-------------- 1 file changed, 503 insertions(+), 243 deletions(-) diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index c0295a603..76e6137be 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -1,4 +1,9 @@ -/* Autogenerated with update_jep106.pl*/ +/* + * Should be autogenerated with update_jep106.pl but latest + * file from JEDEC is only available in PDF form. The PDF + * also breaks the pdftotext flow due to embedded watermarks. + * Created with a mix of scripts and manual editing. + */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", [0][0x03 - 1] = "Fairchild", @@ -40,7 +45,7 @@ [0][0x27 - 1] = "Intl. CMOS Technology", [0][0x28 - 1] = "SSSI", [0][0x29 - 1] = "MicrochipTechnology", -[0][0x2a - 1] = "Ricoh Ltd.", +[0][0x2a - 1] = "Ricoh Ltd", [0][0x2b - 1] = "VLSI", [0][0x2c - 1] = "Micron Technology", [0][0x2d - 1] = "SK Hynix", @@ -67,7 +72,7 @@ [0][0x42 - 1] = "Macronix", [0][0x43 - 1] = "Xerox", [0][0x44 - 1] = "Plus Logic", -[0][0x45 - 1] = "SanDisk Corporation", +[0][0x45 - 1] = "Western Digital Technologies Inc", [0][0x46 - 1] = "Elan Circuit Tech.", [0][0x47 - 1] = "European Silicon Str.", [0][0x48 - 1] = "Apple Computer", @@ -142,7 +147,7 @@ [1][0x0f - 1] = "Robert Bosch", [1][0x10 - 1] = "Chip Express", [1][0x11 - 1] = "DATARAM", -[1][0x12 - 1] = "United Microelectronics Corp.", +[1][0x12 - 1] = "United Microelectronics Corp", [1][0x13 - 1] = "TCSI", [1][0x14 - 1] = "Smart Modular", [1][0x15 - 1] = "Hughes Aircraft", @@ -156,7 +161,7 @@ [1][0x1d - 1] = "Integrated Silicon Solution (ISSI)", [1][0x1e - 1] = "DoD", [1][0x1f - 1] = "Integ. Memories Tech.", -[1][0x20 - 1] = "Corollary Inc.", +[1][0x20 - 1] = "Corollary Inc", [1][0x21 - 1] = "Dallas Semiconductor", [1][0x22 - 1] = "Omnivision", [1][0x23 - 1] = "EIV(Switzerland)", @@ -171,18 +176,18 @@ [1][0x2c - 1] = "Celestica", [1][0x2d - 1] = "Century", [1][0x2e - 1] = "Hal Computers", -[1][0x2f - 1] = "Rohm Company Ltd.", +[1][0x2f - 1] = "Rohm Company Ltd", [1][0x30 - 1] = "Juniper Networks", [1][0x31 - 1] = "Libit Signal Processing", [1][0x32 - 1] = "Mushkin Enhanced Memory", [1][0x33 - 1] = "Tundra Semiconductor", -[1][0x34 - 1] = "Adaptec Inc.", +[1][0x34 - 1] = "Adaptec Inc", [1][0x35 - 1] = "LightSpeed Semi.", -[1][0x36 - 1] = "ZSP Corp.", +[1][0x36 - 1] = "ZSP Corp", [1][0x37 - 1] = "AMIC Technology", [1][0x38 - 1] = "Adobe Systems", [1][0x39 - 1] = "Dynachip", -[1][0x3a - 1] = "PNY Technologies, Inc.", +[1][0x3a - 1] = "PNY Technologies Inc", [1][0x3b - 1] = "Newport Digital", [1][0x3c - 1] = "MMC Networks", [1][0x3d - 1] = "T Square", @@ -194,8 +199,8 @@ [1][0x43 - 1] = "Suwa Electronics", [1][0x44 - 1] = "Transmeta", [1][0x45 - 1] = "Micron CMS", -[1][0x46 - 1] = "American Computer & Digital", -[1][0x47 - 1] = "Enhance 3000 Inc.", +[1][0x46 - 1] = "American Computer & Digital Components Inc", +[1][0x47 - 1] = "Enhance 3000 Inc", [1][0x48 - 1] = "Tower Semiconductor", [1][0x49 - 1] = "CPU Design", [1][0x4a - 1] = "Price Point", @@ -205,19 +210,19 @@ [1][0x4e - 1] = "Unigen Corporation", [1][0x4f - 1] = "Transcend Information", [1][0x50 - 1] = "Memory Card Technology", -[1][0x51 - 1] = "CKD Corporation Ltd.", -[1][0x52 - 1] = "Capital Instruments, Inc.", -[1][0x53 - 1] = "Aica Kogyo, Ltd.", +[1][0x51 - 1] = "CKD Corporation Ltd", +[1][0x52 - 1] = "Capital Instruments Inc", +[1][0x53 - 1] = "Aica Kogyo Ltd", [1][0x54 - 1] = "Linvex Technology", [1][0x55 - 1] = "MSC Vertriebs GmbH", -[1][0x56 - 1] = "AKM Company, Ltd.", -[1][0x57 - 1] = "Dynamem, Inc.", +[1][0x56 - 1] = "AKM Company Ltd", +[1][0x57 - 1] = "Dynamem Inc", [1][0x58 - 1] = "NERA ASA", [1][0x59 - 1] = "GSI Technology", [1][0x5a - 1] = "Dane-Elec (C Memory)", [1][0x5b - 1] = "Acorn Computers", [1][0x5c - 1] = "Lara Technology", -[1][0x5d - 1] = "Oak Technology, Inc.", +[1][0x5d - 1] = "Oak Technology Inc", [1][0x5e - 1] = "Itec Memory", [1][0x5f - 1] = "Tanisys Technology", [1][0x60 - 1] = "Truevision", @@ -234,7 +239,7 @@ [1][0x6b - 1] = "Goldenram", [1][0x6c - 1] = "Clear Logic", [1][0x6d - 1] = "Cimaron Communications", -[1][0x6e - 1] = "Nippon Steel Semi. Corp.", +[1][0x6e - 1] = "Nippon Steel Semi. Corp", [1][0x6f - 1] = "Advantage Memory", [1][0x70 - 1] = "AMCC", [1][0x71 - 1] = "LeCroy", @@ -245,7 +250,7 @@ [1][0x76 - 1] = "Advanced Fibre", [1][0x77 - 1] = "BF Goodrich Data.", [1][0x78 - 1] = "Epigram", -[1][0x79 - 1] = "Acbel Polytech Inc.", +[1][0x79 - 1] = "Acbel Polytech Inc", [1][0x7a - 1] = "Apacer Technology", [1][0x7b - 1] = "Admor Memory", [1][0x7c - 1] = "FOXCONN", @@ -260,7 +265,7 @@ [2][0x07 - 1] = "MOSAID Technologies", [2][0x08 - 1] = "Ardent Technologies", [2][0x09 - 1] = "Switchcore", -[2][0x0a - 1] = "Cisco Systems, Inc.", +[2][0x0a - 1] = "Cisco Systems Inc", [2][0x0b - 1] = "Allayer Technologies", [2][0x0c - 1] = "WorkX AG (Wichman)", [2][0x0d - 1] = "Oasis Semiconductor", @@ -281,9 +286,9 @@ [2][0x1c - 1] = "Sanmina Corporation", [2][0x1d - 1] = "HADCO Corporation", [2][0x1e - 1] = "Corsair", -[2][0x1f - 1] = "Actrans System Inc.", +[2][0x1f - 1] = "Actrans System Inc", [2][0x20 - 1] = "ALPHA Technologies", -[2][0x21 - 1] = "Silicon Laboratories, Inc. (Cygnal)", +[2][0x21 - 1] = "Silicon Laboratories Inc (Cygnal)", [2][0x22 - 1] = "Artesyn Technologies", [2][0x23 - 1] = "Align Manufacturing", [2][0x24 - 1] = "Peregrine Semiconductor", @@ -300,7 +305,7 @@ [2][0x2f - 1] = "Siemens AG", [2][0x30 - 1] = "Sarnoff Corporation", [2][0x31 - 1] = "Itautec SA", -[2][0x32 - 1] = "Radiata Inc.", +[2][0x32 - 1] = "Radiata Inc", [2][0x33 - 1] = "Benchmark Elect. (AVEX)", [2][0x34 - 1] = "Legend", [2][0x35 - 1] = "SpecTek Incorporated", @@ -330,7 +335,7 @@ [2][0x4d - 1] = "Element 14", [2][0x4e - 1] = "Pycon", [2][0x4f - 1] = "Saifun Semiconductors", -[2][0x50 - 1] = "Sibyte, Incorporated", +[2][0x50 - 1] = "Sibyte Incorporated", [2][0x51 - 1] = "MetaLink Technologies", [2][0x52 - 1] = "Feiya Technology", [2][0x53 - 1] = "I & C Technology", @@ -438,7 +443,7 @@ [3][0x3b - 1] = "Concept Computer", [3][0x3c - 1] = "SILCOM", [3][0x3d - 1] = "3Dlabs", -[3][0x3e - 1] = "c’t Magazine", +[3][0x3e - 1] = "c't Magazine", [3][0x3f - 1] = "Sanera Systems", [3][0x40 - 1] = "Silicon Packets", [3][0x41 - 1] = "Viasystems Group", @@ -470,7 +475,7 @@ [3][0x5b - 1] = "Nazomi Communications", [3][0x5c - 1] = "eWave System", [3][0x5d - 1] = "Rockwell Collins", -[3][0x5e - 1] = "Picocel Co. Ltd. (Paion)", +[3][0x5e - 1] = "Picocel Co Ltd (Paion)", [3][0x5f - 1] = "Alphamosaic Ltd", [3][0x60 - 1] = "Sandburst", [3][0x61 - 1] = "SiCon Video", @@ -521,20 +526,20 @@ [4][0x10 - 1] = "Scaleo Chip", [4][0x11 - 1] = "Potentia Power Systems", [4][0x12 - 1] = "C-guys Incorporated", -[4][0x13 - 1] = "Digital Communications Technology", +[4][0x13 - 1] = "Digital Communications Technology Inc", [4][0x14 - 1] = "Silicon-Based Technology", [4][0x15 - 1] = "Fulcrum Microsystems", [4][0x16 - 1] = "Positivo Informatica Ltd", [4][0x17 - 1] = "XIOtech Corporation", [4][0x18 - 1] = "PortalPlayer", [4][0x19 - 1] = "Zhiying Software", -[4][0x1a - 1] = "ParkerVision, Inc.", +[4][0x1a - 1] = "ParkerVision Inc", [4][0x1b - 1] = "Phonex Broadband", [4][0x1c - 1] = "Skyworks Solutions", [4][0x1d - 1] = "Entropic Communications", -[4][0x1e - 1] = "I’M Intelligent Memory Ltd.", +[4][0x1e - 1] = "I'M Intelligent Memory Ltd", [4][0x1f - 1] = "Zensys A/S", -[4][0x20 - 1] = "Legend Silicon Corp.", +[4][0x20 - 1] = "Legend Silicon Corp", [4][0x21 - 1] = "Sci-worx GmbH", [4][0x22 - 1] = "SMSC (Standard Microsystems)", [4][0x23 - 1] = "Renesas Electronics", @@ -543,7 +548,7 @@ [4][0x26 - 1] = "MediaTek", [4][0x27 - 1] = "Non-cents Productions", [4][0x28 - 1] = "US Modular", -[4][0x29 - 1] = "Wintegra Ltd.", +[4][0x29 - 1] = "Wintegra Ltd", [4][0x2a - 1] = "Mathstar", [4][0x2b - 1] = "StarCore", [4][0x2c - 1] = "Oplus Technologies", @@ -559,9 +564,9 @@ [4][0x36 - 1] = "SolusTek", [4][0x37 - 1] = "Kongsberg Maritime", [4][0x38 - 1] = "Faraday Technology", -[4][0x39 - 1] = "Altium Ltd.", +[4][0x39 - 1] = "Altium Ltd", [4][0x3a - 1] = "Insyte", -[4][0x3b - 1] = "ARM Ltd.", +[4][0x3b - 1] = "ARM Ltd", [4][0x3c - 1] = "DigiVision", [4][0x3d - 1] = "Vativ Technologies", [4][0x3e - 1] = "Endicott Interconnect Technologies", @@ -583,7 +588,7 @@ [4][0x4e - 1] = "Quanta Computer", [4][0x4f - 1] = "Yield Microelectronics", [4][0x50 - 1] = "Afa Technologies", -[4][0x51 - 1] = "KINGBOX Technology Co. Ltd.", +[4][0x51 - 1] = "KINGBOX Technology Co Ltd", [4][0x52 - 1] = "Ceva", [4][0x53 - 1] = "iStor Networks", [4][0x54 - 1] = "Advance Modules", @@ -598,149 +603,149 @@ [4][0x5d - 1] = "Adimos", [4][0x5e - 1] = "SiGe Semiconductor", [4][0x5f - 1] = "Fodus Communications", -[4][0x60 - 1] = "Credence Systems Corp.", -[4][0x61 - 1] = "Genesis Microchip Inc.", -[4][0x62 - 1] = "Vihana, Inc.", +[4][0x60 - 1] = "Credence Systems Corp", +[4][0x61 - 1] = "Genesis Microchip Inc", +[4][0x62 - 1] = "Vihana Inc", [4][0x63 - 1] = "WIS Technologies", [4][0x64 - 1] = "GateChange Technologies", [4][0x65 - 1] = "High Density Devices AS", [4][0x66 - 1] = "Synopsys", [4][0x67 - 1] = "Gigaram", -[4][0x68 - 1] = "Enigma Semiconductor Inc.", -[4][0x69 - 1] = "Century Micro Inc.", +[4][0x68 - 1] = "Enigma Semiconductor Inc", +[4][0x69 - 1] = "Century Micro Inc", [4][0x6a - 1] = "Icera Semiconductor", [4][0x6b - 1] = "Mediaworks Integrated Systems", -[4][0x6c - 1] = "O’Neil Product Development", -[4][0x6d - 1] = "Supreme Top Technology Ltd.", +[4][0x6c - 1] = "O'Neil Product Development", +[4][0x6d - 1] = "Supreme Top Technology Ltd", [4][0x6e - 1] = "MicroDisplay Corporation", -[4][0x6f - 1] = "Team Group Inc.", +[4][0x6f - 1] = "Team Group Inc", [4][0x70 - 1] = "Sinett Corporation", [4][0x71 - 1] = "Toshiba Corporation", [4][0x72 - 1] = "Tensilica", [4][0x73 - 1] = "SiRF Technology", -[4][0x74 - 1] = "Bacoc Inc.", +[4][0x74 - 1] = "Bacoc Inc", [4][0x75 - 1] = "SMaL Camera Technologies", [4][0x76 - 1] = "Thomson SC", [4][0x77 - 1] = "Airgo Networks", -[4][0x78 - 1] = "Wisair Ltd.", +[4][0x78 - 1] = "Wisair Ltd", [4][0x79 - 1] = "SigmaTel", [4][0x7a - 1] = "Arkados", -[4][0x7b - 1] = "Compete IT gmbH Co. KG", -[4][0x7c - 1] = "Eudar Technology Inc.", +[4][0x7b - 1] = "Compete IT gmbH Co KG", +[4][0x7c - 1] = "Eudar Technology Inc", [4][0x7d - 1] = "Focus Enhancements", [4][0x7e - 1] = "Xyratex", [5][0x01 - 1] = "Specular Networks", [5][0x02 - 1] = "Patriot Memory (PDP Systems)", -[5][0x03 - 1] = "U-Chip Technology Corp.", +[5][0x03 - 1] = "U-Chip Technology Corp", [5][0x04 - 1] = "Silicon Optix", [5][0x05 - 1] = "Greenfield Networks", [5][0x06 - 1] = "CompuRAM GmbH", -[5][0x07 - 1] = "Stargen, Inc.", +[5][0x07 - 1] = "Stargen Inc", [5][0x08 - 1] = "NetCell Corporation", [5][0x09 - 1] = "Excalibrus Technologies Ltd", [5][0x0a - 1] = "SCM Microsystems", -[5][0x0b - 1] = "Xsigo Systems, Inc.", +[5][0x0b - 1] = "Xsigo Systems Inc", [5][0x0c - 1] = "CHIPS & Systems Inc", [5][0x0d - 1] = "Tier 1 Multichip Solutions", [5][0x0e - 1] = "CWRL Labs", [5][0x0f - 1] = "Teradici", -[5][0x10 - 1] = "Gigaram, Inc.", +[5][0x10 - 1] = "Gigaram Inc", [5][0x11 - 1] = "g2 Microsystems", [5][0x12 - 1] = "PowerFlash Semiconductor", -[5][0x13 - 1] = "P.A. Semi, Inc.", -[5][0x14 - 1] = "NovaTech Solutions, S.A.", -[5][0x15 - 1] = "c2 Microsystems, Inc.", +[5][0x13 - 1] = "P.A. Semi Inc", +[5][0x14 - 1] = "NovaTech Solutions S.A.", +[5][0x15 - 1] = "c2 Microsystems Inc", [5][0x16 - 1] = "Level5 Networks", [5][0x17 - 1] = "COS Memory AG", [5][0x18 - 1] = "Innovasic Semiconductor", -[5][0x19 - 1] = "02IC Co. Ltd", -[5][0x1a - 1] = "Tabula, Inc.", +[5][0x19 - 1] = "02IC Co Ltd", +[5][0x1a - 1] = "Tabula Inc", [5][0x1b - 1] = "Crucial Technology", [5][0x1c - 1] = "Chelsio Communications", [5][0x1d - 1] = "Solarflare Communications", -[5][0x1e - 1] = "Xambala Inc.", +[5][0x1e - 1] = "Xambala Inc", [5][0x1f - 1] = "EADS Astrium", -[5][0x20 - 1] = "Terra Semiconductor, Inc.", -[5][0x21 - 1] = "Imaging Works, Inc.", -[5][0x22 - 1] = "Astute Networks, Inc.", +[5][0x20 - 1] = "Terra Semiconductor Inc", +[5][0x21 - 1] = "Imaging Works Inc", +[5][0x22 - 1] = "Astute Networks Inc", [5][0x23 - 1] = "Tzero", [5][0x24 - 1] = "Emulex", [5][0x25 - 1] = "Power-One", -[5][0x26 - 1] = "Pulse~LINK Inc.", +[5][0x26 - 1] = "Pulse~LINK Inc", [5][0x27 - 1] = "Hon Hai Precision Industry", -[5][0x28 - 1] = "White Rock Networks Inc.", -[5][0x29 - 1] = "Telegent Systems USA, Inc.", -[5][0x2a - 1] = "Atrua Technologies, Inc.", -[5][0x2b - 1] = "Acbel Polytech Inc.", -[5][0x2c - 1] = "eRide Inc.", -[5][0x2d - 1] = "ULi Electronics Inc.", -[5][0x2e - 1] = "Magnum Semiconductor Inc.", -[5][0x2f - 1] = "neoOne Technology, Inc.", -[5][0x30 - 1] = "Connex Technology, Inc.", -[5][0x31 - 1] = "Stream Processors, Inc.", +[5][0x28 - 1] = "White Rock Networks Inc", +[5][0x29 - 1] = "Telegent Systems USA Inc", +[5][0x2a - 1] = "Atrua Technologies Inc", +[5][0x2b - 1] = "Acbel Polytech Inc", +[5][0x2c - 1] = "eRide Inc", +[5][0x2d - 1] = "ULi Electronics Inc", +[5][0x2e - 1] = "Magnum Semiconductor Inc", +[5][0x2f - 1] = "neoOne Technology Inc", +[5][0x30 - 1] = "Connex Technology Inc", +[5][0x31 - 1] = "Stream Processors Inc", [5][0x32 - 1] = "Focus Enhancements", -[5][0x33 - 1] = "Telecis Wireless, Inc.", +[5][0x33 - 1] = "Telecis Wireless Inc", [5][0x34 - 1] = "uNav Microelectronics", -[5][0x35 - 1] = "Tarari, Inc.", -[5][0x36 - 1] = "Ambric, Inc.", -[5][0x37 - 1] = "Newport Media, Inc.", +[5][0x35 - 1] = "Tarari Inc", +[5][0x36 - 1] = "Ambric Inc", +[5][0x37 - 1] = "Newport Media Inc", [5][0x38 - 1] = "VMTS", -[5][0x39 - 1] = "Enuclia Semiconductor, Inc.", -[5][0x3a - 1] = "Virtium Technology Inc.", -[5][0x3b - 1] = "Solid State System Co., Ltd.", +[5][0x39 - 1] = "Enuclia Semiconductor Inc", +[5][0x3a - 1] = "Virtium Technology Inc", +[5][0x3b - 1] = "Solid State System Co Ltd", [5][0x3c - 1] = "Kian Tech LLC", [5][0x3d - 1] = "Artimi", [5][0x3e - 1] = "Power Quotient International", [5][0x3f - 1] = "Avago Technologies", [5][0x40 - 1] = "ADTechnology", [5][0x41 - 1] = "Sigma Designs", -[5][0x42 - 1] = "SiCortex, Inc.", +[5][0x42 - 1] = "SiCortex Inc", [5][0x43 - 1] = "Ventura Technology Group", [5][0x44 - 1] = "eASIC", [5][0x45 - 1] = "M.H.S. SAS", [5][0x46 - 1] = "Micro Star International", -[5][0x47 - 1] = "Rapport Inc.", +[5][0x47 - 1] = "Rapport Inc", [5][0x48 - 1] = "Makway International", -[5][0x49 - 1] = "Broad Reach Engineering Co.", +[5][0x49 - 1] = "Broad Reach Engineering Co", [5][0x4a - 1] = "Semiconductor Mfg Intl Corp", [5][0x4b - 1] = "SiConnect", -[5][0x4c - 1] = "FCI USA Inc.", +[5][0x4c - 1] = "FCI USA Inc", [5][0x4d - 1] = "Validity Sensors", -[5][0x4e - 1] = "Coney Technology Co. Ltd.", +[5][0x4e - 1] = "Coney Technology Co Ltd", [5][0x4f - 1] = "Spans Logic", -[5][0x50 - 1] = "Neterion Inc.", +[5][0x50 - 1] = "Neterion Inc", [5][0x51 - 1] = "Qimonda", -[5][0x52 - 1] = "New Japan Radio Co. Ltd.", +[5][0x52 - 1] = "New Japan Radio Co Ltd", [5][0x53 - 1] = "Velogix", [5][0x54 - 1] = "Montalvo Systems", -[5][0x55 - 1] = "iVivity Inc.", +[5][0x55 - 1] = "iVivity Inc", [5][0x56 - 1] = "Walton Chaintech", [5][0x57 - 1] = "AENEON", -[5][0x58 - 1] = "Lorom Industrial Co. Ltd.", +[5][0x58 - 1] = "Lorom Industrial Co Ltd", [5][0x59 - 1] = "Radiospire Networks", -[5][0x5a - 1] = "Sensio Technologies, Inc.", +[5][0x5a - 1] = "Sensio Technologies Inc", [5][0x5b - 1] = "Nethra Imaging", [5][0x5c - 1] = "Hexon Technology Pte Ltd", [5][0x5d - 1] = "CompuStocx (CSX)", -[5][0x5e - 1] = "Methode Electronics, Inc.", -[5][0x5f - 1] = "Connect One Ltd.", +[5][0x5e - 1] = "Methode Electronics Inc", +[5][0x5f - 1] = "Connect One Ltd", [5][0x60 - 1] = "Opulan Technologies", [5][0x61 - 1] = "Septentrio NV", -[5][0x62 - 1] = "Goldenmars Technology Inc.", +[5][0x62 - 1] = "Goldenmars Technology Inc", [5][0x63 - 1] = "Kreton Corporation", -[5][0x64 - 1] = "Cochlear Ltd.", +[5][0x64 - 1] = "Cochlear Ltd", [5][0x65 - 1] = "Altair Semiconductor", -[5][0x66 - 1] = "NetEffect, Inc.", -[5][0x67 - 1] = "Spansion, Inc.", +[5][0x66 - 1] = "NetEffect Inc", +[5][0x67 - 1] = "Spansion Inc", [5][0x68 - 1] = "Taiwan Semiconductor Mfg", -[5][0x69 - 1] = "Emphany Systems Inc.", +[5][0x69 - 1] = "Emphany Systems Inc", [5][0x6a - 1] = "ApaceWave Technologies", [5][0x6b - 1] = "Mobilygen Corporation", [5][0x6c - 1] = "Tego", [5][0x6d - 1] = "Cswitch Corporation", -[5][0x6e - 1] = "Haier (Beijing) IC Design Co.", +[5][0x6e - 1] = "Haier (Beijing) IC Design Co", [5][0x6f - 1] = "MetaRAM", -[5][0x70 - 1] = "Axel Electronics Co. Ltd.", +[5][0x70 - 1] = "Axel Electronics Co Ltd", [5][0x71 - 1] = "Tilera Corporation", [5][0x72 - 1] = "Aquantia", [5][0x73 - 1] = "Vivace Semiconductor", @@ -748,197 +753,197 @@ [5][0x75 - 1] = "Octalica", [5][0x76 - 1] = "InterDigital Communications", [5][0x77 - 1] = "Avant Technology", -[5][0x78 - 1] = "Asrock, Inc.", +[5][0x78 - 1] = "Asrock Inc", [5][0x79 - 1] = "Availink", -[5][0x7a - 1] = "Quartics, Inc.", +[5][0x7a - 1] = "Quartics Inc", [5][0x7b - 1] = "Element CXI", [5][0x7c - 1] = "Innovaciones Microelectronicas", [5][0x7d - 1] = "VeriSilicon Microelectronics", [5][0x7e - 1] = "W5 Networks", [6][0x01 - 1] = "MOVEKING", -[6][0x02 - 1] = "Mavrix Technology, Inc.", -[6][0x03 - 1] = "CellGuide Ltd.", +[6][0x02 - 1] = "Mavrix Technology Inc", +[6][0x03 - 1] = "CellGuide Ltd", [6][0x04 - 1] = "Faraday Technology", -[6][0x05 - 1] = "Diablo Technologies, Inc.", +[6][0x05 - 1] = "Diablo Technologies Inc", [6][0x06 - 1] = "Jennic", [6][0x07 - 1] = "Octasic", [6][0x08 - 1] = "Molex Incorporated", [6][0x09 - 1] = "3Leaf Networks", [6][0x0a - 1] = "Bright Micron Technology", [6][0x0b - 1] = "Netxen", -[6][0x0c - 1] = "NextWave Broadband Inc.", +[6][0x0c - 1] = "NextWave Broadband Inc", [6][0x0d - 1] = "DisplayLink", [6][0x0e - 1] = "ZMOS Technology", [6][0x0f - 1] = "Tec-Hill", -[6][0x10 - 1] = "Multigig, Inc.", +[6][0x10 - 1] = "Multigig Inc", [6][0x11 - 1] = "Amimon", -[6][0x12 - 1] = "Euphonic Technologies, Inc.", +[6][0x12 - 1] = "Euphonic Technologies Inc", [6][0x13 - 1] = "BRN Phoenix", [6][0x14 - 1] = "InSilica", [6][0x15 - 1] = "Ember Corporation", [6][0x16 - 1] = "Avexir Technologies Corporation", [6][0x17 - 1] = "Echelon Corporation", [6][0x18 - 1] = "Edgewater Computer Systems", -[6][0x19 - 1] = "XMOS Semiconductor Ltd.", -[6][0x1a - 1] = "GENUSION, Inc.", +[6][0x19 - 1] = "XMOS Semiconductor Ltd", +[6][0x1a - 1] = "GENUSION Inc", [6][0x1b - 1] = "Memory Corp NV", [6][0x1c - 1] = "SiliconBlue Technologies", -[6][0x1d - 1] = "Rambus Inc.", +[6][0x1d - 1] = "Rambus Inc", [6][0x1e - 1] = "Andes Technology Corporation", [6][0x1f - 1] = "Coronis Systems", [6][0x20 - 1] = "Achronix Semiconductor", -[6][0x21 - 1] = "Siano Mobile Silicon Ltd.", +[6][0x21 - 1] = "Siano Mobile Silicon Ltd", [6][0x22 - 1] = "Semtech Corporation", -[6][0x23 - 1] = "Pixelworks Inc.", +[6][0x23 - 1] = "Pixelworks Inc", [6][0x24 - 1] = "Gaisler Research AB", [6][0x25 - 1] = "Teranetics", -[6][0x26 - 1] = "Toppan Printing Co. Ltd.", +[6][0x26 - 1] = "Toppan Printing Co Ltd", [6][0x27 - 1] = "Kingxcon", [6][0x28 - 1] = "Silicon Integrated Systems", -[6][0x29 - 1] = "I-O Data Device, Inc.", -[6][0x2a - 1] = "NDS Americas Inc.", +[6][0x29 - 1] = "I-O Data Device Inc", +[6][0x2a - 1] = "NDS Americas Inc", [6][0x2b - 1] = "Solomon Systech Limited", [6][0x2c - 1] = "On Demand Microelectronics", -[6][0x2d - 1] = "Amicus Wireless Inc.", +[6][0x2d - 1] = "Amicus Wireless Inc", [6][0x2e - 1] = "SMARDTV SNC", -[6][0x2f - 1] = "Comsys Communication Ltd.", -[6][0x30 - 1] = "Movidia Ltd.", -[6][0x31 - 1] = "Javad GNSS, Inc.", +[6][0x2f - 1] = "Comsys Communication Ltd", +[6][0x30 - 1] = "Movidia Ltd", +[6][0x31 - 1] = "Javad GNSS Inc", [6][0x32 - 1] = "Montage Technology Group", [6][0x33 - 1] = "Trident Microsystems", [6][0x34 - 1] = "Super Talent", -[6][0x35 - 1] = "Optichron, Inc.", -[6][0x36 - 1] = "Future Waves UK Ltd.", -[6][0x37 - 1] = "SiBEAM, Inc.", -[6][0x38 - 1] = "Inicore,Inc.", +[6][0x35 - 1] = "Optichron Inc", +[6][0x36 - 1] = "Future Waves UK Ltd", +[6][0x37 - 1] = "SiBEAM Inc", +[6][0x38 - 1] = "InicoreInc", [6][0x39 - 1] = "Virident Systems", -[6][0x3a - 1] = "M2000, Inc.", -[6][0x3b - 1] = "ZeroG Wireless, Inc.", -[6][0x3c - 1] = "Gingle Technology Co. Ltd.", -[6][0x3d - 1] = "Space Micro Inc.", +[6][0x3a - 1] = "M2000 Inc", +[6][0x3b - 1] = "ZeroG Wireless Inc", +[6][0x3c - 1] = "Gingle Technology Co Ltd", +[6][0x3d - 1] = "Space Micro Inc", [6][0x3e - 1] = "Wilocity", -[6][0x3f - 1] = "Novafora, Inc.", +[6][0x3f - 1] = "Novafora Inc", [6][0x40 - 1] = "iKoa Corporation", [6][0x41 - 1] = "ASint Technology", [6][0x42 - 1] = "Ramtron", -[6][0x43 - 1] = "Plato Networks Inc.", +[6][0x43 - 1] = "Plato Networks Inc", [6][0x44 - 1] = "IPtronics AS", [6][0x45 - 1] = "Infinite-Memories", -[6][0x46 - 1] = "Parade Technologies Inc.", +[6][0x46 - 1] = "Parade Technologies Inc", [6][0x47 - 1] = "Dune Networks", [6][0x48 - 1] = "GigaDevice Semiconductor", -[6][0x49 - 1] = "Modu Ltd.", +[6][0x49 - 1] = "Modu Ltd", [6][0x4a - 1] = "CEITEC", [6][0x4b - 1] = "Northrop Grumman", [6][0x4c - 1] = "XRONET Corporation", [6][0x4d - 1] = "Sicon Semiconductor AB", -[6][0x4e - 1] = "Atla Electronics Co. Ltd.", +[6][0x4e - 1] = "Atla Electronics Co Ltd", [6][0x4f - 1] = "TOPRAM Technology", -[6][0x50 - 1] = "Silego Technology Inc.", +[6][0x50 - 1] = "Silego Technology Inc", [6][0x51 - 1] = "Kinglife", -[6][0x52 - 1] = "Ability Industries Ltd.", -[6][0x53 - 1] = "Silicon Power Computer &", -[6][0x54 - 1] = "Augusta Technology, Inc.", +[6][0x52 - 1] = "Ability Industries Ltd", +[6][0x53 - 1] = "Silicon Power Computer & Communications", +[6][0x54 - 1] = "Augusta Technology Inc", [6][0x55 - 1] = "Nantronics Semiconductors", [6][0x56 - 1] = "Hilscher Gesellschaft", -[6][0x57 - 1] = "Quixant Ltd.", -[6][0x58 - 1] = "Percello Ltd.", -[6][0x59 - 1] = "NextIO Inc.", -[6][0x5a - 1] = "Scanimetrics Inc.", -[6][0x5b - 1] = "FS-Semi Company Ltd.", +[6][0x57 - 1] = "Quixant Ltd", +[6][0x58 - 1] = "Percello Ltd", +[6][0x59 - 1] = "NextIO Inc", +[6][0x5a - 1] = "Scanimetrics Inc", +[6][0x5b - 1] = "FS-Semi Company Ltd", [6][0x5c - 1] = "Infinera Corporation", -[6][0x5d - 1] = "SandForce Inc.", +[6][0x5d - 1] = "SandForce Inc", [6][0x5e - 1] = "Lexar Media", -[6][0x5f - 1] = "Teradyne Inc.", -[6][0x60 - 1] = "Memory Exchange Corp.", +[6][0x5f - 1] = "Teradyne Inc", +[6][0x60 - 1] = "Memory Exchange Corp", [6][0x61 - 1] = "Suzhou Smartek Electronics", [6][0x62 - 1] = "Avantium Corporation", -[6][0x63 - 1] = "ATP Electronics Inc.", +[6][0x63 - 1] = "ATP Electronics Inc", [6][0x64 - 1] = "Valens Semiconductor Ltd", -[6][0x65 - 1] = "Agate Logic, Inc.", +[6][0x65 - 1] = "Agate Logic Inc", [6][0x66 - 1] = "Netronome", -[6][0x67 - 1] = "Zenverge, Inc.", +[6][0x67 - 1] = "Zenverge Inc", [6][0x68 - 1] = "N-trig Ltd", -[6][0x69 - 1] = "SanMax Technologies Inc.", -[6][0x6a - 1] = "Contour Semiconductor Inc.", +[6][0x69 - 1] = "SanMax Technologies Inc", +[6][0x6a - 1] = "Contour Semiconductor Inc", [6][0x6b - 1] = "TwinMOS", -[6][0x6c - 1] = "Silicon Systems, Inc.", -[6][0x6d - 1] = "V-Color Technology Inc.", +[6][0x6c - 1] = "Silicon Systems Inc", +[6][0x6d - 1] = "V-Color Technology Inc", [6][0x6e - 1] = "Certicom Corporation", [6][0x6f - 1] = "JSC ICC Milandr", -[6][0x70 - 1] = "PhotoFast Global Inc.", +[6][0x70 - 1] = "PhotoFast Global Inc", [6][0x71 - 1] = "InnoDisk Corporation", [6][0x72 - 1] = "Muscle Power", [6][0x73 - 1] = "Energy Micro", [6][0x74 - 1] = "Innofidei", [6][0x75 - 1] = "CopperGate Communications", -[6][0x76 - 1] = "Holtek Semiconductor Inc.", -[6][0x77 - 1] = "Myson Century, Inc.", +[6][0x76 - 1] = "Holtek Semiconductor Inc", +[6][0x77 - 1] = "Myson Century Inc", [6][0x78 - 1] = "FIDELIX", [6][0x79 - 1] = "Red Digital Cinema", [6][0x7a - 1] = "Densbits Technology", [6][0x7b - 1] = "Zempro", [6][0x7c - 1] = "MoSys", [6][0x7d - 1] = "Provigent", -[6][0x7e - 1] = "Triad Semiconductor, Inc.", -[7][0x01 - 1] = "Siklu Communication Ltd.", -[7][0x02 - 1] = "A Force Manufacturing Ltd.", +[6][0x7e - 1] = "Triad Semiconductor Inc", +[7][0x01 - 1] = "Siklu Communication Ltd", +[7][0x02 - 1] = "A Force Manufacturing Ltd", [7][0x03 - 1] = "Strontium", [7][0x04 - 1] = "ALi Corp (Abilis Systems)", -[7][0x05 - 1] = "Siglead, Inc.", -[7][0x06 - 1] = "Ubicom, Inc.", +[7][0x05 - 1] = "Siglead Inc", +[7][0x06 - 1] = "Ubicom Inc", [7][0x07 - 1] = "Unifosa Corporation", -[7][0x08 - 1] = "Stretch, Inc.", +[7][0x08 - 1] = "Stretch Inc", [7][0x09 - 1] = "Lantiq Deutschland GmbH", [7][0x0a - 1] = "Visipro.", [7][0x0b - 1] = "EKMemory", [7][0x0c - 1] = "Microelectronics Institute ZTE", [7][0x0d - 1] = "u-blox AG", -[7][0x0e - 1] = "Carry Technology Co. Ltd.", +[7][0x0e - 1] = "Carry Technology Co Ltd", [7][0x0f - 1] = "Nokia", [7][0x10 - 1] = "King Tiger Technology", [7][0x11 - 1] = "Sierra Wireless", [7][0x12 - 1] = "HT Micron", -[7][0x13 - 1] = "Albatron Technology Co. Ltd.", +[7][0x13 - 1] = "Albatron Technology Co Ltd", [7][0x14 - 1] = "Leica Geosystems AG", [7][0x15 - 1] = "BroadLight", [7][0x16 - 1] = "AEXEA", -[7][0x17 - 1] = "ClariPhy Communications, Inc.", +[7][0x17 - 1] = "ClariPhy Communications Inc", [7][0x18 - 1] = "Green Plug", [7][0x19 - 1] = "Design Art Networks", -[7][0x1a - 1] = "Mach Xtreme Technology Ltd.", -[7][0x1b - 1] = "ATO Solutions Co. Ltd.", +[7][0x1a - 1] = "Mach Xtreme Technology Ltd", +[7][0x1b - 1] = "ATO Solutions Co Ltd", [7][0x1c - 1] = "Ramsta", -[7][0x1d - 1] = "Greenliant Systems, Ltd.", +[7][0x1d - 1] = "Greenliant Systems Ltd", [7][0x1e - 1] = "Teikon", [7][0x1f - 1] = "Antec Hadron", -[7][0x20 - 1] = "NavCom Technology, Inc.", +[7][0x20 - 1] = "NavCom Technology Inc", [7][0x21 - 1] = "Shanghai Fudan Microelectronics", -[7][0x22 - 1] = "Calxeda, Inc.", +[7][0x22 - 1] = "Calxeda Inc", [7][0x23 - 1] = "JSC EDC Electronics", -[7][0x24 - 1] = "Kandit Technology Co. Ltd.", +[7][0x24 - 1] = "Kandit Technology Co Ltd", [7][0x25 - 1] = "Ramos Technology", [7][0x26 - 1] = "Goldenmars Technology", -[7][0x27 - 1] = "XeL Technology Inc.", +[7][0x27 - 1] = "XeL Technology Inc", [7][0x28 - 1] = "Newzone Corporation", [7][0x29 - 1] = "ShenZhen MercyPower Tech", [7][0x2a - 1] = "Nanjing Yihuo Technology", -[7][0x2b - 1] = "Nethra Imaging Inc.", +[7][0x2b - 1] = "Nethra Imaging Inc", [7][0x2c - 1] = "SiTel Semiconductor BV", [7][0x2d - 1] = "SolidGear Corporation", -[7][0x2e - 1] = "Topower Computer Ind Co Ltd.", +[7][0x2e - 1] = "Topower Computer Ind Co Ltd", [7][0x2f - 1] = "Wilocity", [7][0x30 - 1] = "Profichip GmbH", [7][0x31 - 1] = "Gerad Technologies", [7][0x32 - 1] = "Ritek Corporation", [7][0x33 - 1] = "Gomos Technology Limited", [7][0x34 - 1] = "Memoright Corporation", -[7][0x35 - 1] = "D-Broad, Inc.", +[7][0x35 - 1] = "D-Broad Inc", [7][0x36 - 1] = "HiSilicon Technologies", -[7][0x37 - 1] = "Syndiant Inc..", -[7][0x38 - 1] = "Enverv Inc.", +[7][0x37 - 1] = "Syndiant Inc.", +[7][0x38 - 1] = "Enverv Inc", [7][0x39 - 1] = "Cognex", -[7][0x3a - 1] = "Xinnova Technology Inc.", +[7][0x3a - 1] = "Xinnova Technology Inc", [7][0x3b - 1] = "Ultron AG", [7][0x3c - 1] = "Concord Idea Corporation", [7][0x3d - 1] = "AIM Corporation", @@ -948,20 +953,20 @@ [7][0x41 - 1] = "Haotian Jinshibo Science Tech", [7][0x42 - 1] = "Being Advanced Memory", [7][0x43 - 1] = "Adesto Technologies", -[7][0x44 - 1] = "Giantec Semiconductor, Inc.", +[7][0x44 - 1] = "Giantec Semiconductor Inc", [7][0x45 - 1] = "HMD Electronics AG", [7][0x46 - 1] = "Gloway International (HK)", [7][0x47 - 1] = "Kingcore", [7][0x48 - 1] = "Anucell Technology Holding", -[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd.", -[7][0x4a - 1] = "Active-Semi Inc.", +[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd", +[7][0x4a - 1] = "Active-Semi Inc", [7][0x4b - 1] = "Denso Corporation", -[7][0x4c - 1] = "TLSI Inc.", +[7][0x4c - 1] = "TLSI Inc", [7][0x4d - 1] = "Qidan", [7][0x4e - 1] = "Mustang", [7][0x4f - 1] = "Orca Systems", [7][0x50 - 1] = "Passif Semiconductor", -[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing)", +[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc", [7][0x52 - 1] = "Memphis Electronic", [7][0x53 - 1] = "Beckhoff Automation GmbH", [7][0x54 - 1] = "Harmony Semiconductor Corp", @@ -970,23 +975,23 @@ [7][0x57 - 1] = "Eorex Corporation", [7][0x58 - 1] = "Xingtera", [7][0x59 - 1] = "Netsol", -[7][0x5a - 1] = "Bestdon Technology Co. Ltd.", -[7][0x5b - 1] = "Baysand Inc.", -[7][0x5c - 1] = "Uroad Technology Co. Ltd.", +[7][0x5a - 1] = "Bestdon Technology Co Ltd", +[7][0x5b - 1] = "Baysand Inc", +[7][0x5c - 1] = "Uroad Technology Co Ltd", [7][0x5d - 1] = "Wilk Elektronik S.A.", [7][0x5e - 1] = "AAI", [7][0x5f - 1] = "Harman", -[7][0x60 - 1] = "Berg Microelectronics Inc.", -[7][0x61 - 1] = "ASSIA, Inc.", +[7][0x60 - 1] = "Berg Microelectronics Inc", +[7][0x61 - 1] = "ASSIA Inc", [7][0x62 - 1] = "Visiontek Products LLC", [7][0x63 - 1] = "OCMEMORY", -[7][0x64 - 1] = "Welink Solution Inc.", +[7][0x64 - 1] = "Welink Solution Inc", [7][0x65 - 1] = "Shark Gaming", [7][0x66 - 1] = "Avalanche Technology", [7][0x67 - 1] = "R&D Center ELVEES OJSC", -[7][0x68 - 1] = "KingboMars Technology Co. Ltd.", -[7][0x69 - 1] = "High Bridge Solutions Industria", -[7][0x6a - 1] = "Transcend Technology Co. Ltd.", +[7][0x68 - 1] = "KingboMars Technology Co Ltd", +[7][0x69 - 1] = "High Bridge Solutions Industria Eletronica", +[7][0x6a - 1] = "Transcend Technology Co Ltd", [7][0x6b - 1] = "Everspin Technologies", [7][0x6c - 1] = "Hon-Hai Precision", [7][0x6d - 1] = "Smart Storage Systems", @@ -997,54 +1002,54 @@ [7][0x72 - 1] = "LITE-ON IT Corporation", [7][0x73 - 1] = "Inuitive", [7][0x74 - 1] = "HMicro", -[7][0x75 - 1] = "BittWare, Inc.", +[7][0x75 - 1] = "BittWare Inc", [7][0x76 - 1] = "GLOBALFOUNDRIES", -[7][0x77 - 1] = "ACPI Digital Co. Ltd.", +[7][0x77 - 1] = "ACPI Digital Co Ltd", [7][0x78 - 1] = "Annapurna Labs", [7][0x79 - 1] = "AcSiP Technology Corporation", [7][0x7a - 1] = "Idea! Electronic Systems", -[7][0x7b - 1] = "Gowe Technology Co. Ltd.", -[7][0x7c - 1] = "Hermes Testing Solutions, Inc.", +[7][0x7b - 1] = "Gowe Technology Co Ltd", +[7][0x7c - 1] = "Hermes Testing Solutions Inc", [7][0x7d - 1] = "Positivo BGH", [7][0x7e - 1] = "Intelligence Silicon Technology", [8][0x01 - 1] = "3D PLUS", [8][0x02 - 1] = "Diehl Aerospace", [8][0x03 - 1] = "Fairchild", [8][0x04 - 1] = "Mercury Systems", -[8][0x05 - 1] = "Sonics, Inc.", -[8][0x06 - 1] = "GE Intelligent Platforms GmbH & Co.", -[8][0x07 - 1] = "Shenzhen Jinge Information Co. Ltd.", +[8][0x05 - 1] = "Sonics Inc", +[8][0x06 - 1] = "ICC Intelligent Platforms GmbH", +[8][0x07 - 1] = "Shenzhen Jinge Information Co Ltd", [8][0x08 - 1] = "SCWW", -[8][0x09 - 1] = "Silicon Motion Inc.", +[8][0x09 - 1] = "Silicon Motion Inc", [8][0x0a - 1] = "Anurag", [8][0x0b - 1] = "King Kong", -[8][0x0c - 1] = "FROM30 Co. Ltd.", +[8][0x0c - 1] = "FROM30 Co Ltd", [8][0x0d - 1] = "Gowin Semiconductor Corp", -[8][0x0e - 1] = "Fremont Micro Devices Ltd.", +[8][0x0e - 1] = "Fremont Micro Devices Ltd", [8][0x0f - 1] = "Ericsson Modems", [8][0x10 - 1] = "Exelis", -[8][0x11 - 1] = "Satixfy Ltd.", -[8][0x12 - 1] = "Galaxy Microsystems Ltd.", -[8][0x13 - 1] = "Gloway International Co. Ltd.", +[8][0x11 - 1] = "Satixfy Ltd", +[8][0x12 - 1] = "Galaxy Microsystems Ltd", +[8][0x13 - 1] = "Gloway International Co Ltd", [8][0x14 - 1] = "Lab", [8][0x15 - 1] = "Smart Energy Instruments", [8][0x16 - 1] = "Approved Memory Corporation", [8][0x17 - 1] = "Axell Corporation", [8][0x18 - 1] = "Essencore Limited", [8][0x19 - 1] = "Phytium", -[8][0x1a - 1] = "Xi’an SinoChip Semiconductor", +[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", [8][0x1b - 1] = "Ambiq Micro", -[8][0x1c - 1] = "eveRAM Technology, Inc.", +[8][0x1c - 1] = "eveRAM Technology Inc", [8][0x1d - 1] = "Infomax", -[8][0x1e - 1] = "Butterfly Network, Inc.", +[8][0x1e - 1] = "Butterfly Network Inc", [8][0x1f - 1] = "Shenzhen City Gcai Electronics", [8][0x20 - 1] = "Stack Devices Corporation", [8][0x21 - 1] = "ADK Media Group", -[8][0x22 - 1] = "TSP Global Co., Ltd.", +[8][0x22 - 1] = "TSP Global Co Ltd", [8][0x23 - 1] = "HighX", [8][0x24 - 1] = "Shenzhen Elicks Technology", [8][0x25 - 1] = "ISSI/Chingis", -[8][0x26 - 1] = "Google, Inc.", +[8][0x26 - 1] = "Google Inc", [8][0x27 - 1] = "Dasima International Development", [8][0x28 - 1] = "Leahkinn Technology Limited", [8][0x29 - 1] = "HIMA Paul Hildebrandt GmbH Co KG", @@ -1052,98 +1057,98 @@ [8][0x2b - 1] = "Techcomp International (Fastable)", [8][0x2c - 1] = "Ancore Technology Corporation", [8][0x2d - 1] = "Nuvoton", -[8][0x2e - 1] = "Korea Uhbele International Group Ltd.", -[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd.", -[8][0x30 - 1] = "RelChip, Inc.", +[8][0x2e - 1] = "Korea Uhbele International Group Ltd", +[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd", +[8][0x30 - 1] = "RelChip Inc", [8][0x31 - 1] = "Baikal Electronics", -[8][0x32 - 1] = "Nemostech Inc.", +[8][0x32 - 1] = "Nemostech Inc", [8][0x33 - 1] = "Memorysolution GmbH", [8][0x34 - 1] = "Silicon Integrated Systems Corporation", [8][0x35 - 1] = "Xiede", -[8][0x36 - 1] = "Multilaser Components", +[8][0x36 - 1] = "BRC", [8][0x37 - 1] = "Flash Chi", [8][0x38 - 1] = "Jone", -[8][0x39 - 1] = "GCT Semiconductor Inc.", +[8][0x39 - 1] = "GCT Semiconductor Inc", [8][0x3a - 1] = "Hong Kong Zetta Device Technology", -[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd.", +[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd", [8][0x3c - 1] = "Cuso", [8][0x3d - 1] = "Kuso", -[8][0x3e - 1] = "Uniquify Inc.", +[8][0x3e - 1] = "Uniquify Inc", [8][0x3f - 1] = "Skymedi Corporation", -[8][0x40 - 1] = "Core Chance Co. Ltd.", -[8][0x41 - 1] = "Tekism Co. Ltd.", +[8][0x40 - 1] = "Core Chance Co Ltd", +[8][0x41 - 1] = "Tekism Co Ltd", [8][0x42 - 1] = "Seagate Technology PLC", -[8][0x43 - 1] = "Hong Kong Gaia Group Co. Limited", +[8][0x43 - 1] = "Hong Kong Gaia Group Co Limited", [8][0x44 - 1] = "Gigacom Semiconductor LLC", [8][0x45 - 1] = "V2 Technologies", [8][0x46 - 1] = "TLi", [8][0x47 - 1] = "Neotion", [8][0x48 - 1] = "Lenovo", -[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp. Ltd.", +[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp Ltd", [8][0x4a - 1] = "Compound Photonics", [8][0x4b - 1] = "in2H2 inc", -[8][0x4c - 1] = "Shenzhen Pango Microsystems Co. Ltd", +[8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd", [8][0x4d - 1] = "Vasekey", [8][0x4e - 1] = "Cal-Comp Industria de Semicondutores", -[8][0x4f - 1] = "Eyenix Co., Ltd.", +[8][0x4f - 1] = "Eyenix Co Ltd", [8][0x50 - 1] = "Heoriady", -[8][0x51 - 1] = "Accelerated Memory Production Inc.", -[8][0x52 - 1] = "INVECAS, Inc.", +[8][0x51 - 1] = "Accelerated Memory Production Inc", +[8][0x52 - 1] = "INVECAS Inc", [8][0x53 - 1] = "AP Memory", [8][0x54 - 1] = "Douqi Technology", -[8][0x55 - 1] = "Etron Technology, Inc.", +[8][0x55 - 1] = "Etron Technology Inc", [8][0x56 - 1] = "Indie Semiconductor", -[8][0x57 - 1] = "Socionext Inc.", +[8][0x57 - 1] = "Socionext Inc", [8][0x58 - 1] = "HGST", [8][0x59 - 1] = "EVGA", -[8][0x5a - 1] = "Audience Inc.", +[8][0x5a - 1] = "Audience Inc", [8][0x5b - 1] = "EpicGear", -[8][0x5c - 1] = "Vitesse Enterprise Co.", +[8][0x5c - 1] = "Vitesse Enterprise Co", [8][0x5d - 1] = "Foxtronn International Corporation", -[8][0x5e - 1] = "Bretelon Inc.", +[8][0x5e - 1] = "Bretelon Inc", [8][0x5f - 1] = "Graphcore", [8][0x60 - 1] = "Eoplex Inc", -[8][0x61 - 1] = "MaxLinear, Inc.", +[8][0x61 - 1] = "MaxLinear Inc", [8][0x62 - 1] = "ETA Devices", [8][0x63 - 1] = "LOKI", -[8][0x64 - 1] = "IMS Electronics Co., Ltd.", -[8][0x65 - 1] = "Dosilicon Co., Ltd.", +[8][0x64 - 1] = "IMS Electronics Co Ltd", +[8][0x65 - 1] = "Dosilicon Co Ltd", [8][0x66 - 1] = "Dolphin Integration", -[8][0x67 - 1] = "Shenzhen Mic Electronics Technology", -[8][0x68 - 1] = "Boya Microelectronics Inc.", +[8][0x67 - 1] = "Shenzhen Mic Electronics Technolog", +[8][0x68 - 1] = "Boya Microelectronics Inc", [8][0x69 - 1] = "Geniachip (Roche)", [8][0x6a - 1] = "Axign", -[8][0x6b - 1] = "Kingred Electronic Technology Ltd.", +[8][0x6b - 1] = "Kingred Electronic Technology Ltd", [8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.", [8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.", -[8][0x6e - 1] = "Crocus Technology Inc.", +[8][0x6e - 1] = "Crocus Technology Inc", [8][0x6f - 1] = "Creative Chips GmbH", [8][0x70 - 1] = "GE Aviation Systems LLC.", [8][0x71 - 1] = "Asgard", -[8][0x72 - 1] = "Good Wealth Technology Ltd.", +[8][0x72 - 1] = "Good Wealth Technology Ltd", [8][0x73 - 1] = "TriCor Technologies", [8][0x74 - 1] = "Nova-Systems GmbH", [8][0x75 - 1] = "JUHOR", -[8][0x76 - 1] = "Zhuhai Douke Commerce Co. Ltd.", +[8][0x76 - 1] = "Zhuhai Douke Commerce Co Ltd", [8][0x77 - 1] = "DSL Memory", [8][0x78 - 1] = "Anvo-Systems Dresden GmbH", [8][0x79 - 1] = "Realtek", [8][0x7a - 1] = "AltoBeam", [8][0x7b - 1] = "Wave Computing", -[8][0x7c - 1] = "Beijing TrustNet Technology Co. Ltd.", -[8][0x7d - 1] = "Innovium, Inc.", +[8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd", +[8][0x7d - 1] = "Innovium Inc", [8][0x7e - 1] = "Starsway Technology Limited", -[9][0x01 - 1] = "Weltronics Co. LTD", -[9][0x02 - 1] = "VMware, Inc.", +[9][0x01 - 1] = "Weltronics Co LTD", +[9][0x02 - 1] = "VMware Inc", [9][0x03 - 1] = "Hewlett Packard Enterprise", [9][0x04 - 1] = "INTENSO", [9][0x05 - 1] = "Puya Semiconductor", [9][0x06 - 1] = "MEMORFI", [9][0x07 - 1] = "MSC Technologies GmbH", [9][0x08 - 1] = "Txrui", -[9][0x09 - 1] = "SiFive, Inc.", +[9][0x09 - 1] = "SiFive Inc", [9][0x0a - 1] = "Spreadtrum Communications", -[9][0x0b - 1] = "Paragon Technology (Shenzhen) Ltd.", +[9][0x0b - 1] = "XTX Technology Limited", [9][0x0c - 1] = "UMAX Technology", [9][0x0d - 1] = "Shenzhen Yong Sheng Technology", [9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)", @@ -1151,6 +1156,261 @@ [9][0x10 - 1] = "Shenzhen XinRuiYan Electronics", [9][0x11 - 1] = "Eta Compute", [9][0x12 - 1] = "Energous", -[9][0x13 - 1] = "Raspberry Pi Trading Ltd.", -[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co. Ltd.", +[9][0x13 - 1] = "Raspberry Pi Trading Ltd", +[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co Ltd", +[9][0x15 - 1] = "Silicon Mobility", +[9][0x16 - 1] = "IQ-Analog Corporation", +[9][0x17 - 1] = "Uhnder Inc", +[9][0x18 - 1] = "Impinj", +[9][0x19 - 1] = "DEPO Computers", +[9][0x1a - 1] = "Nespeed Sysems", +[9][0x1b - 1] = "Yangtze Memory Technologies Co Ltd", +[9][0x1c - 1] = "MemxPro Inc", +[9][0x1d - 1] = "Tammuz Co Ltd", +[9][0x1e - 1] = "Allwinner Technology", +[9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm", +[9][0x20 - 1] = "XMC", +[9][0x21 - 1] = "Teclast", +[9][0x22 - 1] = "Maxsun", +[9][0x23 - 1] = "Haiguang Integrated Circuit Design", +[9][0x24 - 1] = "RamCENTER Technology", +[9][0x25 - 1] = "Phison Electronics Corporation", +[9][0x26 - 1] = "Guizhou Huaxintong Semi-Conductor", +[9][0x27 - 1] = "Network Intelligence", +[9][0x28 - 1] = "Continental Technology (Holdings)", +[9][0x29 - 1] = "Guangzhou Huayan Suning Electronic", +[9][0x2a - 1] = "Guangzhou Zhouji Electronic Co Ltd", +[9][0x2b - 1] = "Shenzhen Giant Hui Kang Tech Co Ltd", +[9][0x2c - 1] = "Shenzhen Yilong Innovative Co Ltd", +[9][0x2d - 1] = "Neo Forza", +[9][0x2e - 1] = "Lyontek Inc", +[9][0x2f - 1] = "Shanghai Kuxin Microelectronics Ltd", +[9][0x30 - 1] = "Shenzhen Larix Technology Co Ltd", +[9][0x31 - 1] = "Qbit Semiconductor Ltd", +[9][0x32 - 1] = "Insignis Technology Corporation", +[9][0x33 - 1] = "Lanson Memory Co Ltd", +[9][0x34 - 1] = "Shenzhen Superway Electronics Co Ltd", +[9][0x35 - 1] = "Canaan-Creative Co Ltd", +[9][0x36 - 1] = "Black Diamond Memory", +[9][0x37 - 1] = "Shenzhen City Parker Baking Electronics", +[9][0x38 - 1] = "Shenzhen Baihong Technology Co Ltd", +[9][0x39 - 1] = "GEO Semiconductors", +[9][0x3a - 1] = "OCPC", +[9][0x3b - 1] = "Artery Technology Co Ltd", +[9][0x3c - 1] = "Jinyu", +[9][0x3d - 1] = "ShenzhenYing Chi Technology Development", +[9][0x3e - 1] = "Shenzhen Pengcheng Xin Technology", +[9][0x3f - 1] = "Pegasus Semiconductor (Shanghai) Co", +[9][0x40 - 1] = "Mythic Inc", +[9][0x41 - 1] = "Elmos Semiconductor AG", +[9][0x42 - 1] = "Kllisre", +[9][0x43 - 1] = "Shenzhen Winconway Technology", +[9][0x44 - 1] = "Shenzhen Xingmem Technology Corp", +[9][0x45 - 1] = "Gold Key Technology Co Ltd", +[9][0x46 - 1] = "Habana Labs Ltd", +[9][0x47 - 1] = "Hoodisk Electronics Co Ltd", +[9][0x48 - 1] = "SemsoTai (SZ) Technology Co Ltd", +[9][0x49 - 1] = "OM Nanotech Pvt. Ltd", +[9][0x4a - 1] = "Shenzhen Zhifeng Weiye Technology", +[9][0x4b - 1] = "Xinshirui (Shenzhen) Electronics Co", +[9][0x4c - 1] = "Guangzhou Zhong Hao Tian Electronic", +[9][0x4d - 1] = "Shenzhen Longsys Electronics Co Ltd", +[9][0x4e - 1] = "Deciso B.V.", +[9][0x4f - 1] = "Puya Semiconductor (Shenzhen)", +[9][0x50 - 1] = "Shenzhen Veineda Technology Co Ltd", +[9][0x51 - 1] = "Antec Memory", +[9][0x52 - 1] = "Cortus SAS", +[9][0x53 - 1] = "Dust Leopard", +[9][0x54 - 1] = "MyWo AS", +[9][0x55 - 1] = "J&A Information Inc", +[9][0x56 - 1] = "Shenzhen JIEPEI Technology Co Ltd", +[9][0x57 - 1] = "Heidelberg University", +[9][0x58 - 1] = "Flexxon PTE Ltd", +[9][0x59 - 1] = "Wiliot", +[9][0x5a - 1] = "Raysun Electronics International Ltd", +[9][0x5b - 1] = "Aquarius Production Company LLC", +[9][0x5c - 1] = "MACNICA DHW LTDA", +[9][0x5d - 1] = "Intelimem", +[9][0x5e - 1] = "Zbit Semiconductor Inc", +[9][0x5f - 1] = "Shenzhen Technology Co Ltd", +[9][0x60 - 1] = "Signalchip", +[9][0x61 - 1] = "Shenzen Recadata Storage Technology", +[9][0x62 - 1] = "Hyundai Technology", +[9][0x63 - 1] = "Shanghai Fudi Investment Development", +[9][0x64 - 1] = "Aixi Technology", +[9][0x65 - 1] = "Tecon MT", +[9][0x66 - 1] = "Onda Electric Co Ltd", +[9][0x67 - 1] = "Jinshen", +[9][0x68 - 1] = "Kimtigo Semiconductor (HK) Limited", +[9][0x69 - 1] = "IIT Madras", +[9][0x6a - 1] = "Shenshan (Shenzhen) Electronic", +[9][0x6b - 1] = "Hefei Core Storage Electronic Limited", +[9][0x6c - 1] = "Colorful Technology Ltd", +[9][0x6d - 1] = "Visenta (Xiamen) Technology Co Ltd", +[9][0x6e - 1] = "Roa Logic BV", +[9][0x6f - 1] = "NSITEXE Inc", +[9][0x70 - 1] = "Hong Kong Hyunion Electronics", +[9][0x71 - 1] = "ASK Technology Group Limited", +[9][0x72 - 1] = "GIGA-BYTE Technology Co Ltd", +[9][0x73 - 1] = "Terabyte Co Ltd", +[9][0x74 - 1] = "Hyundai Inc", +[9][0x75 - 1] = "EXCELERAM", +[9][0x76 - 1] = "PsiKick", +[9][0x77 - 1] = "Netac Technology Co Ltd", +[9][0x78 - 1] = "PCCOOLER", +[9][0x79 - 1] = "Jiangsu Huacun Electronic Technology", +[9][0x7a - 1] = "Shenzhen Micro Innovation Industry", +[9][0x7b - 1] = "Beijing Tongfang Microelectronics Co", +[9][0x7c - 1] = "XZN Storage Technology", +[9][0x7d - 1] = "ChipCraft Sp. z.o.o.", +[9][0x7e - 1] = "ALLFLASH Technology Limited", +[10][0x01 - 1] = "Foerd Technology Co Ltd", +[10][0x02 - 1] = "KingSpec", +[10][0x03 - 1] = "Codasip GmbH", +[10][0x04 - 1] = "SL Link Co Ltd", +[10][0x05 - 1] = "Shenzhen Kefu Technology Co Limited", +[10][0x06 - 1] = "Shenzhen ZST Electronics Technology", +[10][0x07 - 1] = "Kyokuto Electronic Inc", +[10][0x08 - 1] = "Warrior Technology", +[10][0x09 - 1] = "TRINAMIC Motion Control GmbH & Co", +[10][0x0a - 1] = "PixelDisplay Inc", +[10][0x0b - 1] = "Shenzhen Futian District Bo Yueda Elec", +[10][0x0c - 1] = "Richtek Power", +[10][0x0d - 1] = "Shenzhen LianTeng Electronics Co Ltd", +[10][0x0e - 1] = "AITC Memory", +[10][0x0f - 1] = "UNIC Memory Technology Co Ltd", +[10][0x10 - 1] = "Shenzhen Huafeng Science Technology", +[10][0x11 - 1] = "ChangXin Memory Technologies Inc", +[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm", +[10][0x13 - 1] = "SambaNova Systems", +[10][0x14 - 1] = "V-GEN", +[10][0x15 - 1] = "Jump Trading", +[10][0x16 - 1] = "Ampere Computing", +[10][0x17 - 1] = "Shenzhen Zhongshi Technology Co Ltd", +[10][0x18 - 1] = "Shenzhen Zhongtian Bozhong Technology", +[10][0x19 - 1] = "Tri-Tech International", +[10][0x1a - 1] = "Silicon Intergrated Systems Corporation", +[10][0x1b - 1] = "Shenzhen HongDingChen Information", +[10][0x1c - 1] = "Plexton Holdings Limited", +[10][0x1d - 1] = "AMS (Jiangsu Advanced Memory Semi)", +[10][0x1e - 1] = "Wuhan Jing Tian Interconnected Tech Co", +[10][0x1f - 1] = "Axia Memory Technology", +[10][0x20 - 1] = "Chipset Technology Holding Limited", +[10][0x21 - 1] = "Shenzhen Xinshida Technology Co Ltd", +[10][0x22 - 1] = "Shenzhen Chuangshifeida Technology", +[10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology", +[10][0x24 - 1] = "ADVAN Inc", +[10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd", +[10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading", +[10][0x27 - 1] = "StarRam International Co Ltd", +[10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd", +[10][0x29 - 1] = "UltraMemory Inc", +[10][0x2a - 1] = "New Coastline Global Tech Industry Co", +[10][0x2b - 1] = "Sinker", +[10][0x2c - 1] = "Diamond", +[10][0x2d - 1] = "PUSKILL", +[10][0x2e - 1] = "Guangzhou Hao Jia Ye Technology Co", +[10][0x2f - 1] = "Ming Xin Limited", +[10][0x30 - 1] = "Barefoot Networks", +[10][0x31 - 1] = "Biwin Semiconductor (HK) Co Ltd", +[10][0x32 - 1] = "UD INFO Corporation", +[10][0x33 - 1] = "Trek Technology (S) PTE Ltd", +[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd", +[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd", +[10][0x36 - 1] = "Nuclei System Technology Co Ltd", +[10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology", +[10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd", +[10][0x39 - 1] = "Zotac Technology Ltd", +[10][0x3a - 1] = "Foxline", +[10][0x3b - 1] = "Shenzhen Farasia Science Technology", +[10][0x3c - 1] = "Efinix Inc", +[10][0x3d - 1] = "Hua Nan San Xian Technology Co Ltd", +[10][0x3e - 1] = "Goldtech Electronics Co Ltd", +[10][0x3f - 1] = "Shanghai Han Rong Microelectronics Co", +[10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading", +[10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics", +[10][0x42 - 1] = "Thermaltake Technology Co Ltd", +[10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd", +[10][0x44 - 1] = "UPMEM", +[10][0x45 - 1] = "Chun Well Technology Holding Limited", +[10][0x46 - 1] = "Astera Labs Inc", +[10][0x47 - 1] = "VMEMORY Co Ltd", +[10][0x48 - 1] = "Advantech Co Ltd", +[10][0x49 - 1] = "Chengdu Fengcai Electronic Technology", +[10][0x4a - 1] = "The Boeing Company", +[10][0x4b - 1] = "ThinCI Inc", +[10][0x4c - 1] = "Ramonster Technology Co Ltd", +[10][0x4d - 1] = "Wuhan Naonongmai Technology Co Ltd", +[10][0x4e - 1] = "Shenzhen Hui ShingTong Technology", +[10][0x4f - 1] = "Yourlyon", +[10][0x50 - 1] = "Fabu Technology", +[10][0x51 - 1] = "Shenzhen Yikesheng Technology Co Ltd", +[10][0x52 - 1] = "NOR-MEM", +[10][0x53 - 1] = "Cervoz Co Ltd", +[10][0x54 - 1] = "Bitmain Technologies Inc.", +[10][0x55 - 1] = "Facebook Inc", +[10][0x56 - 1] = "Shenzhen Longsys Electronics Co Ltd", +[10][0x57 - 1] = "Guangzhou Siye Electronic Technology", +[10][0x58 - 1] = "Silergy", +[10][0x59 - 1] = "Adamway", +[10][0x5a - 1] = "PZG", +[10][0x5b - 1] = "Shenzhen King Power Electronics", +[10][0x5c - 1] = "Guangzhou ZiaoFu Tranding Co Ltd", +[10][0x5d - 1] = "Shenzhen SKIHOTAR Semiconductor", +[10][0x5e - 1] = "PulseRain Technology", +[10][0x5f - 1] = "Seeker Technology Limited", +[10][0x60 - 1] = "Shenzhen OSCOO Tech Co Ltd", +[10][0x61 - 1] = "Shenzhen Yze Technology Co Ltd", +[10][0x62 - 1] = "Shenzhen Jieshuo Electronic Commerce", +[10][0x63 - 1] = "Gazda", +[10][0x64 - 1] = "Hua Wei Technology Co Ltd", +[10][0x65 - 1] = "Esperanto Technologies", +[10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", +[10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", +[10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", +[10][0x69 - 1] = "Fraunhofer IIS", +[10][0x6a - 1] = "Kandou Bus SA", +[10][0x6b - 1] = "Acer", +[10][0x6c - 1] = "Artmem Technology Co Ltd", +[10][0x6d - 1] = "Gstar Semiconductor Co Ltd", +[10][0x6e - 1] = "ShineDisk", +[10][0x6f - 1] = "Shenzhen CHN Technology Co Ltd", +[10][0x70 - 1] = "UnionChip Semiconductor Co Ltd", +[10][0x71 - 1] = "Tanbassh", +[10][0x72 - 1] = "Shenzhen Tianyu Jieyun Intl Logistics", +[10][0x73 - 1] = "MCLogic Inc", +[10][0x74 - 1] = "Eorex Corporation", +[10][0x75 - 1] = "Arm Technology (China) Co Ltd", +[10][0x76 - 1] = "Lexar Co Limited", +[10][0x77 - 1] = "QinetiQ Group plc", +[10][0x78 - 1] = "Exascend", +[10][0x79 - 1] = "Hong Kong Hyunion Electronics Co Ltd", +[10][0x7a - 1] = "Shenzhen Banghong Electronics Co Ltd", +[10][0x7b - 1] = "MBit Wireless Inc", +[10][0x7c - 1] = "Hex Five Security Inc", +[10][0x7d - 1] = "ShenZhen Juhor Precision Tech Co Ltd", +[10][0x7e - 1] = "Shenzhen Reeinno Technology Co Ltd", +[11][0x01 - 1] = "ABIT Electronics (Shenzhen) Co Ltd", +[11][0x02 - 1] = "Semidrive", +[11][0x03 - 1] = "MyTek Electronics Corp", +[11][0x04 - 1] = "Wxilicon Technology Co Ltd", +[11][0x05 - 1] = "Shenzhen Meixin Electronics Ltd", +[11][0x06 - 1] = "Ghost Wolf", +[11][0x07 - 1] = "LiSion Technologies Inc", +[11][0x08 - 1] = "Power Active Co Ltd", +[11][0x09 - 1] = "Pioneer High Fidelity Taiwan Co. Ltd", +[11][0x0a - 1] = "LuoSilk", +[11][0x0b - 1] = "Shenzhen Chuangshifeida Technology", +[11][0x0c - 1] = "Black Sesame Technologies Inc", +[11][0x0d - 1] = "Jiangsu Xinsheng Intelligent Technology", +[11][0x0e - 1] = "MLOONG", +[11][0x0f - 1] = "Quadratica LLC", +[11][0x10 - 1] = "Anpec Electronics", +[11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co", +[11][0x12 - 1] = "Kingbank Technology Co Ltd", +[11][0x13 - 1] = "ITRenew Inc", +[11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd", +[11][0x15 - 1] = "Jazer", +[11][0x16 - 1] = "Xiamen Semiconductor Investment Group", +[11][0x17 - 1] = "Guangzhou Longdao Network Tech Co", /* EOF */ From 693b8501e5b1233b87420b1c9d5cbbb3b943b285 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Nov 2020 00:15:44 +0100 Subject: [PATCH 093/113] armv4_5: fix segmentation fault in command 'arm reg' Commit fed713104904 ("armv4_5: support weirdo ARMv6 secure monitor mode") introduces the secure mode 28 of ARMv6 as a synonymous of mode 22 (MON), but does not add it in the switch/case in command 'arm reg'. When command 'arm reg' scans the array arm_mode_data[] on targets without secure modes, it does not detect the new secure mode as not supported by the architecture, thus triggers a segmentation fault when it try to read the register's value from unallocated memory. Issue detected with target arm926ejs. Add the new mode in the switch/case and treat it as the mode MON. Change-Id: I2b72cc558e097879a7ee6ea601200bfda6b60270 Signed-off-by: Antonio Borneo Fixes: fed713104904 ("armv4_5: support weirdo ARMv6 secure monitor mode") Reviewed-on: http://openocd.zylin.com/5941 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/target/armv4_5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 7da28e349..8ac482504 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -869,6 +869,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) continue; /* FALLTHROUGH */ case ARM_MODE_MON: + case ARM_MODE_1176_MON: if (arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; From 62686ab161e9c46a620dd592b2767634e9483c20 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Nov 2020 00:33:59 +0100 Subject: [PATCH 094/113] armv4_5: fix output of command 'arm reg' Commit fc2abe63fd3c ("armv7m: use generic arm::core_mode") adds two special modes for ARMv6M and ARMv7M in struct arm_mode_data[]. While these modes do not have any additional register to be dumped by command 'arm reg', the command still prints an header for these modes but not followed by any register. Detect the special modes for ARMv6M and ARMv7M and skip them to avoid printing the useless header. Change-Id: I04145769e5742624f143c910eebf9a6f6d8e3cdc Signed-off-by: Antonio Borneo Fixes: fc2abe63fd3c ("armv7m: use generic arm::core_mode") Reviewed-on: http://openocd.zylin.com/5942 Tested-by: jenkins --- src/target/armv4_5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 8ac482504..b725853fe 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -856,6 +856,9 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) char *sep = "\n"; char *shadow = ""; + if (!arm_mode_data[mode].n_indices) + continue; + /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { case ARM_MODE_SYS: From a56b7291911b4f42718d406dd2de857db4c11e0f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Nov 2020 12:29:04 +0100 Subject: [PATCH 095/113] arm7_9_common: fix host endianness bug in arm7_9_full_context() The original code passes to ->read_core_regs() and to ->read_xpsr() the pointer to the little-endian buffer reg.value. This is incorrect because the two functions above require a pointer to uint32_t, since they already run the conversion with arm_le_to_h_u32() in the jtag callback. This causes a mismatch on big-endian host and the registers get read with the incorrect endianness. Use an intermediate buffer to read the registers as uint32_t and to track the destination reg.value pointer, then copy the value in reg.value after the call to jtag_execute_queue(). Tested with qemu-armeb and an OpenOCD built through buildroot configured for cortex-a7 big-endian. Note that if jtag_execute_queue() fails, the openocd register cache is not updated, so the already modified flags 'valid' and 'dirty' are incorrect. This part should be moved after the call to jtag_execute_queue() too. Change-Id: Iba70d964ffbb74bf0860bfd9d299f218e3bc65bf Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5943 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/target/arm7_9_common.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index d70d27377..d992aa78b 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1391,6 +1391,11 @@ static int arm7_9_full_context(struct target *target) int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; + struct { + uint32_t value; + void *reg_p; + } read_cache[6 * (16 + 1)]; + int read_cache_idx = 0; LOG_DEBUG("-"); @@ -1433,10 +1438,12 @@ static int arm7_9_full_context(struct target *target) for (j = 0; j < 15; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid) { - reg_p[j] = (uint32_t *)ARMV4_5_CORE_REG_MODE( + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE( arm->core_cache, armv4_5_number_to_mode(i), j).value; + reg_p[j] = &read_cache[read_cache_idx].value; + read_cache_idx++; mask |= 1 << j; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1454,9 +1461,10 @@ static int arm7_9_full_context(struct target *target) /* check if the PSR has to be read */ if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid) { - arm7_9->read_xpsr(target, - (uint32_t *)ARMV4_5_CORE_REG_MODE(arm->core_cache, - armv4_5_number_to_mode(i), 16).value, 1); + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE(arm->core_cache, + armv4_5_number_to_mode(i), 16).value; + arm7_9->read_xpsr(target, &read_cache[read_cache_idx].value, 1); + read_cache_idx++; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1472,6 +1480,14 @@ static int arm7_9_full_context(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; + /* + * FIXME: regs in cache should be tagged as 'valid' only now, + * not before the jtag_execute_queue() + */ + while (read_cache_idx) { + read_cache_idx--; + buf_set_u32(read_cache[read_cache_idx].reg_p, 0, 32, read_cache[read_cache_idx].value); + } return ERROR_OK; } From b5e015357ad4ae1fbb286f9bf6c22a563ab93eb7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 22 Nov 2020 13:02:32 +0100 Subject: [PATCH 096/113] mips_mips64: fix minor host endianness bug Commit 80f1a92bd798 ("mips64: Add generic mips64 target support") adds a log of the target's program counter in function mips_mips64_debug_entry() by directly casting the little-endian buffer in pc->value. This is going to print an incorrect value on big-endian hosts. Use the function buf_get_u64() to return the register value. Not tested on real HW. Issue identified with GCC compiler flag '-Wcast-align=strict' after change http://openocd.zylin.com/5937/ ("target/register: use an array of uint8_t for register's value"). Change-Id: Icbda2b54a03fdec287c804e623f5db4252f9cd2a Signed-off-by: Antonio Borneo Fixes: 80f1a92bd798 ("mips64: Add generic mips64 target support") Reviewed-on: http://openocd.zylin.com/5944 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/target/mips_mips64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index f941af517..0fc089726 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -62,7 +62,7 @@ static int mips_mips64_debug_entry(struct target *target) mips_mips64_examine_debug_reason(target); LOG_DEBUG("entered debug state at PC 0x%" PRIx64 ", target->state: %s", - *(uint64_t *)pc->value, target_state_name(target)); + buf_get_u64(pc->value, 0, 64), target_state_name(target)); return ERROR_OK; } From 1d3d87695c62be88d4a87c7d57de6084d654396b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 15 Nov 2020 22:10:58 +0100 Subject: [PATCH 097/113] target/register: use an array of uint8_t for register's value The use of 'void *' makes the pointer arithmetic incompatible with standard C, even if this is allowed by GCC extensions. The use of 'void *' can also hide incorrect pointer assignments. Switch to 'uint8_t *' and add GCC warning flag to track any use of pointer arithmetic extension. Change-Id: Ic4d15a232834cd6b374330f70e2473a359b1607f Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5937 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- configure.ac | 1 + src/target/arc.c | 2 +- src/target/arm7_9_common.c | 2 +- src/target/etm.c | 2 +- src/target/register.h | 2 +- src/target/riscv/riscv.c | 2 +- src/target/riscv/riscv.h | 4 ++-- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 9cb20ad89..c8978b94d 100644 --- a/configure.ac +++ b/configure.ac @@ -833,6 +833,7 @@ AS_IF([test "x${gcc_wextra}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast" GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align" GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" + GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith" ]) AS_IF([test "x${gcc_werror}" = "xyes"], [ GCC_WARNINGS="${GCC_WARNINGS} -Werror" diff --git a/src/target/arc.c b/src/target/arc.c index cec6441a5..ffe974532 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -305,7 +305,7 @@ static int arc_init_reg(struct target *target, struct reg *reg, /* Initialize struct reg */ reg->name = reg_desc->name; reg->size = 32; /* All register in ARC are 32-bit */ - reg->value = ®_desc->reg_value; + reg->value = reg_desc->reg_value; reg->type = &arc_reg_type; reg->arch_info = reg_desc; reg->caller_save = true; /* @todo should be configurable. */ diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index d992aa78b..797f61c93 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1393,7 +1393,7 @@ static int arm7_9_full_context(struct target *target) struct arm *arm = &arm7_9->arm; struct { uint32_t value; - void *reg_p; + uint8_t *reg_p; } read_cache[6 * (16 + 1)]; int read_cache_idx = 0; diff --git a/src/target/etm.c b/src/target/etm.c index 93dbd2948..faa941fed 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -279,7 +279,7 @@ static void etm_reg_add(unsigned bcd_vers, struct arm_jtag *jtag_info, reg->name = r->name; reg->size = r->size; - reg->value = &ereg->value; + reg->value = ereg->value; reg->arch_info = ereg; reg->type = &etm_scan6_type; reg++; diff --git a/src/target/register.h b/src/target/register.h index 1bae81183..5f1c25fb4 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -127,7 +127,7 @@ struct reg { bool caller_save; /* Pointer to place where the value is stored, in the format understood by * the binarybuffer.h functions. */ - void *value; + uint8_t *value; /* The stored value needs to be written to the target. */ bool dirty; /* When true, value is valid. */ diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 53af07ec3..0d1cee1bf 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -4128,7 +4128,7 @@ int riscv_init_registers(struct target *target) reg_name += strlen(reg_name) + 1; assert(reg_name < info->reg_names + target->reg_cache->num_regs * max_reg_name_len); - r->value = &info->reg_cache_values[number]; + r->value = info->reg_cache_values[number]; } return ERROR_OK; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 7e74cf730..d943134e2 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -68,8 +68,8 @@ typedef struct { /* OpenOCD's register cache points into here. This is not per-hart because * we just invalidate the entire cache when we change which hart is - * selected. */ - uint64_t reg_cache_values[RISCV_MAX_REGISTERS]; + * selected. Use an array of 8 uint8_t per register. */ + uint8_t reg_cache_values[RISCV_MAX_REGISTERS][8]; /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ From 861e75f54efbcc1e0717192c6ddb120478d6c226 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 5 Nov 2020 23:02:55 +0100 Subject: [PATCH 098/113] jimtcl: switch to github The 'historically' main repository of jimtcl in repo.or.cz has lost sync with the github current main repository since July 2020. The new tag 0.80 is not present in repo.or.cz. The developer of jimtcl has been in contact with the admins of repo.or.cz to fix the not better described sync issues and has now decided to stop any further tentative. A new README has been added on 2020-11-19 in the old repository to inform that it is abandoned in favour of github. The old content in repo.or.cz will remain due to forks that still exists in the same server. Switch OpenOCD git submodules to fetch jimtcl code from the main development repository in github. Change-Id: Ia2d59f1347ccfe374538b38131badfd46054eb91 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5948 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 958c5d901..23ffa2543 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://repo.or.cz/git2cl.git [submodule "jimtcl"] path = jimtcl - url = https://repo.or.cz/jimtcl.git + url = https://github.com/msteveb/jimtcl.git [submodule "src/jtag/drivers/libjaylink"] path = src/jtag/drivers/libjaylink url = https://repo.or.cz/libjaylink.git From cc26808136d483e4bf0d1fc0dc3ce199de637f1f Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Fri, 20 Nov 2020 20:25:38 +0100 Subject: [PATCH 099/113] flash/nor/sfdp|stmqspi: fix build issue with clang on mac OS Change-Id: I3b3aa4236125523ad65fd615ada0f5647d26f526 Signed-off-by: Tarek BOCHKATI Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5940 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/sfdp.c | 4 ++-- src/flash/nor/stmqspi.c | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/flash/nor/sfdp.c b/src/flash/nor/sfdp.c index 2fbc37d1f..2183ac1f1 100644 --- a/src/flash/nor/sfdp.c +++ b/src/flash/nor/sfdp.c @@ -90,8 +90,8 @@ int spi_sfdp(struct flash_bank *bank, struct flash_device *dev, return ERROR_FLASH_BANK_NOT_PROBED; } if (((header.revision >> 24) & 0xFF) != SFDP_ACCESS_PROT) { - LOG_ERROR("access protocol 0x%02" PRIx8 " not implemented", - (header.revision >> 24) & 0xFF); + LOG_ERROR("access protocol 0x%02x not implemented", + (header.revision >> 24) & 0xFFU); return ERROR_FLASH_BANK_NOT_PROBED; } diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index 11529f410..f54e4975d 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -455,8 +455,8 @@ static int qspi_write_enable(struct flash_bank *bank) if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { - LOG_ERROR("Cannot write enable flash1. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Cannot write enable flash1. Status=0x%02x", + status & 0xFFU); return ERROR_FLASH_OPERATION_FAILED; } @@ -464,8 +464,8 @@ static int qspi_write_enable(struct flash_bank *bank) status >>= 8; if ((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) if ((status & (SPIFLASH_WE_BIT | SPIFLASH_BSY_BIT)) != SPIFLASH_WE_BIT) { - LOG_ERROR("Cannot write enable flash2. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Cannot write enable flash2. Status=0x%02x", + status & 0xFFU); return ERROR_FLASH_OPERATION_FAILED; } @@ -548,8 +548,8 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { - LOG_ERROR("Mass erase command not accepted by flash1. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Mass erase command not accepted by flash1. Status=0x%02x", + status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } @@ -559,8 +559,8 @@ COMMAND_HANDLER(stmqspi_handle_mass_erase_command) if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { - LOG_ERROR("Mass erase command not accepted by flash2. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Mass erase command not accepted by flash2. Status=0x%02x", + status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } @@ -959,8 +959,8 @@ static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != BIT(SPI_FSEL_FLASH)) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { - LOG_ERROR("Sector erase command not accepted by flash1. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Sector erase command not accepted by flash1. Status=0x%02x", + status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } @@ -971,8 +971,8 @@ static int qspi_erase_sector(struct flash_bank *bank, unsigned int sector) if (((stmqspi_info->saved_cr & (BIT(SPI_DUAL_FLASH) | BIT(SPI_FSEL_FLASH))) != 0) && ((status & SPIFLASH_BSY_BIT) == 0) && ((status & SPIFLASH_WE_BIT) != 0)) { - LOG_ERROR("Sector erase command not accepted by flash2. Status=0x%02" PRIx8, - status & 0xFF); + LOG_ERROR("Sector erase command not accepted by flash2. Status=0x%02x", + status & 0xFFU); retval = ERROR_FLASH_OPERATION_FAILED; goto err; } @@ -1214,7 +1214,7 @@ static int stmqspi_blank_check(struct flash_bank *bank) /* we need le_32_to_h, but that's the same as h_to_le_32 */ result = h_to_le_32(erase_check_info.result); bank->sectors[sector + index].is_erased = ((result & 0xFF) == 0xFF); - LOG_DEBUG("Flash sector %u checked: 0x%04" PRIx16, sector + index, result & 0xFFFF); + LOG_DEBUG("Flash sector %u checked: 0x%04x", sector + index, result & 0xFFFFU); } keep_alive(); sector += count; From 39380318c89990b4661246d367de3fa820c835ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Misek?= Date: Tue, 6 Jan 2015 15:53:09 +0300 Subject: [PATCH 100/113] jtag/drivers/ulink: auto-detect OpenULINK USB endpoints numbers This should provide greater compatibility with different OpenULINK targets which might be using various endpoints numbers. Since they're advertised in the USB descriptor anyway it makes sense to autodetect them. Interface is no longer claimed before attempting to load firmware to a freshly booted device, so I have no idea if this will break on windows or other uncommon systems (Paul). Change-Id: Iee10dcb6911dcf46239c430e174d9f98b5bde3c2 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/2445 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/ulink.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index fd08c1661..f473ce39a 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -25,6 +25,7 @@ #include #include #include +#include "libusb_helper.h" #include "OpenULINK/include/msgtypes.h" /** USB Vendor ID of ULINK device in unconfigured state (no firmware loaded @@ -148,6 +149,9 @@ struct ulink { struct libusb_device_handle *usb_device_handle; enum ulink_type type; + unsigned int ep_in; /**< IN endpoint number */ + unsigned int ep_out; /**< OUT endpoint number */ + int delay_scan_in; /**< Delay value for SCAN_IN commands */ int delay_scan_out; /**< Delay value for SCAN_OUT commands */ int delay_scan_io; /**< Delay value for SCAN_IO commands */ @@ -250,7 +254,7 @@ static struct ulink *ulink_handle; /**************************** USB helper functions ****************************/ /** - * Opens the ULINK device and claims its USB interface. + * Opens the ULINK device * * Currently, only the original ULINK is supported * @@ -288,9 +292,6 @@ static int ulink_usb_open(struct ulink **device) return ERROR_FAIL; libusb_free_device_list(usb_devices, 1); - if (libusb_claim_interface(usb_device_handle, 0) != 0) - return ERROR_FAIL; - (*device)->usb_device_handle = usb_device_handle; (*device)->type = ULINK_1; @@ -725,7 +726,7 @@ static int ulink_execute_queued_commands(struct ulink *device, int timeout) } /* Send packet to ULINK */ - ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_OUT), + ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_out, (unsigned char *)buffer, count_out, &transferred, timeout); if (ret != 0) return ERROR_FAIL; @@ -734,7 +735,7 @@ static int ulink_execute_queued_commands(struct ulink *device, int timeout) /* Wait for response if commands contain IN payload data */ if (count_in > 0) { - ret = libusb_bulk_transfer(device->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN), + ret = libusb_bulk_transfer(device->usb_device_handle, device->ep_in, (unsigned char *)buffer, 64, &transferred, timeout); if (ret != 0) return ERROR_FAIL; @@ -2156,6 +2157,12 @@ static int ulink_init(void) } else LOG_INFO("ULINK device is already running OpenULINK firmware"); + /* Get OpenULINK USB IN/OUT endpoints and claim the interface */ + ret = jtag_libusb_choose_interface(ulink_handle->usb_device_handle, + &ulink_handle->ep_in, &ulink_handle->ep_out, -1, -1, -1, -1); + if (ret != ERROR_OK) + return ret; + /* Initialize OpenULINK command queue */ ulink_clear_queue(ulink_handle); @@ -2171,7 +2178,7 @@ static int ulink_init(void) * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ dummy = calloc(64, sizeof(uint8_t)); - ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, (2 | LIBUSB_ENDPOINT_IN), + ret = libusb_bulk_transfer(ulink_handle->usb_device_handle, ulink_handle->ep_in, dummy, 64, &transferred, 200); free(dummy); From 2bbd85a828f0ea43307a0ca92810570c376002d0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 5 Dec 2020 23:28:53 +0100 Subject: [PATCH 101/113] flash/nor/stmsmi: fix compile error with clang 12.0.0 The git preliminarily version of clang 12.0.0_r370171 f067bc3c0ad6 reports an error in the expansion of the macro SMI_READ_REG(): error: '(' and '{' tokens introducing statement expression appear in different macro expansion contexts [-Werror,-Wcompound-token-split-by-macro] Remove one intermediate macro expansion to make clang happy. Change-Id: I8ae6d9c18808467ba8044d70cbf0a4f76a18d3e6 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5958 Tested-by: jenkins Reviewed-by: Xiaofan --- src/flash/nor/stmsmi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index e73dd22f6..f633e3619 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -41,9 +41,8 @@ #include #include -#define SMI_READ_REG(a) (_SMI_READ_REG(a)) -#define _SMI_READ_REG(a) \ -{ \ +#define SMI_READ_REG(a) \ +({ \ int _ret; \ uint32_t _value; \ \ @@ -51,7 +50,7 @@ if (_ret != ERROR_OK) \ return _ret; \ _value; \ -} +}) #define SMI_WRITE_REG(a, v) \ { \ From 9d3f33757030c30c138405dd8a63cef8fd68184c Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 6 Dec 2020 18:19:01 +0100 Subject: [PATCH 102/113] doc: document adapter drivers linuxgpiod and sysfsgpio Change-Id: If894092a7ae04bb95fa1913d2e3c8465c2d0f75c Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5961 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- doc/openocd.texi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index cc7b6b22e..670d97040 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -623,6 +623,13 @@ emulation model of target hardware. @item @b{xlnx_pcie_xvc} @* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. +@item @b{linuxgpiod} +@* A bitbang JTAG driver using Linux GPIO through library libgpiod. + +@item @b{sysfsgpio} +@* A bitbang JTAG driver using Linux legacy sysfs GPIO. +This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. + @end itemize @node About Jim-Tcl @@ -3240,6 +3247,22 @@ pinout. @end deffn +@deffn {Interface Driver} {linuxgpiod} +Linux provides userspace access to GPIO through libgpiod since Linux kernel version v4.6. +The driver emulates either JTAG and SWD transport through bitbanging. + +See @file{interface/dln-2-gpiod.cfg} for a sample config. +@end deffn + + +@deffn {Interface Driver} {sysfsgpio} +Linux legacy userspace access to GPIO through sysfs is deprecated from Linux kernel version v5.3. +Prefer using @b{linuxgpiod}, instead. + +See @file{interface/sysfsgpio-raspberrypi.cfg} for a sample config. +@end deffn + + @deffn {Interface Driver} {openjtag} OpenJTAG compatible USB adapter. This defines some driver-specific commands: From 77f468893ebe908e0b036beae6abedc50e8298ba Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 30 May 2020 13:33:27 +0200 Subject: [PATCH 103/113] The openocd-0.11.0-rc1 release candidate Change-Id: I111fec1304482f5c0f9d6ee988be8a2ea3de3981 Signed-off-by: Antonio Borneo --- NEWS | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++- configure.ac | 2 +- 2 files changed, 207 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 9df165004..5c04e340f 100644 --- a/NEWS +++ b/NEWS @@ -2,27 +2,232 @@ This file includes highlights of the changes made in the OpenOCD source archive release. JTAG Layer: + * add debug level 4 for verbose I/O debug + * bitbang, add read buffer to improve performance + * Cadence SystemVerilog Direct Programming Interface (DPI) adapter driver + * CMSIS-DAP v2 (USB bulk based) adapter driver + * Cypress KitProg adapter driver + * FTDI FT232R sync bitbang adapter driver + * Linux GPIOD bitbang adapter driver through libgpiod + * Mellanox rshim USB or PCIe adapter driver + * Nuvoton Nu-Link and Nu-Link2 adapter drivers + * NXP IMX GPIO mmap based adapter driver + * ST-Link consolidate all versions in single config + * ST-Link read properly old USB serial numbers + * STLink/V3 support (for ST devices only !) + * STM8 SWIM transport + * TI XDS110 adapter driver + * Xilinx XVC/PCIe adapter driver Boundary Scan: Target Layer: + * 64 bit address support + * ARCv2 target support + * ARM Cortex-A hypervisor mode support + * ARM Cortex-M fast PC sampling support for profiling + * ARM generic CTI support + * ARM generic mem-ap target support + * ARMv7-A MMU tools + * ARMv7m traces add TCP stream server + * ARMv8 AARCH64 target support and semihosting support + * ARMv8 AARCH64 disassembler support through capstone library + * ARMv8-M target support + * EnSilica eSi-RISC target support, including instruction tracing + eSi-Trace support + * MIPS64 target support + * Motorola SREC S6 record image file support + * RISC-V target support + * SEGGER Real Time Transfer (RTT) initial support (for single target, + Cortex-M only) + * ST STM8 target support + * Various MIPS32 target improvements Flash Layer: + * Atheros (ath79) SPI interface support + * Atmel atmega128rfa1 support + * Atmel SAM D21, D51, DA1, E51, E53, E54, G55, R30 support + * Atmel SAMC2?N* support + * Cypress PSoC5LP, PSoC6 support + * EnSilica eSi-RISC support + * Foshan Synwit Tech SWM050 support + * Maxim Integrated MAX32XXX support + * Nordic Semiconductor nRF51822, nRF52810, nRF52832 support + * NXP Kinetis K27, K28, KE1x, KEAx, KL28, KL8x, KV5x, KWx support + * Renesas RPC HF support + * SH QSPI support + * SiFive Freedom E support + * Silicon Labs EFR-family, EZR32HG support + * ST BlueNRG support + * ST STM32 QUAD/OCTO-SPI interface support for Flash, FRAM and EEPROM + * ST STM32F72x, STM32F4x3, STM32H7xx support + * ST STM32G0xx, STM32G4xx, STM32L4x, STM32WB, STM32WL support + * ST STM32L5x support (non secure mode) + * TI CC13xx, CC26xx, CC32xx support + * TI MSP432 support + * Winner Micro w600 support + * Xilinx XCF platform support + * Various discrete SPI NOR flashes support Board, Target, and Interface Configuration Scripts: + * 8devices LIMA board config + * Achilles Instant-Development Kit Arria 10 board config + * Amazon Kindle 2 and DX board config + * Analog Devices ADSP-SC58x, ADSP-SC584-EZBRD board config + * Andes Technology ADP-XC7KFF676 board config + * Andes Technology Corvette-F1 board config + * ARM Musca A board config + * Arty Spartan 7 FPGA board config + * Atmel SAMD10 Xplained mini board config + * Atmel SAMD11 Xplained Pro board config + * Atmel SAM G55 Xplained Pro board config + * AVNET UltraZED EG StarterKit board config + * Blue Pill STM32F103C8 board config + * DP Busblaster v4.1a board config + * DPTechnics DPT-Board-v1 board config + * Emcraft imx8 SOM BSB board config + * Globalscale ESPRESSObin board config + * Kasli board config + * Kintex Ultrascale XCKU040 board config + * Knovative KC-100 board config + * LeMaker HiKey board config + * Microchip (Atmel) SAME54 Xplained Pro board config + * Microchip (Atmel) SAML11 Xplained Pro board config + * Nordic module NRF52 board config + * Numato Lab Mimas A7 board config + * NXP Freedom FRDM-LS1012A board config + * NXP IMX7SABRE board config + * NXP IMX8MP-EVK board config + * NXP MC-IMX8M-EVK board config + * QuickLogic QuickFeather board config + * Renesas R-Car E2, H2, M2 board config + * Renesas R-Car Salvator-X(S) board config + * Renesas RZ/A1H GR-Peach board config + * Rigado BMD-300 board config + * Sayma AMC board config + * Sifive e31arty, e51arty, hifive1 board config + * ST B-L475E-IOT01A board config + * ST BlueNRG idb007v1, idb008v1, idb011v1 board config + * ST STM32F412g discovery board config + * ST STM32F413h discovery board config + * ST STM32F469i discovery board config + * ST STM32F7 Nucleo board config + * ST STM32F723e discovery board config + * ST STM32F746g discovery board config + * ST STM32F769i discovery board config + * ST STM32H735g discovery board config + * ST STM32H743zi Nucleo board config + * ST STM32H745i discovery board config + * ST STM32H747i discovery board config + * ST STM32H750b discovery board config + * ST STM32H7b3i discovery board config + * ST STM32H7x_dual_qspi board config + * ST STM32H7x3i Eval boards config + * ST STM32L073 Nucleo board config + * ST STM32L476g discovery board config + * ST STM32L496g discovery board config + * ST STM32L4p5g discovery board config + * ST STM32L4r9i discovery board config + * ST STM32L5 Nucleo board config + * ST STM32MP15x DK2 board config + * ST STM32WB Nucleo board config + * ST STM8L152R8 Nucleo board config + * Synopsys DesignWare ARC EM board config + * Synopsys DesignWare ARC HSDK board config + * TI BeagleBone family boards config + * TI CC13xx, CC26xx, CC32xx LaunchPad board config + * TI MSP432 LaunchPad board config + * Tocoding Poplar board config + * TP-Link WDR4300 board config + * Allwinner V3s target config + * Andes Technology NDS V5 target config + * Atmel atmega128rfa1 target config + * ARM corelink SSE-200 target config + * Atheros_ar9344 target config + * Cypress PSoC5LP, PSoC6 target config + * EnSilica eSi-RISC target config + * Foshan Synwit Tech SWM050 target config + * GigaDevice GD32VF103 target config + * Hisilicon Hi3798 target config + * Hisilicon Hi6220 target config + * Infineon TLE987x target config + * Marvell Armada 3700 target config + * Maxim Integrated MAX32XXX target config + * Mellanox BlueField target config + * Microchip (Atmel) SAME5x, SAML1x target config + * NXP IMX6SX, IMX6UL, IMX7, IMX7ULP, IMX8 target config + * NXP Kinetis KE1xZ, KE1xF target config + * NXP LPC84x, LPC8Nxx, LS1012A, NHS31xx target config + * Qualcomm QCA4531 target config + * QuickLogic EOS S3 target config + * Renesas R-Car E2, H2, M2 target config + * Renesas R-Car Gen3 target config + * Renesas RZ/A1H target config + * Rockchip RK3308 target config + * ST BlueNRG target config + * ST STM32G0, STM32G4, STM32H7, STM32L0, STM32L5 target config + * ST STM32MP15x target config + * ST STM32WBx, STM32WLEx target config + * ST STM8L152, S003, S103, S105 target config + * Synopsys DesignWare ARC EM target config + * Synopsys DesignWare ARC HS Development Kit SoC target config + * TI CC13xx, CC26xx, CC32xx target config + * TI TNETC4401 target config + * Xilinx UltraScale+ target config + * Altera 5M570Z (MAXV family) CPLD config + * Xilinx Ultrascale, XCF CPLD config + * Intel (Altera) Arria10 FPGA config + * Cadence SystemVerilog Direct Programming Interface (DPI) interface config + * Cypress KitProg interface config + * Digilent SMT2 NC interface config + * DLN-2 example of Linux GPIOD interface config + * FTDI C232HM interface config + * HIE JTAG Debugger interface config + * In-Circuit's ICprog interface config + * isodebug isolated JTAG/SWD+UART interface config + * Mellanox rshim USB or PCIe interface config + * Nuvoton Nu-Link interface config + * NXP IMX GPIO mmap based interface config + * Steppenprobe open hardware interface config + * TI XDS110 interface config Server Layer: + * 64 bit address support + * default bind to IPv4 localhost + * gdb: allow multiple connections + * gdb: architecture element support + * gdb: vCont, vRun support + * telnet: handle Ctrl+A, Ctrl+E and Ctrl+K + +RTOS: + * Chromium-EC rtos support + * hwthread pseudo rtos support + * NuttX rtos support + * RIOT rtos support Documentation: + * Improve STM32 flash driver + * Various typo fix and improvements Build and Release: + * Add libutil to support jimtcl version 0.80 + * Clang warning fixes + * GitHub workflow for Win32 snapshot binaries + * Handle Tcl return values consistently + * Mitigation for CVE-2018-5704: Prevent some forms of Cross + Protocol Scripting attacks + * Support for libftdi 1.5 + * Travis-CI basic support + * Update libjaylink to version 0.2.0 + * Update jimtcl to version 0.79 + * Use external (optional) library capstone for ARM and AARCH64 disassembly This release also contains a number of other important functional and cosmetic bugfixes. For more details about what has changed since the last release, see the git repository history: -http://sourceforge.net/p/openocd/code/ci/v0.x.0/log/?path= +http://sourceforge.net/p/openocd/code/ci/v0.11.0-rc1/log/?path= For older NEWS, see the NEWS files associated with each release diff --git a/configure.ac b/configure.ac index c8978b94d..884f0c612 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.64) -AC_INIT([openocd], [0.10.0+dev], +AC_INIT([openocd], [0.11.0-rc1], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) AC_CONFIG_AUX_DIR([.]) From 0dd3b7fa6c7930446967772832a351e90c426d69 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 10 Dec 2020 01:43:12 +0300 Subject: [PATCH 104/113] Restore +dev suffix Signed-off-by: Paul Fertser --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 884f0c612..236d6bc28 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.64) -AC_INIT([openocd], [0.11.0-rc1], +AC_INIT([openocd], [0.11.0-rc1+dev], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) AC_CONFIG_AUX_DIR([.]) From 4bc8fd24fb7670065fb4fb0077217d0b8cbcfa45 Mon Sep 17 00:00:00 2001 From: Luca Lindhorst Date: Thu, 3 Dec 2020 12:34:41 +0100 Subject: [PATCH 105/113] Correct warning message The warning message regarding wrong verification checksum for LPC2000, claims that the verification will fail, but the checksum written correctly by openocd. Clarify this in the warning message. Change-Id: I929ac767f7f9fdad9bace250c8c04a776462800a Signed-off-by: Luca Lindhorst Reviewed-on: http://openocd.zylin.com/5956 Tested-by: jenkins Reviewed-by: Jonathan McDowell Reviewed-by: Antonio Borneo --- src/flash/nor/lpc2000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 942ef555c..3ad62d669 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -1103,9 +1103,9 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { - LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is " + LOG_WARNING("Boot verification checksum in image (0x%8.8" PRIx32 ") to be written to flash is " "different from calculated vector checksum (0x%8.8" PRIx32 ").", original_value, checksum); - LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector " + LOG_WARNING("OpenOCD will write the correct checksum. To remove this warning modify build tools on developer PC to inject correct LPC vector " "checksum."); } From 4fc0f3530c5133ac76b1659d3da55970a32bea94 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 7 Dec 2020 22:51:46 +0100 Subject: [PATCH 106/113] Makefile.am: fix non-POSIX warning from automake Automake issues a warning Makefile.am:46: warning: wildcard $(srcdir: non-POSIX variable name Makefile.am:46: (probably a GNU make extension) because the GNU make function 'wildcard' is not POSIX. Also the GNU make function 'shell' triggers a similar warning. Use the POSIX extension '!=', that executes an arbitrary shell command, to replace the GNU make 'wildcard'. Don't include the file 'NEWS' because automake already includes it by default. Change-Id: Ice560c3789cec4f3f2197a255d6f5af7b1fde634 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5965 Tested-by: jenkins Reviewed-by: Jonathan McDowell --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 930a30733..7a718d769 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,13 +43,14 @@ if INTERNAL_JIMTCL AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \ -I$(top_builddir)/jimtcl endif +EXTRA_DIST_NEWS != ls $(srcdir)/NEWS-* EXTRA_DIST += \ BUGS \ HACKING \ NEWTAPS \ README.Windows \ README.OSX \ - $(wildcard $(srcdir)/NEWS*) \ + $(EXTRA_DIST_NEWS) \ Doxyfile.in \ tools/logger.pl \ tools/rlink_make_speed_table \ From 88592cc1a194b48946abc29503c57a6020b791e7 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 13 Dec 2020 10:28:56 +0000 Subject: [PATCH 107/113] LICENSES: Update GFDL invariant text to match official wording This was flagged by lintian against the Debian package; the text stating there are no invariant sections deviates from the official GNU wording. Update it to match the text at the bottom of: https://www.gnu.org/licenses/old-licenses/fdl-1.2.en.html Change-Id: Ie222237a8eede24c1b71218b05e1513b74208a47 Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/5974 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 670d97040..9e060b383 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -30,9 +30,9 @@ of the Open On-Chip Debugger (OpenOCD). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no -Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -Texts. A copy of the license is included in the section entitled ``GNU -Free Documentation License''. +Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A +copy of the license is included in the section entitled ``GNU Free +Documentation License''. @end quotation @end copying From 722f5797069bc233c8e1b71bdab283766d6be9b3 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 14 Dec 2020 17:08:06 +0100 Subject: [PATCH 108/113] armv7m_trace: stop getting traces from adapter at exit If OpenOCD is reading trace data from the target, at exit it should stop the adapter to gather data, but should left the target still producing them. Add a helper in armv7m_trace to disable the adapter's trace and call it during OpenOCD teardown. This also provides a workaround for an issue in the firmware of ST-Link V3 till version V3J7. If the SWD connection is closed when trace is active, at following connection the trace does not work anymore. Change-Id: I47ccab61405384938555096c5aca789eaa090d27 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5978 Reviewed-by: Jonathan McDowell Tested-by: jenkins --- src/target/armv7m_trace.c | 15 +++++++++++++++ src/target/armv7m_trace.h | 4 ++++ src/target/cortex_m.c | 2 ++ 3 files changed, 21 insertions(+) diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c index 916d1a164..10f14221d 100644 --- a/src/target/armv7m_trace.c +++ b/src/target/armv7m_trace.c @@ -234,6 +234,21 @@ static int trace_connection_closed(struct connection *connection) return ERROR_OK; } +extern struct command_context *global_cmd_ctx; + +int armv7m_trace_tpiu_exit(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + + if (global_cmd_ctx->mode == COMMAND_CONFIG || + armv7m->trace_config.config_type == TRACE_CONFIG_TYPE_DISABLED) + return ERROR_OK; + + close_trace_channel(armv7m); + armv7m->trace_config.config_type = TRACE_CONFIG_TYPE_DISABLED; + return armv7m_trace_tpiu_config(target); +} + COMMAND_HANDLER(handle_tpiu_config_command) { struct target *target = get_current_target(CMD_CTX); diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h index 076f9d582..cdf79e74c 100644 --- a/src/target/armv7m_trace.h +++ b/src/target/armv7m_trace.h @@ -95,6 +95,10 @@ extern const struct command_registration armv7m_trace_command_handlers[]; * Configure hardware accordingly to the current TPIU target settings */ int armv7m_trace_tpiu_config(struct target *target); +/** + * Disable TPIU data gathering at exit + */ +int armv7m_trace_tpiu_exit(struct target *target); /** * Configure hardware accordingly to the current ITM target settings */ diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 316089c35..ac308b43b 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1648,6 +1648,8 @@ void cortex_m_deinit_target(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); + armv7m_trace_tpiu_exit(target); + free(cortex_m->fp_comparator_list); cortex_m_dwt_free(target); From ed73398eb0b4ce6db63e5cec447ab052d084261a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 2 Dec 2020 22:04:12 +0100 Subject: [PATCH 109/113] cortex-a: fix reset on dapdirect transports The target code for assert reset on cortex_a has been patched on commit b0698501b0e7 ("cortex_a: fix cortex_a_assert_reset() if srst_gates_jtag") then in cdba6ba0ad63 ("cortex_a: fix reset for SWD transport") to workaround the mismatch between jtag and swd implementations. See discussion for the second patch at http://openocd.zylin.com/3641/ While all of these mismatches should hopefully be cleaned by the reset framework rework, an extension of the workaround of the second patch is required for dapdirect transports, either dapdirect_swd and dapdirect_jtag. Extend the existing workaround to all non-jtag transports. Change-Id: Ia6a9d43bab524cbb3de4c37ce24c45f25187353d Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5979 Tested-by: jenkins --- src/target/cortex_a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index f39fd9b2b..d27c298b6 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1681,10 +1681,10 @@ static int cortex_a_assert_reset(struct target *target) */ /* - * FIXME: fix reset when transport is SWD. This is a temporary + * FIXME: fix reset when transport is not JTAG. This is a temporary * work-around for release v0.10 that is not intended to stay! */ - if (transport_is_swd() || + if (!transport_is_jtag() || (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) adapter_assert_reset(); From 6090390a23158b1463be3ffc8ac5731843b73586 Mon Sep 17 00:00:00 2001 From: Jiri Kastner Date: Wed, 16 Dec 2020 20:51:06 +0100 Subject: [PATCH 110/113] tcl/target/rk3308.cfg: add defer-examine only core0 is brought up by bootloader Change-Id: I1d6b5e6ba7498beadbf3805f4271f0197e411bd5 Signed-off-by: Jiri Kastner Reviewed-on: http://openocd.zylin.com/5980 Reviewed-by: Antonio Borneo Tested-by: jenkins Reviewed-by: Jonathan McDowell --- tcl/target/rk3308.cfg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tcl/target/rk3308.cfg b/tcl/target/rk3308.cfg index b55109312..7f957da06 100644 --- a/tcl/target/rk3308.cfg +++ b/tcl/target/rk3308.cfg @@ -28,7 +28,7 @@ swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID -ignore-version dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 -# declare the 8 main application cores +# declare the 4 main application cores set _TARGETNAME $_CHIPNAME.core set _smp_command "" @@ -53,6 +53,7 @@ for { set _core 0 } { $_core < $_cores } { incr _core 1 } { if { $_core != 0 } { set _smp_command "$_smp_command ${_TARGETNAME}$_core" + set _command "$_command -defer-examine" } else { # uncomment to use hardware threads pseudo rtos # set _command "$_command -rtos hwthread" From 433e37f02f6a38a3905b84f2aac12fdd66045137 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Dec 2020 15:44:41 +0100 Subject: [PATCH 111/113] rtos/hwthread: fix register list for armv7a The targets armv7a in file cortex_a.c inherit the register list from file armv4_5.c thus, depending on the core status, some register get marked as not existing. For HW threads other than current target, the registers in the list are not checked for existence and are all forwarded to GDB that in turns complains for too many data: Remote 'g' packet reply is too long (expected 68 bytes, got 104 bytes) Check all the attributes of the registers and pass to GDB only the valid registers. To test it, use a SMP cortex-a target (2 cores are enough) and add -rtos hwthread to all the cores. Connect GDB to OpenOCD and issue the GDB command info threads Change-Id: Ie66119fe83a3c8d53e9d18dda39e60fd97769669 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5981 Tested-by: jenkins --- src/rtos/hwthread.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 850b93223..e2d1ccf13 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -237,23 +237,35 @@ static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, if (!target_was_examined(curr)) return ERROR_FAIL; + int reg_list_size; struct reg **reg_list; - int retval = target_get_gdb_reg_list(curr, ®_list, rtos_reg_list_size, + int retval = target_get_gdb_reg_list(curr, ®_list, ®_list_size, REG_CLASS_GENERAL); if (retval != ERROR_OK) return retval; + int j = 0; + for (int i = 0; i < reg_list_size; i++) { + if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden) + continue; + j++; + } + *rtos_reg_list_size = j; *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg)); if (*rtos_reg_list == NULL) { free(reg_list); return ERROR_FAIL; } - for (int i = 0; i < *rtos_reg_list_size; i++) { - (*rtos_reg_list)[i].number = (*reg_list)[i].number; - (*rtos_reg_list)[i].size = (*reg_list)[i].size; - memcpy((*rtos_reg_list)[i].value, (*reg_list)[i].value, + j = 0; + for (int i = 0; i < reg_list_size; i++) { + if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden) + continue; + (*rtos_reg_list)[j].number = (*reg_list)[i].number; + (*rtos_reg_list)[j].size = (*reg_list)[i].size; + memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value, ((*reg_list)[i].size + 7) / 8); + j++; } free(reg_list); From 7f74906c2d18a2347ec392f9a457963bff3f25b8 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Dec 2020 16:15:54 +0100 Subject: [PATCH 112/113] gdb_server: minor fix for indentation Use a TAB in place of 4 spaces Change-Id: Ic34b7c3ef24078d2c36a193d4dd079bca5a7ef2e Signed-off-by: Antonio Borneo Fixes: a4cdce0129a6 ("gdb_server: prevent false positive valgrind report") Reviewed-on: http://openocd.zylin.com/5982 Tested-by: jenkins Reviewed-by: Jonathan McDowell --- src/server/gdb_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 792bbdcea..c1e90a04a 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2516,7 +2516,7 @@ static int gdb_get_thread_list_chunk(struct target *target, char **thread_list, transfer_type = 'l'; *chunk = malloc(length + 2 + 3); - /* Allocating extra 3 bytes prevents false positive valgrind report + /* Allocating extra 3 bytes prevents false positive valgrind report * of strlen(chunk) word access: * Invalid read of size 4 * Address 0x4479934 is 44 bytes inside a block of size 45 alloc'd */ From c69b4deae36a7bcbab5df80ec2a5dbfd652e25ac Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 19 Dec 2020 22:31:29 +0100 Subject: [PATCH 113/113] gdb_server: fix HW thread status at gdb attach At gdb attach, the event TARGET_EVENT_GDB_ATTACH is in charge of halting the target. For HW thread, rtos_update_threads() should be called after the event to detect and record the new 'halted' status. Instead it is called immediately before the event, thus reading the status before the halt. Move after the event the call to rtos_update_threads(). Change-Id: Iab3480ea0f5283ed6580f0f6c11200083197d1e9 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5983 Tested-by: jenkins --- src/server/gdb_server.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index c1e90a04a..9e44287fd 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -969,15 +969,6 @@ static int gdb_new_connection(struct connection *connection) breakpoint_clear_target(target); watchpoint_clear_target(target); - if (target->rtos) { - /* clean previous rtos session if supported*/ - if (target->rtos->type->clean) - target->rtos->type->clean(target); - - /* update threads */ - rtos_update_threads(target); - } - /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); if (retval != ERROR_OK) @@ -990,6 +981,15 @@ static int gdb_new_connection(struct connection *connection) gdb_putback_char(connection, initial_ack); target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); + if (target->rtos) { + /* clean previous rtos session if supported*/ + if (target->rtos->type->clean) + target->rtos->type->clean(target); + + /* update threads */ + rtos_update_threads(target); + } + if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. *