You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(57) |
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(14) |
Nov
(36) |
Dec
(7) |
2007 |
Jan
(48) |
Feb
(10) |
Mar
(17) |
Apr
(8) |
May
(35) |
Jun
(28) |
Jul
(50) |
Aug
(71) |
Sep
(40) |
Oct
(19) |
Nov
(22) |
Dec
(143) |
2008 |
Jan
(184) |
Feb
(549) |
Mar
(381) |
Apr
(388) |
May
(148) |
Jun
(128) |
Jul
(502) |
Aug
(243) |
Sep
(136) |
Oct
(327) |
Nov
(252) |
Dec
(475) |
2009 |
Jan
(344) |
Feb
(185) |
Mar
(338) |
Apr
(826) |
May
(1559) |
Jun
(1429) |
Jul
(817) |
Aug
(451) |
Sep
(639) |
Oct
(935) |
Nov
(1222) |
Dec
(826) |
2010 |
Jan
(552) |
Feb
(532) |
Mar
(355) |
Apr
(206) |
May
(162) |
Jun
(203) |
Jul
(168) |
Aug
(232) |
Sep
(270) |
Oct
(259) |
Nov
(439) |
Dec
(468) |
2011 |
Jan
(224) |
Feb
(249) |
Mar
(278) |
Apr
(381) |
May
(316) |
Jun
(637) |
Jul
(544) |
Aug
(465) |
Sep
(159) |
Oct
(440) |
Nov
(139) |
Dec
|
2012 |
Jan
(204) |
Feb
(383) |
Mar
(295) |
Apr
(196) |
May
(590) |
Jun
(158) |
Jul
(167) |
Aug
(177) |
Sep
(179) |
Oct
(301) |
Nov
(144) |
Dec
(173) |
2013 |
Jan
(299) |
Feb
(120) |
Mar
(238) |
Apr
(140) |
May
(69) |
Jun
(133) |
Jul
(160) |
Aug
(107) |
Sep
(164) |
Oct
(196) |
Nov
(105) |
Dec
(74) |
2014 |
Jan
(205) |
Feb
(156) |
Mar
(175) |
Apr
(181) |
May
(162) |
Jun
(158) |
Jul
(117) |
Aug
(109) |
Sep
(148) |
Oct
(106) |
Nov
(82) |
Dec
(72) |
2015 |
Jan
(191) |
Feb
(205) |
Mar
(197) |
Apr
(163) |
May
(136) |
Jun
(36) |
Jul
(79) |
Aug
(55) |
Sep
(64) |
Oct
(146) |
Nov
(142) |
Dec
(78) |
2016 |
Jan
(65) |
Feb
(190) |
Mar
(53) |
Apr
(38) |
May
(95) |
Jun
(53) |
Jul
(58) |
Aug
(113) |
Sep
(96) |
Oct
(59) |
Nov
(136) |
Dec
(124) |
2017 |
Jan
(80) |
Feb
(109) |
Mar
(163) |
Apr
(78) |
May
(61) |
Jun
(73) |
Jul
(29) |
Aug
(47) |
Sep
(60) |
Oct
(76) |
Nov
(48) |
Dec
(35) |
2018 |
Jan
(138) |
Feb
(84) |
Mar
(109) |
Apr
(49) |
May
(24) |
Jun
(62) |
Jul
(96) |
Aug
(116) |
Sep
(53) |
Oct
(99) |
Nov
(80) |
Dec
(88) |
2019 |
Jan
(100) |
Feb
(141) |
Mar
(72) |
Apr
(174) |
May
(129) |
Jun
(102) |
Jul
(52) |
Aug
(45) |
Sep
(28) |
Oct
(43) |
Nov
(78) |
Dec
(47) |
2020 |
Jan
(113) |
Feb
(72) |
Mar
(94) |
Apr
(141) |
May
(82) |
Jun
(68) |
Jul
(125) |
Aug
(76) |
Sep
(33) |
Oct
(184) |
Nov
(61) |
Dec
(95) |
2021 |
Jan
(109) |
Feb
(77) |
Mar
(145) |
Apr
(116) |
May
(134) |
Jun
(113) |
Jul
(71) |
Aug
(118) |
Sep
(116) |
Oct
(92) |
Nov
(124) |
Dec
(68) |
2022 |
Jan
(57) |
Feb
(61) |
Mar
(57) |
Apr
(74) |
May
(86) |
Jun
(80) |
Jul
(43) |
Aug
(85) |
Sep
(120) |
Oct
(88) |
Nov
(100) |
Dec
(108) |
2023 |
Jan
(39) |
Feb
(56) |
Mar
(92) |
Apr
(81) |
May
(84) |
Jun
(72) |
Jul
(182) |
Aug
(82) |
Sep
(54) |
Oct
(68) |
Nov
(67) |
Dec
(75) |
2024 |
Jan
(79) |
Feb
(65) |
Mar
(42) |
Apr
(47) |
May
(68) |
Jun
(111) |
Jul
(43) |
Aug
(73) |
Sep
(100) |
Oct
(35) |
Nov
(100) |
Dec
(99) |
2025 |
Jan
(71) |
Feb
(68) |
Mar
(44) |
Apr
(40) |
May
(92) |
Jun
(45) |
Jul
(86) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <ge...@op...> - 2025-06-08 16:39:36
|
This is an automated email from Gerrit. "zapb <de...@za...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8943 -- gerrit commit 7b06bebf97e2f46aa77a2753f124d2707146c77a Author: Marc Schink <de...@za...> Date: Thu Feb 20 20:58:08 2025 +0000 adapter: Rework parallel port driver Make the driver more flexible and allow to specify adapter specific configuration in Tcl rather than in C, similar to the FTDI driver. The rework also includes coding style fixes and improvements of the documentation. All modifications are done such that backwards compatibility is ensured. Tested with Olimex ARM-JTAG cable [1] and APM32F103 target device on Linux and FreeBSD. The driver works on Linux using direct I/O and PPDEV. On FreeBSD, only PPDEV works. The build with direct I/O already failed before the patch. This problem will be fixed in a subsequent patch. The patch is not tested on Windows because there is no documentation for it. [1] https://www.olimex.com/Products/ARM/JTAG/ARM-JTAG/ Change-Id: Ib671d52a919eaf2959cf6365f2c8004257ae074c Signed-off-by: Marc Schink <de...@za...> diff --git a/doc/openocd.texi b/doc/openocd.texi index bd6b3704a8..869efebb6e 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -529,9 +529,8 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @section IBM PC Parallel Printer Port Based -The two well-known ``JTAG Parallel Ports'' cables are the Xilinx DLC5 -and the Macraigor Wiggler. There are many clones and variations of -these on the market. +The two well-known JTAG parallel port cables are the Xilinx DLC5 and the Macraigor Wiggler. +There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor @@ -553,7 +552,7 @@ produced, PDF schematics are easily found and it is easy to make. @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} -@* Yet another variation - See the source code, src/jtag/parport.c +@* Yet another variation - see configuration in @file{interface/parport/wiggler-ntrst-inverted.cfg} @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @@ -3078,61 +3077,102 @@ version, and target voltage. @end deffn @deffn {Interface Driver} {parport} -Supports PC parallel port bit-banging cables: -Wigglers, PLD download cable, and more. -These interfaces have several commands, used to configure the driver -before initializing the JTAG scan chain: -@deffn {Config Command} {parport cable} name -Set the layout of the parallel port cable used to connect to the target. -This is a write-once setting. -Currently valid cable @var{name} values include: +Supports PC parallel port bit-banging adapters. +The interface only supports JTAG as transport. + +The driver supports Linux, FreeBSD, and Windows. +However, the Windows support is untested and unmaintained. + +@deffn {Config Command} {parport port} port_number +Configure the number of the parallel port. + +When using PPDEV to access the parallel port, use the number of the parallel port file @file{/dev/parport} (Linux) or @file{/dev/ppi} (FreeBSD). +The default port number is 0. + +When using direct I/O, the number is the I/O port number. +The default port number is 0x378 (LTP1). +@end deffn + +@deffn {Config Command} {parport layout_signal} name mask +Configure the layout of the parallel port cable used to connect to the target. +The @var{name} must be one of the following signal names: @itemize @minus -@item @b{altium} Altium Universal JTAG cable. -@item @b{arm-jtag} Same as original wiggler except SRST and -TRST connections reversed and TRST is also inverted. -@item @b{chameleon} The Amontec Chameleon's CPLD when operated -in configuration mode. This is only used to -program the Chameleon itself, not a connected target. -@item @b{dlc5} The Xilinx Parallel cable III. -@item @b{flashlink} The ST Parallel cable. -@item @b{lattice} Lattice ispDOWNLOAD Cable -@item @b{old_amt_wiggler} The Wiggler configuration that comes with -some versions of -Amontec's Chameleon Programmer. The new version available from -the website uses the original Wiggler layout ('@var{wiggler}') -@item @b{triton} The parallel port adapter found on the -``Karo Triton 1 Development Board''. -This is also the layout used by the HollyGates design -(see @uref{http://www.lartmaker.nl/projects/jtag/}). -@item @b{wiggler} The original Wiggler layout, also supported by -several clones, such as the Olimex ARM-JTAG -@item @b{wiggler2} Same as original wiggler except an led is fitted on D5. -@item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. +@item @b{tdo}: JTAG TDO signal +@item @b{tdi} JTAG TDI signal +@item @b{tms} JTAG TMS signal +@item @b{tck} JTAG TCK signal +@item @b{trst} JTAG TRST signal +@item @b{output-invert} Virtual signal to invert an output pin +@item @b{input-invert} Virtual signal to invert an input pin +@item @b{led} LED indicator signal @end itemize + +The @var{mask} must be an 8-bit integer value. +A mask for the signals @b{tdo}, @b{tdi}, @b{tms}, and @b{tck} must be specified, all others are optional. + +The data and status pins of the parallel port are used as output and input pins, respectively. +The mapping between mask bits and the parallel port pins is given in the following table. + +@multitable @columnfractions .2 .1 .1 .1 .1 .1 .1 .1 .1 +@headitem Pin direction @tab Bit 7 @tab Bit 6 @tab Bit 5 @tab Bit 4 @tab Bit 3 @tab Bit 2 @tab Bit 1 @tab Bit 0 +@item Input +@tab ~11 +@tab 10 +@tab 12 +@tab 13 +@tab 15 +@tab - +@tab - +@tab - +@item Output +@tab 9 +@tab 8 +@tab 7 +@tab 6 +@tab 5 +@tab 4 +@tab 3 +@tab 2 +@end multitable + +For example, in order to configure the JTAG TDO signal on pin 11, bit 7 must be set in the mask: + +@example +parport layout_signal tdo 0x80 +@end example + +Since pin 11 is always inverted by hardware, you need to invert the signal for correct operation. +This can be done using the virtual @emph{input-invert} signal: + +@example +parport layout_signal input-invert 0x80 +@end example @end deffn -@deffn {Config Command} {parport port} [port_number] -Display either the address of the I/O port -(default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. -If a parameter is provided, first switch to use that port. -This is a write-once setting. +@deffn {Config Command} {parport layout_init} mask +Configure the state of the output pins during the driver initialization. +For the mapping between bits and parallel port pins, see @command{parport layout_signal}. +@end deffn -When using PPDEV to access the parallel port, use the number of the parallel port: -@option{parport port 0} (the default). If @option{parport port 0x378} is specified -you may encounter a problem. +@deffn {Config Command} {parport layout_exit} mask +Configure the state of the output pins after driver shutdown. +The state is only set if enabled by the @command{parport write_on_exit} command. +For the mapping between bits and parallel port pins, see @command{parport layout_signal}. @end deffn -@deffn {Config Command} {parport toggling_time} [nanoseconds] -Displays how many nanoseconds the hardware needs to toggle TCK; -the parport driver uses this value to obey the -@command{adapter speed} configuration. -When the optional @var{nanoseconds} parameter is given, -that setting is changed before displaying the current value. +@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) +Configure whether the driver sets the value specified by @command{parport layout_exit} to the output pins on shutdown. +@end deffn + +@deffn {Config Command} {parport toggling_time} time +Configure how many nanoseconds the hardware needs to toggle TCK. +The driver uses this value to obey the @command{adapter speed} configuration. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. + @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @@ -3140,15 +3180,18 @@ oscilloscope, follow the procedure below: > parport toggling_time 1000 > adapter speed 500 @end example + This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: + @example > parport toggling_time <measured nanoseconds> @end example + Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. @@ -3160,20 +3203,6 @@ match with the rate you specified in the @command{adapter speed} command; be conservative. @end quotation @end deffn - -@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) -This will configure the parallel driver to write a known -cable-specific value to the parallel interface on exiting OpenOCD. -@end deffn - -For example, the interface configuration file for a -classic ``Wiggler'' cable on LPT2 might look something like this: - -@example -adapter driver parport -parport port 0x278 -parport cable wiggler -@end example @end deffn @deffn {Interface Driver} {presto} diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 143f3bde1f..d9e61d2be6 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -20,7 +20,7 @@ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <machine/sysarch.h> #include <machine/cpufunc.h> -#define ioperm(startport, length, enable)\ +#define ioperm(startport, length, enable) \ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ @@ -45,67 +45,60 @@ #include <windows.h> #endif -// Parallel port cable description. -struct cable { - const char *name; - // Status port bit containing current TDO value. - uint8_t tdo_mask; - // Data port bit for TRST. - uint8_t trst_mask; - // Data port bit for TMD. - uint8_t tms_mask; - // Data port bit for TCK. - uint8_t tck_mask; - // Data port bit for TDI. - uint8_t tdi_mask; - // Data port bit for SRST. - uint8_t srst_mask; - // Data port bits that should be inverted. - uint8_t output_invert; - // Status port that should be inverted. - uint8_t input_invert; - // Initialize data port with this value. - uint8_t port_init; - // De-initialize data port with this value. - uint8_t port_exit; - // Data port bit for LED. - uint8_t led_mask; +enum signal { + SIGNAL_TDO = 0, + SIGNAL_TRST, + SIGNAL_TMS, + SIGNAL_TCK, + SIGNAL_TDI, + SIGNAL_SRST, + SIGNAL_OUTPUT_INVERT, + SIGNAL_INPUT_INVERT, + SIGNAL_LED, }; -static const struct cable cables[] = { - /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ - { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, - { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, - { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, - { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, -/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: - HARD TCK - Target TCK - HARD TMS - Target TMS - HARD TDI - Target TDI - HARD TDO - Target TDO - SOFT TCK - Target TRST - SOFT TDI - Target SRST -*/ - { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, - { "aspo", 0x10, 0x01, 0x04, 0x08, 0x02, 0x10, 0x17, 0x00, 0x17, 0x17, 0x00 }, - { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +const char *signal_names[] = { + [SIGNAL_TDO] = "tdo", + [SIGNAL_TRST] = "trst", + [SIGNAL_TMS] = "tms", + [SIGNAL_TCK] = "tck", + [SIGNAL_TDI] = "tdi", + [SIGNAL_SRST] = "srst", + [SIGNAL_OUTPUT_INVERT] = "output-invert", + [SIGNAL_INPUT_INVERT] = "input-invert", + [SIGNAL_LED] = "led", }; -// Configuration variables. -static char *parport_cable; +static enum signal required_signals[] = { + SIGNAL_TDO, + SIGNAL_TMS, + SIGNAL_TCK, + SIGNAL_TDI, +}; + +static bool find_signal_by_name(const char *name, enum signal *signal) +{ + for (size_t i = 0; i < ARRAY_SIZE(signal_names); i++) { + if (!strcmp(name, signal_names[i])) { + *signal = i; + return true; + } + } + + return false; +} + +// Initialize data port with this value. +static uint8_t parport_init_state; +// De-initialize data port with this value. +static uint8_t parport_exit_state; +static uint8_t parport_signal_masks[ARRAY_SIZE(signal_names)]; static uint16_t parport_port; -static bool parport_exit; +static bool parport_write_exit_state; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; // Interface variables. -static const struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 @@ -125,7 +118,7 @@ static enum bb_value parport_read(void) data = inb(statusport); #endif - if ((data ^ cable->input_invert) & cable->tdo_mask) + if ((data ^ parport_signal_masks[SIGNAL_INPUT_INVERT]) & parport_signal_masks[SIGNAL_TDO]) return BB_HIGH; else return BB_LOW; @@ -133,8 +126,7 @@ static enum bb_value parport_read(void) static inline void parport_write_data(void) { - uint8_t output; - output = dataport_value ^ cable->output_invert; + const uint8_t output = dataport_value ^ parport_signal_masks[SIGNAL_OUTPUT_INVERT]; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); @@ -149,24 +141,28 @@ static inline void parport_write_data(void) static int parport_write(int tck, int tms, int tdi) { - int i = wait_states + 1; + const uint8_t tck_mask = parport_signal_masks[SIGNAL_TCK]; if (tck) - dataport_value |= cable->tck_mask; + dataport_value |= tck_mask; else - dataport_value &= ~cable->tck_mask; + dataport_value &= ~tck_mask; + + const uint8_t tms_mask = parport_signal_masks[SIGNAL_TMS]; if (tms) - dataport_value |= cable->tms_mask; + dataport_value |= tms_mask; else - dataport_value &= ~cable->tms_mask; + dataport_value &= ~tms_mask; + + const uint8_t tdi_mask = parport_signal_masks[SIGNAL_TDI]; if (tdi) - dataport_value |= cable->tdi_mask; + dataport_value |= tdi_mask; else - dataport_value &= ~cable->tdi_mask; + dataport_value &= ~tdi_mask; - while (i-- > 0) + for (int i = 0; i < wait_states + 1; i++) parport_write_data(); return ERROR_OK; @@ -177,15 +173,19 @@ static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); + const uint8_t trst_mask = parport_signal_masks[SIGNAL_TRST]; + if (trst == 0) - dataport_value |= cable->trst_mask; + dataport_value |= trst_mask; else if (trst == 1) - dataport_value &= ~cable->trst_mask; + dataport_value &= ~trst_mask; + + const uint8_t srst_mask = parport_signal_masks[SIGNAL_SRST]; if (srst == 0) - dataport_value |= cable->srst_mask; + dataport_value |= srst_mask; else if (srst == 1) - dataport_value &= ~cable->srst_mask; + dataport_value &= ~srst_mask; parport_write_data(); @@ -194,10 +194,12 @@ static int parport_reset(int trst, int srst) static int parport_led(bool on) { + const uint8_t led_mask = parport_signal_masks[SIGNAL_LED]; + if (on) - dataport_value |= cable->led_mask; + dataport_value |= led_mask; else - dataport_value &= ~cable->led_mask; + dataport_value &= ~led_mask; parport_write_data(); @@ -213,11 +215,12 @@ static int parport_speed(int speed) static int parport_khz(int khz, int *jtag_speed) { if (!khz) { - LOG_DEBUG("RCLK not supported"); + LOG_ERROR("RCLK is not supported"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); + return ERROR_OK; } @@ -226,32 +229,35 @@ static int parport_speed_div(int speed, int *khz) uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; + return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 -static int parport_get_giveio_access(void) +static bool parport_get_giveio_access(void) { - HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; - return -1; + return false; } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) - return 0; + return true; + + HANDLE h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); - h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; - return -1; + return false; } CloseHandle(h); - return 0; + return true; } #endif @@ -263,78 +269,65 @@ static const struct bitbang_interface parport_bitbang = { static int parport_init(void) { - const struct cable *cur_cable; -#if PARPORT_USE_PPDEV == 1 - char buffer[256]; -#endif - - cur_cable = cables; - - if (!parport_cable) { - parport_cable = strdup("wiggler"); - LOG_WARNING("No parport cable specified, using default 'wiggler'"); - } + for (size_t i = 0; i < ARRAY_SIZE(required_signals); i++) { + const enum signal signal = required_signals[i]; - while (cur_cable->name) { - if (!strcmp(cur_cable->name, parport_cable)) { - cable = cur_cable; - break; + if (!parport_signal_masks[signal]) { + LOG_ERROR("Required signal mask '%s' is not specified", + signal_names[signal]); + return ERROR_FAIL; } - cur_cable++; - } - - if (!cable) { - LOG_ERROR("No matching cable found for %s", parport_cable); - return ERROR_JTAG_INIT_FAILED; } - dataport_value = cable->port_init; + dataport_value = parport_init_state; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { - LOG_ERROR("device is already opened"); + LOG_ERROR("Parallel port is already open"); return ERROR_JTAG_INIT_FAILED; } + char device_path[256]; + #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - LOG_DEBUG("opening /dev/ppi%d...", parport_port); + snprintf(device_path, sizeof(device_path), "/dev/ppi%d", parport_port); +#else + snprintf(device_path, sizeof(device_path), "/dev/parport%d", parport_port); +#endif /* __FreeBSD__, __FreeBSD_kernel__ */ - snprintf(buffer, 256, "/dev/ppi%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#else /* not __FreeBSD__, __FreeBSD_kernel__ */ - LOG_DEBUG("opening /dev/parport%d...", parport_port); + LOG_DEBUG("Using parallel port %s", device_path); - snprintf(buffer, 256, "/dev/parport%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#endif /* __FreeBSD__, __FreeBSD_kernel__ */ + device_handle = open(device_path, O_WRONLY); if (device_handle < 0) { int err = errno; - LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); + LOG_ERROR("Failed to open parallel port %s (errno = %d)", device_path, + err); + LOG_ERROR("Check whether the device exists and if you have the required access rights"); return ERROR_JTAG_INIT_FAILED; } - LOG_DEBUG("...open"); - #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - int i = ioctl(device_handle, PPCLAIM); + int retval = ioctl(device_handle, PPCLAIM); - if (i < 0) { - LOG_ERROR("cannot claim device"); + if (retval < 0) { + LOG_ERROR("Failed to claim parallel port %s", device_path); return ERROR_JTAG_INIT_FAILED; } - i = PARPORT_MODE_COMPAT; - i = ioctl(device_handle, PPSETMODE, &i); - if (i < 0) { - LOG_ERROR(" cannot set compatible mode to device"); + int value = PARPORT_MODE_COMPAT; + retval = ioctl(device_handle, PPSETMODE, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } - i = IEEE1284_MODE_COMPAT; - i = ioctl(device_handle, PPNEGOT, &i); - if (i < 0) { - LOG_ERROR("cannot set compatible 1284 mode to device"); + value = IEEE1284_MODE_COMPAT; + retval = ioctl(device_handle, PPNEGOT, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ @@ -342,24 +335,24 @@ static int parport_init(void) #else /* not PARPORT_USE_PPDEV */ if (!parport_port) { parport_port = 0x378; - LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); + LOG_WARNING("No parallel port specified, using default 0x378 (LPT1)"); } + LOG_DEBUG("Using parallel port 0x%x", parport_port); + dataport = parport_port; statusport = parport_port + 1; - LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 - if (parport_get_giveio_access() != 0) { + if (!parport_get_giveio_access()) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ - LOG_ERROR("missing privileges for direct i/o"); + LOG_ERROR("Missing privileges for direct I/O"); return ERROR_JTAG_INIT_FAILED; } - LOG_DEBUG("...privileges granted"); - // Make sure parallel port is in right mode (clear tristate and interrupt. + // Make sure parallel port is in right mode (clear tristate and interrupt). #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else @@ -370,8 +363,10 @@ static int parport_init(void) if (parport_reset(0, 0) != ERROR_OK) return ERROR_FAIL; + if (parport_write(0, 0, 0) != ERROR_OK) return ERROR_FAIL; + if (parport_led(true) != ERROR_OK) return ERROR_FAIL; @@ -385,94 +380,117 @@ static int parport_quit(void) if (parport_led(false) != ERROR_OK) return ERROR_FAIL; - if (parport_exit) { - dataport_value = cable->port_exit; + if (parport_write_exit_state) { + dataport_value = parport_exit_state; parport_write_data(); } - free(parport_cable); - parport_cable = NULL; - return ERROR_OK; } COMMAND_HANDLER(parport_handle_port_command) { - if (CMD_ARGC == 1) { - // Only if the port wasn't overwritten by cmdline. - if (!parport_port) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); - } else { - LOG_ERROR("The parport port was already configured!"); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + // Only if the port wasn't overwritten by command-line. + if (parport_port > 0) { + command_print(CMD, "The parallel port is already configured"); + return ERROR_FAIL; } - command_print(CMD, "parport port = 0x%" PRIx16 "", parport_port); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); return ERROR_OK; } -COMMAND_HANDLER(parport_handle_cable_command) +COMMAND_HANDLER(parport_handle_layout_signal_command) { - if (!CMD_ARGC) - return ERROR_OK; - - // Only if the cable name wasn't overwritten by cmdline. - if (!parport_cable) { - // TODO: REVISIT first verify that it's listed in cables[]. - parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); - if (!parport_cable) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - strcpy(parport_cable, CMD_ARGV[0]); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *signal_name = CMD_ARGV[0]; + enum signal signal; + + if (!find_signal_by_name(signal_name, &signal)) { + command_print(CMD, "invalid signal name '%s'", signal_name); + return ERROR_COMMAND_ARGUMENT_INVALID; } - // TODO: REVISIT it's probably worth returning the current value. + uint8_t mask; + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], mask); + + parport_signal_masks[signal] = mask; + + return ERROR_OK; +} + +COMMAND_HANDLER(parport_handler_layout_init_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], parport_init_state); + + return ERROR_OK; +} + +COMMAND_HANDLER(parport_handler_layout_exit_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], parport_exit_state); return ERROR_OK; } +// This command is only for backward compatibility and will be removed in the +// future. +COMMAND_HANDLER(parport_handle_cable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + return command_run_linef(CMD_CTX, "parport_select_cable %s", CMD_ARGV[0]); +} + COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_write_exit_state); return ERROR_OK; } COMMAND_HANDLER(parport_handle_toggling_time_command) { - if (CMD_ARGC == 1) { - uint32_t ns; - int retval = parse_u32(CMD_ARGV[0], &ns); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - if (retval != ERROR_OK) - return retval; + uint32_t toggling_time; - if (!ns) { - LOG_ERROR("0 ns is not a valid parport toggling time"); - return ERROR_FAIL; - } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], toggling_time); - parport_toggling_time_ns = ns; - retval = adapter_get_speed(&wait_states); - if (retval != ERROR_OK) { - /* - * If adapter_get_speed fails then the clock_mode has - * not been configured, this happens if toggling_time is - * called before the adapter speed is set. - */ - LOG_INFO("no parport speed set - defaulting to zero wait states"); - wait_states = 0; - } + if (!toggling_time) { + command_print(CMD, "toggling time must not be 0 ns"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - command_print(CMD, "parport toggling time = %" PRIu32 " ns", - parport_toggling_time_ns); + parport_toggling_time_ns = toggling_time; + int retval = adapter_get_speed(&wait_states); + + if (retval != ERROR_OK) { + /* + * If adapter_get_speed fails then the clock_mode has not been + * configured, this happens if toggling_time is called before the + * adapter speed is set. + */ + LOG_INFO("No parallel port speed set, using zero wait states"); + wait_states = 0; + } return ERROR_OK; } @@ -482,35 +500,52 @@ static const struct command_registration parport_subcommand_handlers[] = { .name = "port", .handler = parport_handle_port_command, .mode = COMMAND_CONFIG, - .help = "Display the address of the I/O port (e.g. 0x378) " - "or the number of the '/dev/parport' device used. " - "If a parameter is provided, first change that port.", - .usage = "[port_number]", + .help = "Configure the address of the I/O port (e.g. 0x378) " + "or the number of the '/dev/parport' (Linux) or '/dev/ppi' (FreeBSD) device used", + .usage = "port_number", + }, + { + .name = "layout_signal", + .handler = parport_handle_layout_signal_command, + .mode = COMMAND_CONFIG, + .help = "Configure the signal layout of the parallel port", + .usage = "name mask", + }, + { + .name = "layout_init", + .handler = parport_handler_layout_init_command, + .mode = COMMAND_CONFIG, + .help = "Configure the output pin states during driver initialization", + .usage = "mask", + }, + { + .name = "layout_exit", + .handler = parport_handler_layout_exit_command, + .mode = COMMAND_CONFIG, + .help = "Configure the output pin states after driver shutdown", + .usage = "mask", }, { .name = "cable", .handler = parport_handle_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " - "used to connect to the target.", - // TODO: REVISIT there's no way to list layouts we know. - .usage = "[layout]", + "used to connect to the target", + .usage = "cable", }, { .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, - .help = "Configure the parallel driver to write " - "a known value to the parallel interface on exit.", + .help = "Configure the driver to write a value to the parallel port on shutdown", .usage = "('on'|'off')", }, { .name = "toggling_time", .handler = parport_handle_toggling_time_command, .mode = COMMAND_CONFIG, - .help = "Displays or assigns how many nanoseconds it " - "takes for the hardware to toggle TCK.", - .usage = "[nanoseconds]", + .help = "Configure how many nanoseconds it takes for the hardware to toggle TCK", + .usage = "time", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 2d8ebf0410..28a237aa57 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -359,6 +359,27 @@ proc parport_cable args { eval parport cable $args } +lappend _telnet_autocomplete_skip parport_select_cable +proc parport_select_cable {cable} { + echo "DEPRECATED! Do not use 'parport cable' but use a cable configuration file in interface/parport" + + switch $cable { + "wiggler" { source [find interface/parport/wiggler.cfg] } + "wiggler2" { source [find interface/parport/wiggler2.cfg] } + "wiggler_ntrst_inverted" { source [find interface/parport/wiggler-ntrst-inverted.cfg] } + "old_amt_wiggler" { source [find interface/parport/amt-wiggler-old.cfg ] } + "arm-jtag" { source [find interface/parport/arm-jtag.cfg] } + "chameleon" { source [find interface/parport/chameleon.cfg] } + "dlc5" { source [find interface/parport/dlc5.cfg] } + "triton" { source [find interface/parport/triton.cfg] } + "lattice" { source [find interface/parport/lattice.cfg] } + "flashlink" { source [find interface/parport/flashlink.cfg] } + "altium" { source [find interface/parport/altium.cfg] } + "aspo" { source [find interface/parport/aspo.cfg] } + default { error "invalid parallel port cable '$cable'" } + } +} + lappend _telnet_autocomplete_skip parport_write_on_exit proc parport_write_on_exit args { echo "DEPRECATED! use 'parport write_on_exit' not 'parport_write_on_exit'" diff --git a/tcl/interface/parport/altium.cfg b/tcl/interface/parport/altium.cfg new file mode 100644 index 0000000000..c33c247c8e --- /dev/null +++ b/tcl/interface/parport/altium.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: +# +# HARD TCK - Target TCK +# HARD TMS - Target TMS +# HARD TDI - Target TDI +# HARD TDO - Target TDO +# SOFT TCK - Target TRST +# SOFT TDI - Target SRST + +adapter driver parport + +parport layout_signal tdo 0x10 +parport layout_signal trst 0x20 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 +parport layout_signal srst 0x80 +parport layout_signal led 0x08 + +parport layout_init 0x10 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/amt-wiggler-old.cfg b/tcl/interface/parport/amt-wiggler-old.cfg new file mode 100644 index 0000000000..df165e23dd --- /dev/null +++ b/tcl/interface/parport/amt-wiggler-old.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x01 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x11 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/arm-jtag.cfg b/tcl/interface/parport/arm-jtag.cfg new file mode 100644 index 0000000000..f14f4922a2 --- /dev/null +++ b/tcl/interface/parport/arm-jtag.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x01 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/aspo.cfg b/tcl/interface/parport/aspo.cfg new file mode 100644 index 0000000000..29a9df7117 --- /dev/null +++ b/tcl/interface/parport/aspo.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x10 +parport layout_signal trst 0x01 +parport layout_signal tms 0x04 +parport layout_signal tck 0x08 +parport layout_signal tdi 0x02 +parport layout_signal srst 0x10 +parport layout_signal output-invert 0x17 + +parport layout_init 0x17 +parport layout_exit 0x17 diff --git a/tcl/interface/parport/chameleon.cfg b/tcl/interface/parport/chameleon.cfg new file mode 100644 index 0000000000..3e19cdac42 --- /dev/null +++ b/tcl/interface/parport/chameleon.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal tms 0x04 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x02 +parport layout_signal input-invert 0x80 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/dlc5.cfg b/tcl/interface/parport/dlc5.cfg index 24acea7a95..ae8caf51f6 100644 --- a/tcl/interface/parport/dlc5.cfg +++ b/tcl/interface/parport/dlc5.cfg @@ -1,17 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# # Xilinx Parallel Cable III 'DLC 5' (and various clones) -# -# http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} adapter driver parport -parport port $_PARPORTADDR -parport cable dlc5 + +parport layout_signal tdo 0x10 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 + +parport layout_init 0x10 +parport layout_exit 0x10 diff --git a/tcl/interface/parport/flashlink.cfg b/tcl/interface/parport/flashlink.cfg new file mode 100644 index 0000000000..634a6fc928 --- /dev/null +++ b/tcl/interface/parport/flashlink.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x20 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x04 +parport layout_signal srst 0x20 +parport layout_signal output-invert 0x30 +parport layout_signal input-invert 0x20 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/lattice.cfg b/tcl/interface/parport/lattice.cfg new file mode 100644 index 0000000000..0b8dfe4a19 --- /dev/null +++ b/tcl/interface/parport/lattice.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x40 +parport layout_signal trst 0x10 +parport layout_signal tms 0x04 +parport layout_signal tck 0x02 +parport layout_signal tdi 0x01 +parport layout_signal srst 0x08 + +parport layout_init 0x18 +parport layout_exit 0x18 diff --git a/tcl/interface/parport/triton.cfg b/tcl/interface/parport/triton.cfg new file mode 100644 index 0000000000..092b55a4f1 --- /dev/null +++ b/tcl/interface/parport/triton.cfg @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x08 +parport layout_signal tms 0x04 +parport layout_signal tck 0x01 +parport layout_signal tdi 0x02 +parport layout_signal input-invert 0x80 + +parport layout_init 0x0 +parport layout_exit 0x0 diff --git a/tcl/interface/parport/wiggler-ntrst-inverted.cfg b/tcl/interface/parport/wiggler-ntrst-inverted.cfg new file mode 100644 index 0000000000..639516ae58 --- /dev/null +++ b/tcl/interface/parport/wiggler-ntrst-inverted.cfg @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x11 +parport layout_signal input-invert 0x80 + +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/wiggler.cfg b/tcl/interface/parport/wiggler.cfg index b9fceeb852..4e53f57f9b 100644 --- a/tcl/interface/parport/wiggler.cfg +++ b/tcl/interface/parport/wiggler.cfg @@ -1,21 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Parallel port wiggler (many clones available) on port 0x378 -# -# Addresses: 0x378/LPT1 or 0x278/LPT2 ... -# +adapter driver parport -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - if {$tcl_platform(platform) eq "windows"} { - set _PARPORTADDR 0x378 - } { - set _PARPORTADDR 0 - } -} +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 -adapter driver parport -parport port $_PARPORTADDR -parport cable wiggler +parport layout_init 0x80 +parport layout_exit 0x80 diff --git a/tcl/interface/parport/wiggler2.cfg b/tcl/interface/parport/wiggler2.cfg new file mode 100644 index 0000000000..d4a0c41c0b --- /dev/null +++ b/tcl/interface/parport/wiggler2.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +parport layout_signal tdo 0x80 +parport layout_signal trst 0x10 +parport layout_signal tms 0x02 +parport layout_signal tck 0x04 +parport layout_signal tdi 0x08 +parport layout_signal srst 0x01 +parport layout_signal output-invert 0x01 +parport layout_signal input-invert 0x80 +parport layout_signal led 0x20 + +parport layout_init 0x80 +parport layout_exit 0x0 -- |
From: <ge...@op...> - 2025-06-08 09:29:06
|
This is an automated email from Gerrit. "R. Diez <rdi...@rd...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8942 -- gerrit commit b2184622abab4a5af5490ee0290202b90b61dd57 Author: R. Diez <rdi...@rd...> Date: Sun Jun 8 11:22:39 2025 +0200 configure.ac: remove usage of obsolete Automake macro AM_PROG_CC_C_O Macro AM_PROG_CC_C_O has been obsolete since Automake 1.14, released in June 2013 (12 years ago). It used to check whether the C compiler supports the -c and -o options, but that is now included in AC_PROG_CC. Increase the minimum required Automake version to 1.14 accordingly. Also remove the "not a GNU package" comment, which does not really make sense. Change-Id: I987ba8686721c7f36fba81e100f1c3ddf77f636d Signed-off-by: R. Diez <rdi...@rd...> diff --git a/Makefile.am b/Makefile.am index b2b6cef006..845543721d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# not a GNU package. You can remove this line, if -# have all needed files, that a GNU package needs -AUTOMAKE_OPTIONS = gnu 1.6 +AUTOMAKE_OPTIONS = gnu 1.14 .DELETE_ON_ERROR: diff --git a/configure.ac b/configure.ac index 3e1d9a2baa..27d6309a49 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,6 @@ AC_LANG([C]) AC_PROG_CC # autoconf 2.70 obsoletes AC_PROG_CC_C99 and includes it in AC_PROG_CC m4_version_prereq([2.70],[],[AC_PROG_CC_C99]) -AM_PROG_CC_C_O AC_PROG_RANLIB # If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates a misleading error message, -- |
From: <ge...@op...> - 2025-06-08 07:35:41
|
This is an automated email from Gerrit. "Brian Kuschak <bku...@gm...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8941 -- gerrit commit b8b60f4f55aaaf182c3ed21ffe996bb558f05adf Author: Brian Kuschak <bku...@gm...> Date: Sun Jun 8 15:25:09 2025 +0800 jtag/drivers: add new driver remote_swd Create a new driver 'remote_swd' that supports an SWD interface to a remote programmer over a simple TCP/IP protocol. It has a lightweight remote-side implementation. Supports SWD only, not JTAG. When used for flash programming an MCU, the performance is much faster than using the remote_bitbang driver. (Flashing a 64 KB image to an STM32 completes in about 7 seconds, as compared to 20 minutes for remote_bitbang). An implementation of the firmware for an SWD programmer that uses this remote_swd protocol can be found at the link below. https://github.com/bkuschak/openocd_remote_swd_esp32 Change-Id: If0580d1c831a8dd8ef2ab6d8afa6d6852f30ebe5 Signed-off-by: Brian Kuschak <bku...@gm...> diff --git a/configure.ac b/configure.ac index 3e1d9a2baa..4d5c48ac3a 100644 --- a/configure.ac +++ b/configure.ac @@ -172,6 +172,9 @@ m4_define([SYSFSGPIO_ADAPTER], m4_define([REMOTE_BITBANG_ADAPTER], [[[remote_bitbang], [Remote Bitbang driver], [REMOTE_BITBANG]]]) +m4_define([REMOTE_SWD_ADAPTER], + [[[remote_swd], [Remote SWD programmer over TCP/IP], [REMOTE_SWD]]]) + m4_define([LIBJAYLINK_ADAPTERS], [[[jlink], [SEGGER J-Link Programmer], [JLINK]]]) @@ -322,6 +325,7 @@ AC_ARG_ADAPTERS([ LIBGPIOD_ADAPTERS, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, + REMOTE_SWD_ADAPTER, LINUXSPIDEV_ADAPTER, SERIAL_PORT_ADAPTERS, DUMMY_ADAPTER, @@ -698,6 +702,7 @@ PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_li PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpiod]) PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs]) PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([REMOTE_SWD_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes"], [Linux build]) PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"], @@ -867,6 +872,7 @@ m4_foreach([adapter], [USB1_ADAPTERS, LIBGPIOD_ADAPTERS, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, + REMOTE_SWD_ADAPTER, LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, LINUXSPIDEV_ADAPTER, VDEBUG_ADAPTER, diff --git a/doc/openocd.texi b/doc/openocd.texi index bd6b3704a8..cb7276ee17 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -627,6 +627,9 @@ This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. @item @b{esp_usb_jtag} @* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3 and ESP32-S3 chips using OpenOCD. +@item @b{remote_swd} +@* An SWD driver for use with remote programmers over TCP/IP. + @end itemize @node About Jim Tcl @@ -2881,6 +2884,34 @@ remote_bitbang host mysocket @end example @end deffn +@deffn {Interface Driver} {remote_swd} +Controls a remote SWD programmer over TCP/IP using a simple protocol. For flash +programming, this is much faster than using the remote_bitbang driver. It has +a lightweight remote-side implementation. Supports SWD only, not JTAG. + +An implementation of the firmware for an ESP32-based SWD programmer that uses +this remote_swd protocol can be found at: +https://github.com/bkuschak/openocd_remote_swd_esp32 + +@deffn {Config Command} {remote_swd host} hostname +Specifies the hostname or IP address of the remote SWD programmer to connect to +using TCP. +@end deffn + +@deffn {Config Command} {remote_swd port} number +Specifies the TCP port number of the remote SWD programmer. +@end deffn + +For example, to connect remotely via TCP to the host foobar you might have +something like: + +@example +adapter driver remote_swd +remote_swd host foobar +remote_swd port 5253 +@end example +@end deffn + @deffn {Interface Driver} {usb_blaster} USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index b0dd8e3ad1..a8921de9df 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -210,6 +210,9 @@ endif if AM335XGPIO DRIVERFILES += %D%/am335xgpio.c endif +if REMOTE_SWD +DRIVERFILES += %D%/remote_swd.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/remote_swd.c b/src/jtag/drivers/remote_swd.c new file mode 100644 index 0000000000..e0182cc22f --- /dev/null +++ b/src/jtag/drivers/remote_swd.c @@ -0,0 +1,509 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2025 by Brian Kuschak <bku...@gm...> * + * Adapted from remote_bitbang.c * + * * + * Controls a remote SWD programmer over TCP/IP. Much faster than using * + * the remote_bitbang driver. Lightweight remote-side implementation. * + * Supports SWD only. JTAG not supported. * + * * + * Tested using a XIAO ESP32C6 as the programmer and STM32 Blue Pill as * + * the target. Flash programming performance: 9.5 KB/sec. * + * * + * openocd \ * + * --search tcl \ * + * -c "debug_level 2" \ * + * -c "reset_config none" \ * + * -c "adapter driver remote_swd" \ * + * -c "remote_swd host 192.168.100.40" \ * + * -c "remote_swd port 5253" \ * + * -f tcl/target/stm32f1x.cfg \ * + * -c "program firmware.elf verify reset exit" * + * * + * Refer to the implementation of the remote-side firmware for ESP32 at * + * https://github.com/bkuschak/openocd_remote_swd_esp32 * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef _WIN32 +#include <sys/un.h> +#include <netdb.h> +#include <netinet/tcp.h> +#endif +#include <arpa/inet.h> +#include "bitbang.h" +#include "helper/system.h" +#include "helper/replacements.h" +#include <jtag/interface.h> + +// Define our version of the protocol used. Remote side must match. +#define PROTOCOL_VERSION 0x01 + +// Arbitrary limit on host name length. +#define REMOTE_SWD_HOST_MAX 255 + +// First 4 bits of the flags hold the operation code. +#define FLAGS_OP_PROTOCOL 0x1 // Get remote protocol version. +#define FLAGS_OP_VERSION 0x2 // Get remote HW/SW version. +#define FLAGS_OP_SERIAL_NUM 0x3 // Get remote serial number. +#define FLAGS_OP_SPEED 0x4 // Set speed in 'data' field. +#define FLAGS_OP_RESET 0x5 // Set NRST state in 'data' field. +#define FLAGS_OP_SWITCH_SEQ 0x6 // Send sequence in 'data' field. +#define FLAGS_OP_READ_REG 0x7 // SWD read register. +#define FLAGS_OP_WRITE_REG 0x8 // SWD write register. +#define FLAGS_OP(flags) ((flags) & 0xF) + +// Remaining bits are reserved for flags. +#define FLAGS_EXPECT_ACK BIT(4) +#define FLAGS_EXPECT_DATA BIT(5) +#define FLAGS_SRST_OPEN_DRAIN BIT(4) // Used for OP_RESET only. + +// The 3 ACK bits returned by the target. +#define ACK_OK BIT(0) +#define ACK_WAIT BIT(1) +#define ACK_FAULT BIT(2) + +// The maximum number of queued commands, before we write them to the target. +#define MAX_QUEUE_LEN 128 + +// Very simple TCP stream protocol. +// We send commands to the remote side, using the struct below. +// The remote side returns the same struct back to us, with the ack field set, +// and the data field set if the command was a read. The cmd, ack, and data +// fields are what is actually transmitted on the wire, SWDIO. +struct queued_command { + uint8_t flags; // Opcode and flags. + uint8_t ap_delay_clks; // Additional clock cycles sent after the data. + uint8_t cmd; // SWD command. + uint8_t ack; // SWD ACK (3 bits) returned. + uint32_t data; // SWD data, sent or returned. +}; + +enum flush_bool { + NO_FLUSH, + FLUSH_SEND_BUF +}; + +static char *remote_swd_host; +static char *remote_swd_port; +static int sockfd; + +// The queued commands and a write index. +static struct queued_command queued_commands[MAX_QUEUE_LEN]; +static unsigned int queued_commands_idx; + +// We need a place to store the return data pointers. These are the caller's +// pointers for storing response data, and the ACK responses. +static uint32_t *response_data[MAX_QUEUE_LEN]; +static uint8_t response_acks[MAX_QUEUE_LEN]; + +static int remote_swd_run_queue(void); + +static int remote_swd_queue(struct queued_command *cmd, uint32_t *response, + enum flush_bool flush) +{ + // Use network byte order in the packets. + queued_commands[queued_commands_idx] = *cmd; + queued_commands[queued_commands_idx].data = htonl(cmd->data); + + response_data[queued_commands_idx] = response; + + if (!response) + LOG_DEBUG_IO("No response pointer provided."); + queued_commands_idx++; + if (flush == FLUSH_SEND_BUF || queued_commands_idx >= + ARRAY_SIZE(queued_commands)) + return remote_swd_run_queue(); + return ERROR_OK; +} + +static int remote_swd_quit(void) +{ + LOG_DEBUG("remote_swd interface quit"); + + if (close_socket(sockfd) != 0) { + log_socket_error("close_socket"); + return ERROR_FAIL; + } + + free(remote_swd_host); + free(remote_swd_port); + return ERROR_OK; +} + +static int remote_swd_reset(int trst, int srst) +{ + /* SRST only. SWD doesn't have TRST. */ + bool srst_open_drain = true; + enum reset_types cfg = jtag_get_reset_config(); + if (cfg & RESET_SRST_PUSH_PULL) + srst_open_drain = false; + + LOG_INFO("RESET: srst=%d, open_drain=%d", srst, srst_open_drain); + + struct queued_command cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.flags = FLAGS_OP_RESET; + cmd.flags |= srst_open_drain ? FLAGS_SRST_OPEN_DRAIN : 0; + cmd.data = srst ? 1 : 0; + + /* Always flush the send buffer on reset */ + return remote_swd_queue(&cmd, NULL, NO_FLUSH); +} + +static int remote_swd_speed(int hz) +{ + LOG_DEBUG("SPEED: %d Hz", hz); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_SPEED; + command.data = hz; + return remote_swd_queue(&command, NULL, NO_FLUSH); +} + +static void remote_swd_write_reg(unsigned char cmd, unsigned int value, + unsigned int ap_delay_clk) +{ + LOG_DEBUG("WRITE_REG: cmd=0x%02x, value=0x%08x, ap_delay_clk=%d", + cmd, value, ap_delay_clk); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_WRITE_REG; + command.flags |= FLAGS_EXPECT_ACK; + command.cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + command.data = value; + command.ap_delay_clks = ap_delay_clk; + + if (remote_swd_queue(&command, NULL, NO_FLUSH) == ERROR_FAIL) + LOG_ERROR("write_reg failed"); +} + +static void remote_swd_read_reg(unsigned char cmd, unsigned int *value, + unsigned int ap_delay_clk) +{ + LOG_DEBUG("READ_REG: cmd=0x%02x, ap_delay_clk=%d", cmd, + ap_delay_clk); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_READ_REG; + command.flags |= FLAGS_EXPECT_ACK; + command.flags |= FLAGS_EXPECT_DATA; + command.cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + command.ap_delay_clks = ap_delay_clk; + + if (remote_swd_queue(&command, value, NO_FLUSH) == ERROR_FAIL) + LOG_ERROR("read_reg failed"); +} + +static int remote_swd_switch_seq(enum swd_special_seq seq) +{ + LOG_DEBUG("SWITCH_SEQ: %d", seq); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_SWITCH_SEQ; + command.data = seq; + + if (remote_swd_queue(&command, NULL, NO_FLUSH) == ERROR_FAIL) + return ERROR_FAIL; + return 0; +} + +static int remote_swd_protocol(unsigned int *value) +{ + LOG_DEBUG("PROTOCOL"); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_PROTOCOL; + command.flags |= FLAGS_EXPECT_DATA; + + if (remote_swd_queue(&command, value, FLUSH_SEND_BUF) == ERROR_FAIL) + return ERROR_FAIL; + return 0; +} + +static int remote_swd_version(unsigned int *value) +{ + LOG_DEBUG("VERSION"); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_VERSION; + command.flags |= FLAGS_EXPECT_DATA; + + if (remote_swd_queue(&command, value, FLUSH_SEND_BUF) == ERROR_FAIL) + return ERROR_FAIL; + return 0; +} + +static int remote_swd_serial_number(unsigned int *value) +{ + LOG_DEBUG("SERIAL_NUM"); + + struct queued_command command; + memset(&command, 0, sizeof(command)); + command.flags = FLAGS_OP_SERIAL_NUM; + command.flags |= FLAGS_EXPECT_DATA; + + if (remote_swd_queue(&command, value, FLUSH_SEND_BUF) == ERROR_FAIL) + return ERROR_FAIL; + return 0; +} + +static int remote_swd_init_tcp(void) +{ + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + struct addrinfo *result, *rp; + int fd = 0; + + LOG_INFO("Connecting to %s:%s", + remote_swd_host ? remote_swd_host : "localhost", + remote_swd_port); + + /* Obtain address(es) matching host/port */ + int s = getaddrinfo(remote_swd_host, remote_swd_port, &hints, &result); + if (s != 0) { + LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s)); + return ERROR_FAIL; + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully connect(2). + If socket(2) (or connect(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp ; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) + break; /* Success */ + + close(fd); + } + + /* Set NODELAY to minimize latency. */ + int one = 1; + /* On Windows optval has to be a const char *. */ + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); + + freeaddrinfo(result); /* No longer needed */ + + if (!rp) { /* No address succeeded */ + log_socket_error("Failed to connect"); + return ERROR_FAIL; + } + + return fd; +} + +static int remote_swd_swd_init(void) +{ + LOG_DEBUG("remote_swd_swd_init"); + return ERROR_OK; +} + +static int remote_swd_init(void) +{ + LOG_INFO("Initializing remote_swd driver"); + + memset(queued_commands, 0, sizeof(queued_commands)); + memset(response_data, 0, sizeof(response_data)); + memset(response_acks, 0, sizeof(response_acks)); + queued_commands_idx = 0; + + int ret = remote_swd_init_tcp(); + if (ret < 0) { + log_socket_error("remote_swd socket init"); + LOG_ERROR("Failed initializing socket. Error: %d", errno); + return ret; + } + sockfd = ret; + + LOG_INFO("remote_swd driver initialized"); + + // Get device version and serial number. + unsigned int protocol = 0; + unsigned int version = 0; + unsigned int serial_num = 0; + ret = remote_swd_protocol(&protocol); + if (ret != ERROR_OK) { + LOG_ERROR("Failed getting remote protocol version!"); + return ERROR_FAIL; + } + ret = remote_swd_version(&version); + if (ret != ERROR_OK) { + LOG_ERROR("Failed getting remote version!"); + return ERROR_FAIL; + } + ret = remote_swd_serial_number(&serial_num); + if (ret != ERROR_OK) { + LOG_ERROR("Failed getting remote serial number!"); + return ERROR_FAIL; + } + + LOG_INFO("Remote protocol version: %u", protocol); + LOG_INFO("Remote HW/SW version: 0x%02hX / 0x%02hX", + version & 0xFF, (version >> 8) & 0xFF); + LOG_INFO("Remote serial number: %08X", serial_num); + + if (protocol != PROTOCOL_VERSION) { + LOG_ERROR("Remote protocol version (%u) does not match our own (%u)!", + protocol, PROTOCOL_VERSION); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(remote_swd_handle_remote_swd_port_command) +{ + if (CMD_ARGC == 1) { + uint16_t port; + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); + free(remote_swd_port); + remote_swd_port = port == 0 ? NULL : strdup(CMD_ARGV[0]); + LOG_INFO("remote_swd got port %s", remote_swd_port); + return ERROR_OK; + } + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HANDLER(remote_swd_handle_remote_swd_host_command) +{ + if (CMD_ARGC == 1) { + free(remote_swd_host); + remote_swd_host = strdup(CMD_ARGV[0]); + LOG_INFO("remote_swd got host %s", remote_swd_host); + return ERROR_OK; + } + return ERROR_COMMAND_SYNTAX_ERROR; +} + +static const struct command_registration remote_swd_subcommand_handlers[] = { + { + .name = "port", + .handler = remote_swd_handle_remote_swd_port_command, + .mode = COMMAND_CONFIG, + .help = "Set the TCP port to use to connect to the remote SWD.\n", + .usage = "port_number", + }, + { + .name = "host", + .handler = remote_swd_handle_remote_swd_host_command, + .mode = COMMAND_CONFIG, + .help = "Set the host to use to connect to the remote SWD.\n", + .usage = "host_name", + }, + // TODO add subcommands to set the pin numbers for SWDIO, SWCLK, SRST. + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration remote_swd_command_handlers[] = { + { + .name = "remote_swd", + .mode = COMMAND_ANY, + .help = "perform remote_swd management", + .chain = remote_swd_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + + +static int remote_swd_run_queue(void) +{ + LOG_DEBUG("Executing %d queued transactions", queued_commands_idx); + if (queued_commands_idx <= 0) + return ERROR_OK; + + // Send entire queue at once. + int nbytes = queued_commands_idx * sizeof(*queued_commands); + LOG_DEBUG_IO("Sending %d bytes... (fd=%d)", nbytes, sockfd); + ssize_t n = write_socket(sockfd, queued_commands, nbytes); + LOG_DEBUG_IO("write_socket returned %zd", n); + if (n < 0) { + log_socket_error("remote_swd write_socket error"); + queued_commands_idx = 0; + return ERROR_FAIL; + } + if (n != nbytes) { + log_socket_error("remote_swd write_socket short write"); + queued_commands_idx = 0; + return ERROR_FAIL; + } + + // Wait for the entire response. + struct queued_command response[queued_commands_idx]; + nbytes = sizeof(response); + LOG_DEBUG_IO("Reading %d bytes...", nbytes); + n = read_socket(sockfd, response, nbytes); + LOG_DEBUG_IO("read_socket returned %zd", n); + if (n < 0) { + log_socket_error("remote_swd read_socket error"); + queued_commands_idx = 0; + return ERROR_FAIL; + } + if (n != nbytes) { + log_socket_error("remote_swd read_socket short read"); + queued_commands_idx = 0; + return ERROR_FAIL; + } + + // Iterate over the response data, storing the responses into the caller's + // pointers. + memset(response_acks, 0, sizeof(response_acks)); + for (unsigned int i = 0; i < queued_commands_idx; i++) { + struct queued_command *cmd = &queued_commands[i]; + struct queued_command *resp = &response[i]; + + if (response_data[i]) + *response_data[i] = 0; + + if (cmd->flags & FLAGS_EXPECT_ACK) { + LOG_DEBUG("Got response ack: %x", resp->data); + response_acks[i] = resp->ack; + } + if (cmd->flags & FLAGS_EXPECT_DATA) { + LOG_DEBUG("Got response data: %08x", resp->data); + if (response_data[i]) + *response_data[i] = ntohl(resp->data); + } + } + + LOG_DEBUG("SWD run_queue success"); + queued_commands_idx = 0; + return ERROR_OK; +} + +const struct swd_driver remote_swd_ops = { + .init = remote_swd_swd_init, + .switch_seq = remote_swd_switch_seq, + .read_reg = remote_swd_read_reg, + .write_reg = remote_swd_write_reg, + .run = remote_swd_run_queue, +}; + +struct adapter_driver remote_swd_adapter_driver = { + .name = "remote_swd", + .transport_ids = TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_SWD, + .commands = remote_swd_command_handlers, + .init = &remote_swd_init, + .quit = &remote_swd_quit, + .speed = &remote_swd_speed, + .reset = &remote_swd_reset, + .swd_ops = &remote_swd_ops, +}; diff --git a/src/jtag/drivers/remote_swd.lua b/src/jtag/drivers/remote_swd.lua new file mode 100644 index 0000000000..08225f5833 --- /dev/null +++ b/src/jtag/drivers/remote_swd.lua @@ -0,0 +1,99 @@ +-- Wireshark packet dissector for the remote_swd protocol. +-- Adapted from ChatGPT. +-- +-- Place this file into the Wireshark plugins directory. +-- macOS/Linux: ~/.config/wireshark/plugins/ +-- Windows: AppData\Roaming\Wireshark\plugins\ + +-- Define protocol +local remote_swd_proto = Proto("remote_swd", "OpenOCD remote_swd protocol") + +-- Enumerated values for bit fields +local field1_enum = { + [0] = "Unknown", + [1] = "Protocol Version", + [2] = "HW/SW Version", + [3] = "Serial Number", + [4] = "Speed", + [5] = "Reset", + [6] = "Switch Sequence", + [7] = "Read Register", + [8] = "Write Register", + [9] = "Unknown", + [10] = "Unknown", + [11] = "Unknown", + [12] = "Unknown", + [13] = "Unknown", + [14] = "Unknown", + [15] = "Unknown" +} + +local field5_enum = { + [0] = "ACK none", + [1] = "ACK OK", + [2] = "ACK WAIT", + [3] = "ACK unknown", + [4] = "ACK FAULT", + [5] = "ACK unknown", + [6] = "ACK unknown", + [7] = "ACK unknown" +} + +-- Define fields +local f_field1 = ProtoField.uint8("remote_swd.opcode", "Opcode", base.DEC, field1_enum, 0x0F) +local f_field2_ack = ProtoField.bool("remote_swd.flags.ack", "Expect ACK", 8, nil, 0x10) +local f_field2_data = ProtoField.bool("remote_swd.flags.data", "Expect Data", 8, nil, 0x20) +local f_field3 = ProtoField.uint8("remote_swd.ap_delay_clks", "AP delay clocks", base.DEC) +local f_field4 = ProtoField.uint8("remote_swd.cmd", "SWD command", base.HEX) +local f_field5 = ProtoField.uint8("remote_swd.ack", "SWD ack", base.HEX, field5_enum, 0x07) +local f_field6 = ProtoField.uint32("remote_swd.data", "SWD data", base.HEX) + +remote_swd_proto.fields = { f_field1, f_field2_ack, f_field2_data, f_field3, f_field4, f_field5, f_field6 } + +-- Struct size in bytes +local STRUCT_SIZE = 8 + +-- Dissector +function remote_swd_proto.dissector(buffer, pinfo, tree) + pinfo.cols.protocol = remote_swd_proto.name + + local total_len = buffer:len() + + -- TCP reassembly: if not enough data for one struct, ask for more + if total_len < STRUCT_SIZE then + pinfo.desegment_len = STRUCT_SIZE - total_len + return + end + + -- Reassemble if data is not a multiple of struct size + if (total_len % STRUCT_SIZE) ~= 0 then + pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT + return + end + + -- Dissect + local subtree = tree:add(remote_swd_proto, buffer(), "Operations") + + local offset = 0 + local struct_num = 0 + + while offset + STRUCT_SIZE <= total_len do + local struct_buf = buffer(offset, STRUCT_SIZE) + local struct_tree = subtree:add(remote_swd_proto, struct_buf, "Operation " .. struct_num) + + struct_tree:add(f_field1, struct_buf(0, 1)) + struct_tree:add(f_field2_ack, struct_buf(0, 1)) + struct_tree:add(f_field2_data, struct_buf(0, 1)) + struct_tree:add(f_field3, struct_buf(1, 1)) + struct_tree:add(f_field4, struct_buf(2, 1)) + struct_tree:add(f_field5, struct_buf(3, 1)) + struct_tree:add_le(f_field6, struct_buf(4, 4)) + + offset = offset + STRUCT_SIZE + struct_num = struct_num + 1 + end +end + +-- Register the protocol to a TCP port (e.g., 5253) +local tcp_port = DissectorTable.get("tcp.port") +tcp_port:add(5253, remote_swd_proto) diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 475dbed36e..c5518454e1 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -400,6 +400,7 @@ extern struct adapter_driver osbdm_adapter_driver; extern struct adapter_driver parport_adapter_driver; extern struct adapter_driver presto_adapter_driver; extern struct adapter_driver remote_bitbang_adapter_driver; +extern struct adapter_driver remote_swd_adapter_driver; extern struct adapter_driver rlink_adapter_driver; extern struct adapter_driver rshim_dap_adapter_driver; extern struct adapter_driver stlink_dap_adapter_driver; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index e49bd9e0f3..07b2d3393e 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -108,6 +108,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_REMOTE_BITBANG == 1 &remote_bitbang_adapter_driver, #endif +#if BUILD_REMOTE_SWD == 1 + &remote_swd_adapter_driver, +#endif #if BUILD_HLADAPTER == 1 &hl_adapter_driver, #endif diff --git a/tcl/interface/remote_swd.cfg b/tcl/interface/remote_swd.cfg new file mode 100644 index 0000000000..bcf11124bd --- /dev/null +++ b/tcl/interface/remote_swd.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +# +# configuration file for remote_swd adapter +# + +adapter driver remote_swd +remote_swd host 192.168.2.144 +remote_swd port 5253 + +reset_config none -- |
From: <ge...@op...> - 2025-06-03 11:52:14
|
This is an automated email from Gerrit. "Antonio Borneo <bor...@gm...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8940 -- gerrit commit d8b215654819c35a5f768f0c7c3c60865ce4871f Author: Antonio Borneo <bor...@gm...> Date: Tue Jun 3 11:52:59 2025 +0200 HACKING: describe keeping the 'Change-Id' on new patch versions We often get on Gerrit a new version of an old patch with a new 'Change-Id' value. This breaks the history of the review, adding more work to the review process. Describe in HACKING why the hook 'commit-msg' is required and how to handle the 'Change-Id' on new patch versions. Change-Id: I5c060b19f966add7422704912b38e1ab2f788e5f Signed-off-by: Antonio Borneo <bor...@gm...> diff --git a/HACKING b/HACKING index 8988b1617d..785179efe9 100644 --- a/HACKING +++ b/HACKING @@ -169,7 +169,9 @@ git remote add review https://USERNAME:PAS...@re.../p/openocd.git Gerrit server, even if you plan to use several local branches for different topics. It is possible because @c for/master is not a traditional Git branch. - -# You will need to install this hook, we will look into a better solution: + -# You will need to install this hook to automatically add the + field "Change-Id:" in the commit message, as required by Gerrit. + We will look into a better solution: @code wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks @@ -246,6 +248,12 @@ doc: fix typos @code git pull --rebase origin master @endcode + +-# When you create a new version of an old patch, check that the new patch + keeps the same 'Change-Id:' field of the old patch. + This allows the Gerrit server to recognize the patch as a new version of + the older one and keeps track of the history and the review process. + -# Send the patches to the Gerrit server for review: @code git push review -- |
From: <ge...@op...> - 2025-06-03 08:44:23
|
This is an automated email from Gerrit. "Antonio Borneo <bor...@gm...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8939 -- gerrit commit 935ab3e6d4b7d264960e26052bd5caa1c290a58e Author: Antonio Borneo <bor...@gm...> Date: Tue Jun 3 10:34:29 2025 +0200 configure: hide build issue of amt_jtagaccel driver by disabling it With commit d8a2f6dbcf5f ("configure.ac: show the Amontec JTAG-Accelerator driver in the config summary") the driver amt_jtagaccel is now build by default on Linux. This highlights the dependency of some include files, dependency that is not properly managed and that can cause build failure. The driver is queued to be dropped soon, so there is no real interest to fix the dependencies. Change the default so the driver is not built if the user does not require it at configure time. Change-Id: Ifb74e2c802abda290efbf59ca4ce02048c94e6f8 Signed-off-by: Antonio Borneo <bor...@gm...> diff --git a/configure.ac b/configure.ac index c44d902d2c..3e1d9a2baa 100644 --- a/configure.ac +++ b/configure.ac @@ -329,11 +329,14 @@ AC_ARG_ADAPTERS([ JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, - AMTJTAGACCEL_ADAPTER, PCIE_ADAPTERS, LIBJAYLINK_ADAPTERS ],[auto]) +AC_ARG_ADAPTERS([ + AMTJTAGACCEL_ADAPTER + ],[no]) + AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) -- |
From: <ge...@op...> - 2025-06-02 16:44:16
|
This is an automated email from Gerrit. "Vitaly Cheptsov <vi...@pr...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8886 -- gerrit commit d0ae4b24ed2f85cdb6cacaafcbebde4eca8523c4 Author: Vitaly Cheptsov <vi...@pr...> Date: Sun May 18 08:49:30 2025 +0300 jlink: add nickname support Using nicknames provides a human-readable alternative to serial numbers for convenience purposes. Allow matching adapter serial with device nickname. Change-Id: I03b8d28a6c89412a825d42f4f66b3b528f217d9c Signed-off-by: Vitaly Cheptsov <vi...@pr...> diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 9caf37f6f0..e8e7c949fa 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -23,6 +23,7 @@ #include <stdint.h> #include <math.h> +#include <string.h> #include <jtag/interface.h> #include <jtag/swd.h> @@ -40,8 +41,6 @@ static struct jaylink_connection connlist[JAYLINK_MAX_CONNECTIONS]; static enum jaylink_jtag_version jtag_command_version; static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; -static uint32_t serial_number; -static bool use_serial_number; static bool use_usb_location; static enum jaylink_usb_address usb_address; static bool use_usb_address; @@ -561,8 +560,14 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) } use_usb_location = !!adapter_usb_get_location(); + const char *adapter_serial = adapter_get_required_serial(); - if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { + uint32_t serial_number; + ret = jaylink_parse_serial_number(adapter_serial, &serial_number); + if (ret != JAYLINK_OK) + serial_number = 0; + + if (!adapter_serial && !use_usb_address && !use_usb_location && num_devices > 1) { LOG_ERROR("Multiple devices found, specify the desired device"); LOG_INFO("Found devices:"); for (size_t i = 0; devs[i]; i++) { @@ -575,7 +580,12 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) jaylink_strerror(ret)); continue; } - LOG_INFO("Device %zu serial: %" PRIu32, i, serial); + char name[JAYLINK_NICKNAME_MAX_LENGTH]; + int name_ret = jaylink_device_get_nickname(devs[i], name); + if (name_ret == JAYLINK_OK) + LOG_INFO("Device %zu serial: %" PRIu32 ", nickname %s", i, serial, name); + else + LOG_INFO("Device %zu serial: %" PRIu32, i, serial); } jaylink_free_devices(devs, true); @@ -588,20 +598,31 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) for (size_t i = 0; devs[i]; i++) { struct jaylink_device *dev = devs[i]; - if (use_serial_number) { - uint32_t tmp; - ret = jaylink_device_get_serial_number(dev, &tmp); - - if (ret == JAYLINK_ERR_NOT_AVAILABLE) { - continue; - } else if (ret != JAYLINK_OK) { - LOG_WARNING("jaylink_device_get_serial_number() failed: %s", - jaylink_strerror(ret)); - continue; + if (adapter_serial) { + /* + * Treat adapter serial as a nickname first as it can also be numeric. + * If it fails to match (optional) device nickname try to compare + * adapter serial with the actual device serial number. + */ + char nickname[JAYLINK_NICKNAME_MAX_LENGTH]; + ret = jaylink_device_get_nickname(dev, nickname); + if (ret != JAYLINK_OK || strcmp(nickname, adapter_serial) != 0) { + if (!serial_number) + continue; + + uint32_t tmp; + ret = jaylink_device_get_serial_number(dev, &tmp); + if (ret == JAYLINK_ERR_NOT_AVAILABLE) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_serial_number() failed: %s", + jaylink_strerror(ret)); + continue; + } + + if (serial_number != tmp) + continue; } - - if (serial_number != tmp) - continue; } if (use_usb_address) { @@ -670,29 +691,12 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - const char *serial = adapter_get_required_serial(); - if (serial) { - ret = jaylink_parse_serial_number(serial, &serial_number); - if (ret == JAYLINK_ERR) { - LOG_ERROR("Invalid serial number: %s", serial); - jaylink_exit(jayctx); - return ERROR_JTAG_INIT_FAILED; - } - if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret)); - jaylink_exit(jayctx); - return ERROR_JTAG_INIT_FAILED; - } - use_serial_number = true; - use_usb_address = false; - } - bool found_device; ret = jlink_open_device(JAYLINK_HIF_USB, &found_device); if (ret != ERROR_OK) return ret; - if (!found_device && use_serial_number) { + if (!found_device && adapter_get_required_serial()) { ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); if (ret != ERROR_OK) return ret; -- |
From: Plamena M. <PMa...@hi...> - 2025-05-29 12:51:05
|
Hello, We have a Cortex-A32 target that requires this patch for AArch32 support - https://review.openocd.org/c/openocd/+/5854. Can we do something more to get the patch merged and released? Best regards, Plamena ________________________________ From: Antonio Borneo <bor...@gm...> Sent: Friday, 23 May 2025 1:16 pm To: OpenOCD <Ope...@li...> Subject: Preparing for OpenOCD v1.0.0-rc1 CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe. Never provide your password! VORSICHT: Diese E-Mail kommt von einem externen Absender. Bitte keine Links anklicken oder Anlagen öffnen falls Sie den Absender nicht kennen. Niemals Ihr Kennwort eingeben! Hello, we are going to tag OpenOCD v1.0.0-rc1 in around one month. It will follow a period of code freeze, during which only patches for bug fixes will be merged. The release v1.0.0 is expected before the end of the year. Why v1.0.0 ? Because OpenOCD is 20 years old, and at such an age it's mature enough for a cool major release. Because today we have already merged 996 commits since last release v0.12.0 (2023-01-14), and it's time to focus on tests and fixes. Because it's summer and old bugs get hotter, so time to fix them. Because, ... feel free to add your personal reason to this list! ;-) Said that, I invite you all to report any feature still pending in Gerrit that you absolutely want to have in v1.0.0. Regards, Antonio Hilscher Development & Test Center EOOD | Business Park Varna - B8, 402 | 9009 Varna | Bulgaria | www.hilscher.com<http://www.hilscher.com> Important Information: This e-mail message including its attachments contains confidential and legally protected information solely intended for the addressee. If you are not the intended addressee of this message, please contact the addresser immediately and delete this message including its attachments. The unauthorized dissemination, copying and change of this e-mail are strictly forbidden. The addresser shall not be liable for the content of such changed e-mails. ????????: ???? ?????????? ????????? ? ??????????? ??? ???? ??????? ???????? ?????????? ????????????? ?????????? ?? ???????? ????? ??????????. ??? ?????? ????? ?? ? ? ??????? ?? ?????????? ???? ????????? ?? ???????? ???? ????????? ? ??????????? ??? ???? ??????? ???? ???????????? ????????? ????????. ????????, ??????? ??? ????????? ? ????? ???? ?? ???????????? ??????????? ? ???? ????????? ??? ????????? ???????? ?? ?????? ? ?????? ?????????. |
From: <ge...@op...> - 2025-05-29 12:38:11
|
This is an automated email from Gerrit. "Jonathan Bell <jon...@ra...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8885 -- gerrit commit fafb1fb84460c245924ae36a389ce5f2bf5f32ae Author: Jonathan Bell <jon...@ra...> Date: Wed May 21 15:37:25 2025 +0100 tcl: fix broken Raspberry Pi website links raspberrypi.com is the home for technical information, raspberrypi.org is the Foundation's site (though there are intelligent redirects). Several pages have moved around, fix these. Also tweak a few comments for style and correctness. Signed-off-by: Jonathan Bell <jon...@ra...> Change-Id: I7f52bcc362fb213b50987e3a42866fe4a6fec883 diff --git a/tcl/board/rpi3.cfg b/tcl/board/rpi3.cfg index fd93a9d9d8..a08bfeb12e 100644 --- a/tcl/board/rpi3.cfg +++ b/tcl/board/rpi3.cfg @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 3 board with BCM2837 chip -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2837.cfg] transport select jtag diff --git a/tcl/board/rpi4b.cfg b/tcl/board/rpi4b.cfg index 5b046af7b5..7d937e8c05 100644 --- a/tcl/board/rpi4b.cfg +++ b/tcl/board/rpi4b.cfg @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 4 model B board with BCM2711 chip -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2711.cfg] transport select jtag diff --git a/tcl/target/bcm2711.cfg b/tcl/target/bcm2711.cfg index f8d2b3a65b..9704daf812 100644 --- a/tcl/target/bcm2711.cfg +++ b/tcl/target/bcm2711.cfg @@ -3,8 +3,8 @@ # The Broadcom BCM2711 used in Raspberry Pi 4 # No documentation was found on Broadcom website -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2835.cfg b/tcl/target/bcm2835.cfg index 32a03666c4..645588730d 100644 --- a/tcl/target/bcm2835.cfg +++ b/tcl/target/bcm2835.cfg @@ -3,8 +3,8 @@ # This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, # the Compute Module, and the Raspberry Pi Zero. -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2835 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2836.cfg b/tcl/target/bcm2836.cfg index 04921315ed..695426e7a8 100644 --- a/tcl/target/bcm2836.cfg +++ b/tcl/target/bcm2836.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# The Broadcom chip used in the Raspberry Pi 2 Model B +# The Broadcom chip used in the Raspberry Pi 2 Model B v1.1 -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2836 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2837.cfg b/tcl/target/bcm2837.cfg index 749de31037..d41892c431 100644 --- a/tcl/target/bcm2837.cfg +++ b/tcl/target/bcm2837.cfg @@ -3,9 +3,9 @@ # This is the Broadcom chip used in the Raspberry Pi 3, # and in later models of the Raspberry Pi 2. -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837b0 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index f64d4322b1..da88a3125b 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # RP2040 is a microcontroller with dual Cortex-M0+ core. -# https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2040 # The device requires multidrop SWD for debug. transport select swd diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index b7617acd4c..96bb9298fb 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # RP2350 is a microcontroller with dual Cortex-M33 cores or dual Hazard3 RISC-V cores. -# https://www.raspberrypi.com/documentation/microcontrollers/rp2350.html +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2350 transport select swd -- |
From: <ge...@op...> - 2025-05-29 12:38:05
|
This is an automated email from Gerrit. "Jonathan Bell <jon...@ra...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8884 -- gerrit commit 0cdf77fae801dec8f89164c41db1785e8da08bee Author: Jonathan Bell <jon...@ra...> Date: Wed May 21 15:26:20 2025 +0100 doc: bcm2835gpio: remove broken link and clarify usage Pi 5 GPIOs are exposed on RP1 which requires the use of libgpiod. Signed-off-by: Jonathan Bell <jon...@ra...> Change-Id: I8b2c44ec5edd71abaa0a763ba4d4f4603a211348 diff --git a/doc/openocd.texi b/doc/openocd.texi index ca357c7802..74012afab4 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3346,8 +3346,10 @@ The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @deffn {Interface Driver} {bcm2835gpio} -This SoC is present in Raspberry Pi which is a cheap single-board computer -exposing some GPIOs on its expansion header. +This GPIO interface is present in Raspberry Pi 0-4 which is a cheap +single-board computer exposing some GPIOs on its expansion header. + +@emph{Note:} for Raspberry Pi 5, use @b{linuxgpiod} not this driver. The driver accesses memory-mapped GPIO peripheral registers directly for maximum performance, but the only possible race condition is for @@ -3386,9 +3388,7 @@ and drive strength is reduced to 4 mA (2 mA on RPi 4). @deffn {Config Command} {bcm2835gpio peripheral_base} @var{base} Set the peripheral base register address to access GPIOs. Ignored if @file{/dev/gpiomem} is used. For the RPi1, use -0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full -list can be found in the -@uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}. +0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. @end deffn @end deffn -- |
From: <ge...@op...> - 2025-05-29 11:02:01
|
This is an automated email from Gerrit. "Ahmed Haoues <ahm...@st...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8882 -- gerrit commit c52ca8cba4a6ab2816d678ab1d03558343949f1c Author: HAOUES Ahmed <ahm...@st...> Date: Thu May 29 10:01:20 2025 +0100 flash/bluenrg-x: fix programming for devices with 512k flash flash ADDRESS register is encoded in 17 bits (was 16), so fix the cast to uint32_t Change-Id: I13384ee8967e65890577b12a42a0eb4f1e2a7467 Signed-off-by: HAOUES Ahmed <ahm...@st...> diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c index 1bc72d5921..3c1988f112 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -52,7 +52,7 @@ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t addres /* Clear the IRQ flags */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F; /* Load the flash address to write */ - *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2); + *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint32_t)((address + index - MFB_BOTTOM) >> 2); /* Prepare and load the data to flash */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1]; diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc index ff05634bb2..146a6bedeb 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc @@ -1,17 +1,19 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x05,0x93,0x43,0x68,0x14,0x9e,0x09,0x93,0x05,0x9b,0x05,0x00,0x07,0x91,0x06,0x92, -0x01,0x24,0xb1,0x46,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, -0x2b,0x68,0x00,0x2b,0x61,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x5e,0xd9,0x6b,0x68, -0x07,0x9a,0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x4a,0x46,0x00,0x21,0x03,0x93,0xd1,0x60, -0x00,0x2b,0x42,0xd0,0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x00,0x92, -0x48,0x22,0x4a,0x44,0x93,0x46,0x4c,0x22,0x27,0x4f,0x4a,0x44,0xbc,0x46,0x4e,0x46, -0x92,0x46,0x06,0x99,0x4b,0x46,0x61,0x44,0x08,0x00,0x00,0x99,0x18,0x36,0x6a,0x68, -0x08,0x95,0x8c,0x46,0x55,0x46,0xda,0x46,0xb3,0x46,0x10,0x33,0x04,0x92,0x11,0x68, -0x5e,0x46,0x00,0x91,0x51,0x68,0x97,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,0x3f,0x21, -0x19,0x60,0x81,0x03,0x09,0x0c,0x31,0x60,0x46,0x46,0x00,0x99,0x31,0x60,0x66,0x46, -0x01,0x99,0x31,0x60,0x56,0x46,0x02,0x99,0x37,0x60,0x29,0x60,0xcc,0x26,0x49,0x46, -0x0e,0x60,0x19,0x68,0x0c,0x42,0xfc,0xd0,0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30, -0x51,0x1a,0x8e,0x42,0xdb,0xd8,0x08,0x9d,0x6a,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46, -0x63,0x44,0x06,0x93,0x07,0x9a,0x6b,0x68,0x9a,0x42,0x01,0xd8,0x09,0x9b,0x6b,0x60, -0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,0x96,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68, -0x9b,0x1a,0x9f,0xd5,0x90,0xe7,0xc0,0x46,0x00,0x00,0xfc,0xef, +0x16,0x9e,0x05,0x00,0x01,0x24,0xb1,0x46,0x06,0x93,0x43,0x68,0x08,0x91,0x07,0x92, +0x09,0x93,0x06,0x9b,0x00,0x2b,0x6f,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, +0x2b,0x68,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x65,0xd9,0x6b,0x68, +0x08,0x9a,0xd3,0x1a,0x0b,0x93,0x0b,0x9b,0x0f,0x2b,0xea,0xdd,0x4a,0x46,0x00,0x21, +0x0b,0x9b,0xd1,0x60,0x04,0x93,0x00,0x2b,0x43,0xd0,0x31,0x4a,0x07,0x9b,0x94,0x46, +0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x63,0x44,0x94,0x46,0x48,0x22, +0x4a,0x44,0x93,0x46,0x05,0x93,0x4c,0x22,0x4b,0x46,0x4a,0x44,0x10,0x33,0x4e,0x46, +0x92,0x46,0x00,0x93,0x2b,0x00,0x18,0x36,0x6a,0x68,0x55,0x46,0xb2,0x46,0x5e,0x46, +0x9b,0x46,0x10,0x68,0x57,0x68,0x01,0x90,0x3f,0x20,0x00,0x9b,0x02,0x97,0x97,0x68, +0x03,0x97,0xd7,0x68,0x18,0x60,0x53,0x46,0x05,0x98,0x40,0x18,0x80,0x08,0x18,0x60, +0x43,0x46,0x01,0x98,0x18,0x60,0x63,0x46,0x02,0x98,0x18,0x60,0x03,0x98,0x4b,0x46, +0x30,0x60,0xcc,0x20,0x2f,0x60,0x18,0x60,0x00,0x9b,0x18,0x68,0x04,0x42,0xfc,0xd0, +0x58,0x46,0x10,0x32,0x42,0x60,0x04,0x98,0x10,0x31,0x00,0x93,0x88,0x42,0xd8,0xd8, +0x5d,0x46,0x07,0x9a,0x0b,0x9b,0x94,0x46,0x9c,0x44,0x63,0x46,0x08,0x9a,0x07,0x93, +0x6b,0x68,0x93,0x42,0x01,0xd3,0x09,0x9b,0x6b,0x60,0x06,0x9a,0x0b,0x9b,0xd3,0x1a, +0x06,0x93,0x06,0x9b,0x00,0x2b,0x8f,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68,0x9b,0x1a, +0x0b,0x93,0x0b,0x9b,0x00,0x2b,0x00,0xdb,0x95,0xe7,0x00,0x23,0x0b,0x93,0x92,0xe7, +0x00,0x00,0xfc,0xef, diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index cde4af5e3b..a953e9b283 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -315,10 +315,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* Put the 4th parameter at the location in the stack frame of target write() function. * See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.lst - * 34 ldr r6, [sp, #80] + * 34 ldr r6, [sp, #88] * ^^^ offset */ - init_mem_param(&mem_params[0], write_algorithm_stack->address + 80, 32, PARAM_OUT); + init_mem_param(&mem_params[0], write_algorithm_stack->address + 88, 32, PARAM_OUT); /* Stack for target write algorithm - target write() function has * __attribute__((naked)) so it does not setup the new stack frame. * Therefore the stack frame uses the area from SP upwards! -- |
From: <ge...@op...> - 2025-05-29 11:02:01
|
This is an automated email from Gerrit. "Ahmed Haoues <ahm...@st...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8881 -- gerrit commit a8bd384e1952b5d4a7cfedecfcd5c7049a4a9837 Author: HAOUES Ahmed <ahm...@st...> Date: Tue May 27 11:34:24 2025 +0100 flash/bluenrg-x: Support STM32WB09 AKA BlueNRG-LPF device The BlueNRG-LPF has a flash size up to 512 Kb Change-Id: I4c71b716330351004f4f2ab8bf8eac7d5bb694eb Signed-off-by: HAOUES Ahmed <ahm...@st...> diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index d019c1165e..cde4af5e3b 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -19,6 +19,7 @@ #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) +#define BLUENRGLPF_JTAG_REG (flash_priv_data_lpf.jtag_idcode_reg) #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) @@ -76,6 +77,16 @@ static const struct flash_ctrl_priv_data flash_priv_data_lps = { .part_name = "STM32WB05 (BLUENRG-LPS)", }; +static const struct flash_ctrl_priv_data flash_priv_data_lpf = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x02032041, + .part_name = "STM32WB09 (BLUENRG-LPF)", +}; + struct bluenrgx_flash_bank { bool probed; uint32_t die_id; @@ -86,7 +97,9 @@ static const struct flash_ctrl_priv_data *flash_ctrl[] = { &flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp, - &flash_priv_data_lps}; + &flash_priv_data_lps, + &flash_priv_data_lpf +}; /* flash_bank bluenrg-x 0 0 0 0 <target#> */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -387,7 +400,8 @@ static int bluenrgx_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) { + if (idcode != flash_priv_data_lp.jtag_idcode && idcode != flash_priv_data_lps.jtag_idcode + && idcode != flash_priv_data_lpf.jtag_idcode) { retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; -- |
From: <ge...@op...> - 2025-05-29 11:01:51
|
This is an automated email from Gerrit. "Ahmed Haoues <ahm...@st...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8883 -- gerrit commit 70edb53e2355d4720c9de32b79131cc81713a46a Author: HAOUES Ahmed <ahm...@st...> Date: Tue May 27 11:42:42 2025 +0100 flash/bluenrg-x: support programming without loader fallback programming without loader when resources are not available while at there refactor reused code (wait for interrupt and command execution) Change-Id: I2cba0f53d3470bc324f4a72614c236cebf196f64 Signed-off-by: BOCHKATI Tarek <tar...@st...> Signed-off-by: HAOUES Ahmed <ahm...@st...> diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index a953e9b283..ccbbcc66eb 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -143,8 +143,45 @@ static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); } -static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) +static int bluenrgx_wait_for_interrupt(struct flash_bank *bank, uint32_t interrupt_flag) +{ + bool flag_raised = false; + for (unsigned int j = 0; j < 100; j++) { + uint32_t value; + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value) != ERROR_OK) { + LOG_ERROR("Register read failed"); + return ERROR_FAIL; + } + + if (value & interrupt_flag) { + flag_raised = true; + break; + } + } + + /* clear the interrupt */ + if (flag_raised) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, interrupt_flag) != ERROR_OK) { + LOG_ERROR("Cannot clear interrupt flag"); + return ERROR_FAIL; + } + + return ERROR_OK; + } + + LOG_ERROR("Erase command failed (timeout)"); + return ERROR_TIMEOUT_REACHED; +} + +static inline int bluenrgx_wait_for_command(struct flash_bank *bank) +{ + if (bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDSTART) == ERROR_OK) + return bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDDONE); + + return ERROR_FAIL; +} + +static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval = ERROR_OK; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -186,19 +223,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int i = 0; i < 100; i++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (i == 99) { - LOG_ERROR("Mass erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } else { command = FLASH_CMD_ERASE_PAGE; @@ -222,19 +248,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int j = 0; j < 100; j++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (j == 99) { - LOG_ERROR("Erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } } @@ -242,7 +257,7 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, } -static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, +static int bluenrgx_write_with_loader(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -264,22 +279,6 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; - /* check preconditions */ - if (!bluenrgx_info->probed) - return ERROR_FLASH_BANK_NOT_PROBED; - - if ((offset + count) > bank->size) { - LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, - (offset + count), - bank->size); - return ERROR_FLASH_DST_OUT_OF_BANK; - } - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); @@ -366,6 +365,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) LOG_ERROR("flash write failed = %08" PRIx32, error); } + if (retval == ERROR_OK) { uint32_t rp; /* Read back rp and check that is valid */ @@ -377,6 +377,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, } } } + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); target_free_working_area(target, write_algorithm_stack); @@ -391,6 +392,80 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } +static int bluenrgx_write_without_loader(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + unsigned int data_count = count / FLASH_DATA_WIDTH; + + while (data_count--) { + /* clear flags */ + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, offset >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_memory(target, bluenrgx_get_flash_reg(bank, FLASH_REG_DATA0), + FLASH_WORD_LEN, FLASH_DATA_WIDTH_W, buffer) != ERROR_OK) { + LOG_ERROR("Failed to write data"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, FLASH_CMD_BURSTWRITE) != ERROR_OK) { + LOG_ERROR("Failed"); + return ERROR_FAIL; + } + + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; + + /* increment offset, and buffer */ + offset += FLASH_DATA_WIDTH; + buffer += FLASH_DATA_WIDTH; + } + + return ERROR_OK; +} + +static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int retval = ERROR_OK; + + /* check preconditions */ + if (!bluenrgx_info->probed) + return ERROR_FLASH_BANK_NOT_PROBED; + + if ((offset + count) > bank->size) { + LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, + (offset + count), + bank->size); + return ERROR_FLASH_DST_OUT_OF_BANK; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + assert(offset % FLASH_WORD_LEN == 0); + assert(count % FLASH_WORD_LEN == 0); + + retval = bluenrgx_write_with_loader(bank, buffer, offset, count); + /* if resources are not available write without a loader */ + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + LOG_WARNING("falling back to programming without a flash loader (slower)"); + retval = bluenrgx_write_without_loader(bank, buffer, offset, count); + } + return retval; +} + static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -428,7 +503,7 @@ static int bluenrgx_probe(struct flash_bank *bank) return retval; bank->size = (size_info + 1) * FLASH_WORD_LEN; - bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); + bank->num_sectors = bank->size / FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h index 720cb6e618..03c66cd81a 100644 --- a/src/flash/nor/bluenrg-x.h +++ b/src/flash/nor/bluenrg-x.h @@ -28,7 +28,12 @@ #define FLASH_CMD_WRITE 0x33 #define FLASH_CMD_BURSTWRITE 0xCC #define FLASH_INT_CMDDONE 0x01 +#define FLASH_INT_CMDSTART 0x02 +/* Flash Controller constants */ #define FLASH_WORD_LEN 4 +#define FLASH_DATA_WIDTH_W 4 +#define FLASH_DATA_WIDTH 16 + #endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ -- |
From: <ge...@op...> - 2025-05-29 11:01:45
|
This is an automated email from Gerrit. "Ahmed Haoues <ahm...@st...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8880 -- gerrit commit 8bfe538f099c1b87943355095d70503a68500464 Author: HAOUES Ahmed <ahm...@st...> Date: Tue May 27 11:22:09 2025 +0100 flash/bluenrg-x: Add blueNRG alternate names BlueNRG-LP -> STM32WB07 BlueNRG-LPS -> STM32WB05 Change-Id: I8e05ea29e84d3a7842e145fb66f448d0c82bd004 Signed-off-by: HAOUES Ahmed <ahm...@st...> diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 9ced2e9718..d019c1165e 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -63,7 +63,7 @@ static const struct flash_ctrl_priv_data flash_priv_data_lp = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x0201E041, - .part_name = "BLUENRG-LP", + .part_name = "STM32WB07 (BLUENRG-LP)", }; static const struct flash_ctrl_priv_data flash_priv_data_lps = { @@ -73,7 +73,7 @@ static const struct flash_ctrl_priv_data flash_priv_data_lps = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x02028041, - .part_name = "BLUENRG-LPS", + .part_name = "STM32WB05 (BLUENRG-LPS)", }; struct bluenrgx_flash_bank { -- |
From: <ge...@op...> - 2025-05-29 10:54:22
|
This is an automated email from Gerrit. "Name of user not set <me...@el...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8938 -- gerrit commit a341106452002a4d8669591534df3e593b9cf76f Author: Electric Worry <me...@el...> Date: Thu May 29 11:31:59 2025 +0100 tcl/board/orange_pi_zero_3: Add Orange Pi Zero 3 board The Orange Pi Zero 3 is an SBC that uses an Allwinner H618 SoC. As such, JTAG support is fully available, however the SoC multiplexes JTAG function with UART1 and microSD. Unfortunately Xunlong has used UART1 for the Wifi-BT chip, leaving JTAG accessible only via the microSD using a microSD breakout board (for example). Change-Id: I0dc078cd2f3176815271917eb5e948cc8ef94525 Signed-off-by: Electric Worry <me...@el...> diff --git a/tcl/board/orange_pi_zero_3.cfg b/tcl/board/orange_pi_zero_3.cfg new file mode 100644 index 0000000000..2af983c650 --- /dev/null +++ b/tcl/board/orange_pi_zero_3.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Orange Pi Zero 3 board with Allwinner H618 chip +# http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-3.html +# +# Accessing JTAG signals on Orange Pi Zero 3 board requires connection to pins +# on the microSD card slot. +# 1 - DAT2 - TCK +# 2 - CD/DAT3 - NC +# 3 - CMD - TDO +# 4 - VDD - NC +# 5 - CLK - NC +# 6 - VSS - NC +# 7 - DAT0 - TDI +# 8 - DAT1 - TMS +# +# PF Configure Register 0 at address 0x0300b0b4 must be set 0x07373733 to set +# the JTAG function on these pins (which is what the factory installed image on +# the SPI flash does when the board is powered without a microSD inserted). + +source [find target/allwinner_h618.cfg] + +# To this contributor's knowledge, the board neither exposes TRST nor SRST. +reset_config none -- |
From: <ge...@op...> - 2025-05-29 09:57:27
|
This is an automated email from Gerrit. "Name of user not set <me...@el...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8936 -- gerrit commit 38ccd8677ac2b72733fc673933f38028b85a4a50 Author: Electric Worry <me...@el...> Date: Thu May 29 10:51:59 2025 +0100 target: add support for Allwinner H618 SoC The Allwinner H618 is an updated H616 but appears functionally equivalent. It is used in small boards such as Orange Pi Zero 3. Change-Id: I299a42be746189f3e8e31070aa26b83ab7d806a4 Signed-off-by: Electric Worry <me...@el...> diff --git a/tcl/target/allwinner_h618.cfg b/tcl/target/allwinner_h618.cfg new file mode 100644 index 0000000000..242e9a1579 --- /dev/null +++ b/tcl/target/allwinner_h618.cfg @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Allwinner H618 chip. It is an updated version of the Allwinner H616. + +# Information is available on linux-sunxi.org: +# Datasheet: https://linux-sunxi.org/images/b/b9/H616_Datasheet_V1.0_cleaned.pdf +# Manual: https://linux-sunxi.org/images/2/24/H616_User_Manual_V1.0_cleaned.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME h618 +} + +if { [info exists CHIPCORES] } { + set _cores $CHIPCORES +} else { + set _cores 4 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +# these addresses are obtained from the ROM table via 'dap info 1' command +set _DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000} +set _CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 1 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + $_TARGETNAME configure -event reset-assert-post { aarch64 dbginit } + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 -- |
From: <ge...@op...> - 2025-05-29 09:49:57
|
This is an automated email from Gerrit. "Liam Fletcher <lia...@mi...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8879 -- gerrit commit 6ac7aed4698b05cf281855f34dc813def9246fe0 Author: Liam Fletcher <lia...@mi...> Date: Mon May 26 10:54:40 2025 +0100 tcl: add embedded flashpro5 config To support Microchips Embedded Flashpro5 Change-Id: I7861e0772fd4cbf0539725d238c59ae15bbcca41 Signed-off-by: Liam Fletcher <lia...@mi...> diff --git a/tcl/board/microchip_riscv_efp5.cfg b/tcl/board/microchip_riscv_efp5.cfg new file mode 100644 index 0000000000..3f34ffa5e9 --- /dev/null +++ b/tcl/board/microchip_riscv_efp5.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip RISC-V board +# +# https://www.microchip.com/en-us/products/fpgas-and-plds/fpga-and-soc-design-tools/mi-v +# + +source [find interface/embedded_flashpro5.cfg] +source [find target/microchip_riscv.cfg] diff --git a/tcl/interface/embedded_flashpro5.cfg b/tcl/interface/embedded_flashpro5.cfg new file mode 100644 index 0000000000..e540351d93 --- /dev/null +++ b/tcl/interface/embedded_flashpro5.cfg @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Embedded FlashPro5 +# +# https://www.microchip.com/en-us/development-tool/flashpro5 +# + +adapter driver ftdi + +ftdi vid_pid 0x1514 0x2008 + +# That FTDI has 4 channels (channel 0 and 1 are MPSSE-capable, 2 and 3 are bitbang +ftdi channel 0 + +# Initial Layout - data[0..15] direction[0..15] +ftdi layout_init 0x0018 0xfdfb +# Signal Data Direction Notes +# AD0 TCK 0 1 (out) Port A TCK +# AD1 TDI 0 1 (out) Port A TDI +# AD2 TDO 0 0 (in) PORT A TDO +# AD3 TMS 1 1 (out) Port A TMS +# AD4 GPIOL0 1 1 (out) Port A TRST +# AD5 GPIOL1 0 1 (out) (unused) +# AD6 GPIOL2 0 1 (out) (unused) +# AD7 GPIOL3 0 1 (out) (unused) + +# BD0 TCK 0 1 (out) FTDI_UART_B_TXD +# BD1 TDI 0 0 (in) FTDI_UART_B_RXD +# BD2 TDO 0 1 (out) (unused) +# BD3 TMS 0 1 (out) (unused) +# BD4 GPIOL0 0 1 (out) (unused) +# BD5 GPIOL1 0 1 (out) (unused) +# BD6 GPIOL2 0 1 (out) (unused) +# BD7 GPIOL2 0 1 (out) (unused) + +# Signals definition +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 -- |
From: <ge...@op...> - 2025-05-29 09:49:56
|
This is an automated email from Gerrit. "Liam Fletcher <lia...@mi...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8877 -- gerrit commit 108c7a3bc9b6156e453c0604cc9d87558f73b133 Author: Liam Fletcher <lia...@mi...> Date: Mon May 26 10:30:07 2025 +0100 target: add microchip riscv config To support members of the PIC64GX and Polarfire SoC family, as well as soft MiV processor on FPGA Change-Id: I75dd965f1ce550807706d00fe17de887d36f0b02 Signed-off-by: Liam Fletcher <lia...@mi...> diff --git a/tcl/target/microchip_riscv.cfg b/tcl/target/microchip_riscv.cfg new file mode 100644 index 0000000000..6f469925e3 --- /dev/null +++ b/tcl/target/microchip_riscv.cfg @@ -0,0 +1,288 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +#------------------------------------------------------------------------------ +# Microchip RISC-V +#------------------------------------------------------------------------------ + +transport select jtag + +# PolarFire SoC (MPFS) hart id to name lookup table +array set mpfs_hart_names { + 0 hart0_e51 + 1 hart1_u54_1 + 2 hart2_u54_2 + 3 hart3_u54_3 + 4 hart4_u54_4 +} + +# PIC64GX hart id to name lookup table +array set pic64gx_hart_names { + 0 hart0_e51 + 1 hart1_u54_1 + 2 hart2_u54_2 + 3 hart3_u54_3 + 4 hart4_u54_4 +} + +# MPFS devices table +set mpfs_cpu_tap_info { + MPFS025 0x0f8531cf + MPFS095 0x0f8181cf + MPFS160 0x0f8191cf + MPFS250 0x0f81a1cf + MPFS460 0x0f81b1cf + RTPFS160 0x0f8991cf + RTPFS460 0x0f89b1cf +} + +# PIC64GX table +set pic64gx_tap_info { + PIC64GX1000 0x0f8531cf +} + +# PolarFire table +set polarfire_tap_info { + MPF050 0x0f8101cf + MPF100 0x0f8111cf + MPF200 0x0f8121cf + MPF300 0x0f8131cf + MPF500 0x0f8141cf + RTPF500-A 0x8f8141cf + RTPF500 0x0f8941cf + MPFS250 0x0f81a1cf +} + +# RTG4 table +set rtg4_tap_info { + RT4P6000 0x007001cf + RT4P12000 0x007011cf + RT4P16000 0x007021cf +} + +# MiV Soft Processor table +set miv_tap_info { + MiV1 0x10e31913 + MiV2 0x1c0011cf + MiV3 0x1e50105f +} + +proc expected_ids {tap_list} { + set str "" + dict for {key value} $tap_list { + append str "-expected-id" " " $value " " + } + + return $str +} + +# Process COREID variable +if {![exists COREID]} { + set COREID -1 +} + +# COREID +# For Multi-Hart setups, check COREID, default to -1 (single debug connection +# to all harts) if unspecified or invalid (out of range ) +proc handle_coreid {lower_bound upper_bound coreid} { + if {$coreid < $lower_bound || $coreid > $upper_bound} { + echo [format "Warn : COREID %s not in range ($lower_bound..$upper_bound), defaulting to -1 \ + (single connection to all harts)" $coreid] + set coreid -1 + } + + return $coreid +} + +# "Direct" debugging (not via FPGA TAP) to MiV +proc setup_miv {device tap_info} { + set irlen 5 + set expected_ids [expected_ids $tap_info] + + # RISC-V CPU DTM TAP + eval jtag newtap $device cpu -irlen $irlen $expected_ids -ignore-version + # Mi-V soft core - implicitly single hart + set _TARGETNAME_0 $device.miv + target create $_TARGETNAME_0 riscv -chain-position $device.cpu + + $_TARGETNAME_0 configure -event reset-init board_reset_init + $_TARGETNAME_0 configure -event reset-init init_regs + + # gdb-detach event handler + $_TARGETNAME_0 configure -event gdb-detach { + # resume execution on debugger detach + resume + } + + # + # Utility procedures + # + + proc board_reset_init {} { + # call board level reset-init if defined + if {[exists -proc do_board_reset_init]} { + do_board_reset_init + } + } + + proc init_regs {} { + reg pc 0 + } + + # + # Reset configuration + # + + # Only TRSTn supported + reset_config trst_only +} + +# MPFS +proc setup_mpfs {device coreid tap_info hart_names} { + set coreid [handle_coreid -1 4 $coreid ] + + # RISC-V CPU DTM TAP + set irlen 8 + set expected_ids [expected_ids $tap_info] + eval jtag newtap $device cpu -irlen $irlen $expected_ids -ignore-version + + # PolarFire SoC (MPFS) + if {$coreid == -1} { + # Single debug connection to all harts + set _TARGETNAME_0 $device.$hart_names(0) + set _TARGETNAME_1 $device.$hart_names(1) + set _TARGETNAME_2 $device.$hart_names(2) + set _TARGETNAME_3 $device.$hart_names(3) + set _TARGETNAME_4 $device.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $device.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $device.cpu -coreid 1 + target create $_TARGETNAME_2 riscv -chain-position $device.cpu -coreid 2 + target create $_TARGETNAME_3 riscv -chain-position $device.cpu -coreid 3 + target create $_TARGETNAME_4 riscv -chain-position $device.cpu -coreid 4 + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 + + $_TARGETNAME_1 configure -event reset-init init_regs + $_TARGETNAME_2 configure -event reset-init init_regs + $_TARGETNAME_3 configure -event reset-init init_regs + $_TARGETNAME_4 configure -event reset-init init_regs + + } else { + # Debug connection to a specific hart + set _TARGETNAME_0 $device.$hart_names($coreid) + target create $_TARGETNAME_0 riscv -chain-position $device.cpu -coreid $coreid + } + + $_TARGETNAME_0 configure -event reset-init board_reset_init + $_TARGETNAME_0 configure -event reset-init init_regs + + # gdb-detach event handler + $_TARGETNAME_0 configure -event gdb-detach { + # resume execution on debugger detach + resume + } + + # + # Utility procedures + # + + proc board_reset_init {} { + # call board level reset-init if defined + if {[exists -proc do_board_reset_init]} { + do_board_reset_init + } + } + + proc init_regs {} { + reg pc 0 + } + + # + # Reset configuration + # + + # Only TRSTn supported + reset_config trst_only +} + +proc setup_pic64gx {device coreid tap_info hart_names } { + set coreid [handle_coreid -1 4 $coreid ] + + # RISC-V CPU DTM TAP + set irlen 8 + set expected_ids [expected_ids $tap_info] + eval jtag newtap $device cpu -irlen $irlen $expected_ids -ignore-version + + # PIC64GX + if {$coreid == -1} { + # Single debug connection to all harts + set _TARGETNAME_0 $device.$hart_names(0) + set _TARGETNAME_1 $device.$hart_names(1) + set _TARGETNAME_2 $device.$hart_names(2) + set _TARGETNAME_3 $device.$hart_names(3) + set _TARGETNAME_4 $device.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $device.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $device.cpu -coreid 1 + target create $_TARGETNAME_2 riscv -chain-position $device.cpu -coreid 2 + target create $_TARGETNAME_3 riscv -chain-position $device.cpu -coreid 3 + target create $_TARGETNAME_4 riscv -chain-position $device.cpu -coreid 4 + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 + + $_TARGETNAME_1 configure -event reset-init init_regs + $_TARGETNAME_2 configure -event reset-init init_regs + $_TARGETNAME_3 configure -event reset-init init_regs + $_TARGETNAME_4 configure -event reset-init init_regs + + } else { + # Debug connection to a specific hart + set _TARGETNAME_0 $device.$hart_names($coreid) + target create $_TARGETNAME_0 riscv -chain-position $device.cpu -coreid $coreid + } + + $_TARGETNAME_0 configure -event reset-init board_reset_init + $_TARGETNAME_0 configure -event reset-init init_regs + + # gdb-detach event handler + $_TARGETNAME_0 configure -event gdb-detach { + # resume execution on debugger detach + resume + } + + # + # Utility procedures + # + + proc board_reset_init {} { + # call board level reset-init if defined + if {[exists -proc do_board_reset_init]} { + do_board_reset_init + } + } + + proc init_regs {} { + reg pc 0 + } + + # + # Reset configuration + # + + # Only TRSTn supported + reset_config trst_only +} + +# +# Handle different riscv based devices +# +if {[string range $DEVICE 0 7] eq "pic64gx"} { + echo [format "Info : Connecting to member of PIC64GX family"] + set ret [setup_pic64gx $DEVICE $COREID $pic64gx_tap_info $pic64gx_hart_names] +} elseif {[string range $DEVICE 0 4] eq "mpfs"} { + echo [format "Info : Connecting to member of PolarFire SoC family"] + set ret [setup_mpfs $DEVICE $COREID $mpfs_cpu_tap_info $mpfs_hart_names] +} elseif {[string range $DEVICE 0 3] eq "miv"} { + echo [format "Info : Connecting to soft MiV processor on FPGA"] + set ret [setup_miv $DEVICE $miv_tap_info] +} else { + echo [format "Error: Unknown DEVICE %s" $DEVICE] +} -- |
From: <ge...@op...> - 2025-05-29 09:49:52
|
This is an automated email from Gerrit. "Liam Fletcher <lia...@mi...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8878 -- gerrit commit 17b6fead55b93b541c38f8c8ce5d9caf88a661f1 Author: Liam Fletcher <lia...@mi...> Date: Mon May 26 10:42:56 2025 +0100 tcl: add pic64gx curiosity config To support PIC64GX Curiosity Board Change-Id: I2234d8725744fbae00b3909773b370e5c18debd8 Signed-off-by: Liam Fletcher <lia...@mi...> diff --git a/tcl/board/microchip_pic64gx_curiosity.cfg b/tcl/board/microchip_pic64gx_curiosity.cfg new file mode 100644 index 0000000000..5c6849f49f --- /dev/null +++ b/tcl/board/microchip_pic64gx_curiosity.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip RISC-V board +# +# https://www.microchip.com/en-us/products/microprocessors/64-bit-mpus/pic64gx +# +source [find interface/pic64gx.cfg] +source [find target/microchip_riscv.cfg] diff --git a/tcl/interface/pic64gx.cfg b/tcl/interface/pic64gx.cfg new file mode 100644 index 0000000000..20eb74fce2 --- /dev/null +++ b/tcl/interface/pic64gx.cfg @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# MCHP Debug - PIC64GX +# + +adapter speed 6000 + +adapter driver ftdi + +ftdi vid_pid 0x1514 0x200a + +# That FTDI has 4 channels (channel 0 and 1 are MPSSE-capable, 2 and 3 are bitbang +ftdi channel 0 + +# Initial Layout - data[0..15] direction[0..15] +ftdi layout_init 0x0018 0xfdfb +# Signal Data Direction Notes +# AD0 TCK 0 1 (out) Port A TCK +# AD1 TDI 0 1 (out) Port A TDI +# AD2 TDO 0 0 (in) PORT A TDO +# AD3 TMS 1 1 (out) Port A TMS +# AD4 GPIOL0 1 1 (out) Port A TRST +# AD5 GPIOL1 0 1 (out) (unused) +# AD6 GPIOL2 0 1 (out) (unused) +# AD7 GPIOL3 0 1 (out) (unused) + +# BD0 TCK 0 1 (out) FTDI_UART_B_TXD +# BD1 TDI 0 0 (in) FTDI_UART_B_RXD +# BD2 TDO 0 1 (out) (unused) +# BD3 TMS 0 1 (out) (unused) +# BD4 GPIOL0 0 1 (out) (unused) +# BD5 GPIOL1 0 1 (out) (unused) +# BD6 GPIOL2 0 1 (out) (unused) +# BD7 GPIOL2 0 1 (out) (unused) + +# Signals definition +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 -- |
From: <ge...@op...> - 2025-05-28 15:13:15
|
This is an automated email from Gerrit. "Ivan <Iva...@in...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8876 -- gerrit commit e6ad7d7ad58c47e86c0110429bed785230435141 Author: kryvosheiaivan <Iva...@in...> Date: Wed May 28 16:52:42 2025 +0300 Fix pending transfer Change-Id: I44621ac6096791714910220d04614d0a19ce47bd Signed-off-by: kryvosheiaivan <Iva...@in...> diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index 8fbcb029dd..ca78cf9b8d 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -414,7 +414,20 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p static void cmsis_dap_usb_close(struct cmsis_dap *dap) { for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { - libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + if (dap->bdata->command_transfers[i].status == CMSIS_DAP_TRANSFER_PENDING) { + LOG_DEBUG("busy command USB transfer at %u", dap->pending_fifo_put_idx); + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 1000 + }; + /* Complete pending commands */ + int res = libusb_handle_events_timeout_completed(dap->bdata->usb_ctx, &tv, NULL); + if (res == 0) { + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } + } else { + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } libusb_free_transfer(dap->bdata->response_transfers[i].transfer); } cmsis_dap_usb_free(dap); -- |
From: <ge...@op...> - 2025-05-28 15:03:44
|
This is an automated email from Gerrit. "Antonio Borneo <bor...@gm...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8935 -- gerrit commit a0a5607d31c92f4bfe556efca7f46dfa642e14ab Author: Antonio Borneo <bor...@gm...> Date: Wed May 28 16:58:44 2025 +0200 configure: fix for missing include files on Linux The include files under subfolder 'linux' are not installed by default in all Linux boxes. Add the check in 'configure' for the presence of the include file and conditionally enable the build of the driver. Change-Id: Ie88645c3455ab07622f069a0cc7bf09d1a5a2c75 Signed-off-by: Antonio Borneo <bor...@gm...> Fixes: 7214c8be46f7 ("configure: show adapter Xilinx XVC/PCIe in the configuration summary") Fixes: 83e0293f7ba3 ("Add Linux SPI device SWD adapter support") diff --git a/configure.ac b/configure.ac index e48653b215..10b617195d 100644 --- a/configure.ac +++ b/configure.ac @@ -63,6 +63,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <features.h>]], [[int v = __GLIBC_ AC_MSG_RESULT($have_glibc) AC_CHECK_HEADERS([fcntl.h]) +AC_CHECK_HEADERS([linux/pci.h]) +AC_CHECK_HEADERS([linux/spi/spidev.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([poll.h]) @@ -694,10 +696,10 @@ PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpi PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs]) PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) -PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build]) +PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes"], [Linux build]) PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"], [internal error: validation should happen beforehand]) -PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev]) +PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_spi_spidev_h" = "xyes"], [Linux spidev]) PROCESS_ADAPTERS([VDEBUG_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_DPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused]) -- |
From: Adrien C. <ach...@na...> - 2025-05-28 08:45:23
|
Hi, I'd like to raise again this topic. It would be nice to agree on an acceptable solution for the next OpenOCD release. An extra command to handle the specific case looks good to me. Maybe we need to decide whether we need a very generic command to tweak SCTLR (as proposed by change 6055) or a more specific command that simply targets to clear and invalidate the cache. Thanks. Best regards, Adrien Charruel ________________________________ De : Adrien CHARRUEL <ach...@na...> Envoyé : lundi 5 mai 2025 17:43 À : OpenOCD <ope...@li...> Objet : RE: ARMv8r: Unable to Load ELF With Cache Enabled Vous n’obtenez pas souvent d’e-mail à partir de ach...@na.... Pourquoi c’est important<https://aka.ms/LearnAboutSenderIdentification> Thanks Antonio, So my assumptions were wrong about how openocd accesses the memory and this gives me a better comprehension of what you already explained. The patch you pointed is interesting, I tried to solve my issue with a custom command as well. But my approach was very simple, it was simply to call the function that clears and invalidates both caches (This function has been introduced by the patches we already submitted). I enclose my modifications for information. Giving the issue some thoughts, we might have (at least) two different use cases: * User loads a first ELF that activate the cache in crt0 code. We need to clear and invalidate to properly load a second ELF. My attempt is focused on this case. * User loads a first ELF. Then a second binary that do not need the cache may be loaded. In this case it's important to have a finer access to SCTLR register, as proposed in patch 6055. I'm also wondering if there might be an issue with L1 and L2 caches. Are they both controlled with the same instructions? Note that I didn't read ARM TRM on this topic yet. I'll catch up and get feedback from my team as well. Best regards, Adrien Charruel ________________________________ De : Antonio Borneo <bor...@gm...> Envoyé : lundi 5 mai 2025 16:40 À : Adrien CHARRUEL <ach...@na...> Cc : OpenOCD <ope...@li...> Objet : Re: ARMv8r: Unable to Load ELF With Cache Enabled Thinking over your use case ... what I already wrote is not fully relevant. When a previous FW has enabled the cache, to load and execute a new FW you need either: - or sync I-Cache and D-Cache after any write, but this slows down everything; - or disable caching before loading the 2nd FW. But this also means that the 2nd FW should enable caches if it needs. Today for armv8a/r we do not have an OpenOCD command to disable cache. But there is change 6055 that was targeting this. Do you think this could work in your case? Antonio On Mon, May 5, 2025, 14:55 Antonio Borneo <bor...@gm...<mailto:bor...@gm...>> wrote: Hi Adrian, OpenOCD creates a link between the CPU and GDB. Nor GDB nor OpenOCD have the knowledge required to access the RAM directly (apart for the cortex-m case where the RAM is mapped in the same address space of the debug registers). By the way, not relevant here, there are cases where having GDB accessing the RAM is required, but this is work on progress in https://review.openocd.org/c/openocd/+/8815 Today GDB memory requests are managed through the CPU. For armv8r, OpenOCD injects instructions in the pipeline of the CPU to R/W memory through CPU registers. Memory is read and written by the CPU, eventually passing through the D-Cache. I-Cache is not impacted, so after a memory write it is required to flush D-Cache and invalidate I-Cache before executing a new code. The D-Cache flush requires also a flush of any write buffer present in the CPU. The I-Cache invalidate requires the invalidate of the instructions pre-fetch buffer in the CPU. The sequence provided by ARM should guarantee all is property synchronized. The SW sequence in OpenOCD is incorrect; it misses at least the invalidate of the pre-fetch buffer. Regards Antonio On Mon, May 5, 2025, 14:16 Adrien CHARRUEL <ach...@na...<mailto:ach...@na...>> wrote: Hi Antonio, Sorry the word "sideloading" may not be appropriate in my case. What I meant it that, to my understanding, OpenOCD is loading the ELF file through the DAP of the SoC. The DAP is linked to the interconnect and has access to the embedded RAM to write the binary. The loading of the second ELF file is done without reseting the board. And doing so, it bypasses the caches of the CPUs thus compromising the coherency. So caches have to be invalidated before running the CPUs. Here is a schematic of our architecture. I hope this makes sense. OPENOCD │ │ │ ┌─────────────┐ │ │ │ │ │ eRAM │ │ │ │ │ └──────┬──────┘ ┌────┴─────┐ ┌─────────────────────┴─────────────────────────────────┐ │ │ │ │ │ DAP ├─────┤ ARM Network Interconnect │ │ │ │ │ └──────────┘ └────────────────────────┬──────────────────────────────┘ │ ┌────────────┐ ┌─┌───┴───┐─┐ │ │ │ │ CACHE │ │ │ CORE0 │ │ └───────┘ │ │ TCMA ├─┤ │ │ │ │ │ └────────────┘ │ │ ┌────────────┐ │ CPU0 │ │ │ │ │ │ CORE0 │ │ │ │ TCMB ├─┤ │ │ │ │ │ └────────────┘ └───────────┘ Thanks for your time. Best regards, Adrien Charruel ________________________________ De : Antonio Borneo <bor...@gm...<mailto:bor...@gm...>> Envoyé : dimanche 4 mai 2025 13:03 À : Adrien CHARRUEL <ach...@na...<mailto:ach...@na...>> Cc : ope...@li...<mailto:ope...@li...> <ope...@li...<mailto:ope...@li...>> Objet : Re: ARMv8r: Unable to Load ELF With Cache Enabled On Tue, Apr 29, 2025 at 4:12 PM Adrien CHARRUEL <ach...@na...<mailto:ach...@na...>> wrote: > > Hi, > > I'd like to raise an issue we are having in my team with OpenOCD. I'm not able to load an ELF file from GDB once some code is already running and caches have been enabled. > > Here is a more complete description of my use case: > > Start OpenOCD and connect with GDB. > Load a first ELF file and run it through GDB. This first program enables caches. > Halt the target. > Load a second ELF file through GDB with the "load" command. > Run it => fails... Sometimes I get a crash. For very small program the old one still resides in cache and is executed instead of the new one. > > The issue is that I'm sideloading the binary through the DAP and memory coherency is not preserved. Hi, what do you mean by "sideloading the binary through the DAP" ? The GDB command "load" in your email uses the current target for the load. No sideloading through other APs is implemented. In latest ARM reference manual for armv8a https://developer.arm.com/documentation/ddi0487/latest/ in chapter for 64 bits B2.7.4.2 - "Synchronization and coherency issues between data and instruction accesses" and for 32 bits E2.5.3.2 - "Synchronization and coherency issues between data and instruction accesses" there are the sequences of instructions to guarantee the coherency. I see that OpenOCD code does not respect it. On Cortex-A35 during step-by-step execution, changing a next instruction with a SW breakpoint fails because the CPU has already pre-fetched next instructions. I cannot find information on such a prefetch, but it's reasonable to consider it exists and that the correct sequence from ARM is required to invalidate it. Checking the extra documents for armv8r, DDI0568 and DDI0600, I don't find any specific info. Probably updating the sequence in OpenOCD for my SW breakpoint issue is fixing your issue too. Antonio > Here are some more details on my setup: > > Target: quad cortex-r52 from our in-house chip. It's a standard armv8r core. We use our in-house JTAG probe, Angie, which is upstreamed in openocd. > Configuration script is "ngultra.cfg" enclosed to this email. > Command line: > ./src/openocd -f tcl/interface/angie.cfg -f tcl/target/ngultra.cfg > List of GDB commands: > target remote :3333 > load apps/test_led/out/test_led.elf > file apps/test_led/out/test_led.elf > continue > CTRL+C > load apps/test_led2/out/test_led2.elf > file apps/test_led2/out/test_led2.elf > continue > Expected: second led test should run fine, it's not the case. > OpenOCD logs enclosed as "openocd.log". > > > Version of OpenOCD is SHA1 "169d463a3d3c91f62c980aba287b5e110b310ad0" with extra patches available here: > > https://review.openocd.org/q/topic:nx-armv8r > https://review.openocd.org/q/topic:nx-angie > > > > Potential solution and discussion: > > As there is already a discussion on this topic with Antonio (https://review.openocd.org/c/openocd/+/8656), I removed this part from my patchset. > Indeed Antonio's point is good, it's too slow to attempt a clear cache at every memory write. It's not an option. > > I prepared another patch that adds a "clear_caches" command for aarch64. > The user will have to manually call this before loading another binary. It might be a better solution. > > I'm still wondering if the clear cache could be called from another function, maybe in the aarch64_halt() callback, but I can't tell if there will be side effects. > > Moreover, this behaviour is not only relevant for armv8r but for armv8a as well. I reproduced it by using aarch64 instead of armv8r in the target configuration. > > I hope that my question is clear enough. I'll remain available to discuss this point. > Maybe it's an expected behaviour and I'd like to hear from the community to know how to deal with this issue and for me to have a better understanding of it. > > Thanks a lot. > Best regards, > > > > > Adrien Charruel |
From: Brandon M. <lis...@mo...> - 2025-05-27 19:31:58
|
On 5/24/25 07:34, Tomas Vanek wrote: > Please be aware of *12.2 Preparing a Target before Flash Programming > *""" > The target device should be in well defined state before the flash > programming begins. > Always issue reset init before Flash Programming Commands. ... I guess if we're willing to accept that this is "the only way", then just doing it in the reset init event is sufficient. It seems like it might be a good idea to yell at the user if they attempt flash programming when the target is not in such a well-defined state, but that's outside my pay grade on this one. > *So the Tcl event which should be issued before flash erase/write is > reset-init. With the exception of targets > with totally screwed reset. The IMXRT is only mostly screwed... Bafflingly, the external reset pin basically doesn't work when you're trying to use a debugger. It does something and will in fact case the CPU to "reboot" insofar as it will re-run the ROM bootloader, but trying to halt the core afterward fails for reasons I cannot figure out. Instead, you have to use Cortex-M sysresetreq which introduces other problems. In effect, you end up relying on the watchdog to reset most of the chip for you which leads to obvious problems if you've disabled the watchdog. The most reliable method is to assert POR_B, de-assert it, call for sysresetreq via the core, then attempt to halt it. OpenOCD can't currently do that easily since there's no good reset_config for it. I have a little TCL routine that does it by frobbing the reset_config in the middle of the process. > Unfortunately the Kinetis watchdog is so strict in checking the time > between writes in the switch-off sequence that we have to run a target > algo to meet the sequence timing. > If iMXRT has a similar watchdog then Tcl target memory writes will not work. The IMXRT is similar in that respect. All three watchdogs (two instances of one type and one instance of another) require a pretty tightly-timed sequence of writes to disable them. In fact, I have yet to figure out how to reliably disable one of them. Thankfully the bootloader does it for me for my main application. There is, however, another baffling feature that's essentially a backdoor on the watchdogs. While the watchdogs have all this crazy protection on them, the system reset controller just has a register you can write to that disables resets from the watchdog from taking effect. As far as I can tell, a single write to this register with the right values completely neuters the watchdogs, though I am still testing. It's not even a write-once or otherwise lockable register. |
From: Daniel A. <dan...@gm...> - 2025-05-26 21:01:27
|
<div style="font-family: 'verdana'; font-size: 12px; color: #000;">Hi All<br><br>I'd like to have the following in the Release:<br><br>- <a href="https://deref-gmx.net/mail/client/uCXe98uIIMI/dereferrer/?redirectUrl=https%3A%2F%2Freview.openocd.org%2Fc%2Fopenocd%2F%2B%2F8873" target="_blank" rel="noopener">https://review.openocd.org/c/openocd/+/8873</a><br>it also solves tickets:#434 "Deprecated commands with spaces require quotes"<br><a href="https://deref-gmx.net/mail/client/AkX9GsGVx50/dereferrer/?redirectUrl=https%3A%2F%2Fsourceforge.net%2Fp%2Fopenocd%2Fmailman%2Fmessage%2F58820280%2F" target="_blank" rel="noopener">https://sourceforge.net/p/openocd/mailman/message/58820280/</a><br><br>- <a href="https://deref-gmx.net/mail/client/yQog3QMvcfc/dereferrer/?redirectUrl=https%3A%2F%2Freview.openocd.org%2Fc%2Fopenocd%2F%2B%2F8088" target="_blank" rel="noopener">https://review.openocd.org/c/openocd/+/8088</a><br><br>- further i'd like to have a solution for the depricated command<br>'pld device' which was renamed to 'pld create'<br>the stuff in src/jtag/startup.tc:1166 does not work and I don't know<br>how to solve this. Any help here?<br><br>Regards,<br>danselmi</div> <div id="sub-body-container" style="margin: 10px 5px 5px 10px; padding: 10px 0px 10px 10px; border-left: 2px solid rgb(195, 217, 229);"> <div style="margin: 0px 0px 10px;"> <div><strong>Gesendet: </strong>Freitag, 23. Mai 2025 um 12:16</div> <div><strong>Von: </strong>"Antonio Borneo" <bor...@gm...></div> <div><strong>An: </strong>OpenOCD <Ope...@li...></div> <div><strong>Betreff: </strong>Preparing for OpenOCD v1.0.0-rc1</div> </div> Hello,<br><br>we are going to tag OpenOCD v1.0.0-rc1 in around one month.<br>It will follow a period of code freeze, during which only patches for<br>bug fixes will be merged.<br>The release v1.0.0 is expected before the end of the year.<br><br>Why v1.0.0 ?<br>Because OpenOCD is 20 years old, and at such an age it's mature enough<br>for a cool major release.<br>Because today we have already merged 996 commits since last release<br>v0.12.0 (2023-01-14), and it's time to focus on tests and fixes.<br>Because it's summer and old bugs get hotter, so time to fix them.<br>Because, ... feel free to add your personal reason to this list! ;-)<br><br>Said that, I invite you all to report any feature still pending in<br>Gerrit that you absolutely want to have in v1.0.0.<br><br>Regards,<br>Antonio<br><br></div> |
From: <ge...@op...> - 2025-05-26 05:59:26
|
This is an automated email from Gerrit. "Tomas Vanek <va...@fb...>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/8934 -- gerrit commit 495eb02e1e327de56d9bb6b1dcae445035b0e9fc Author: Tomas Vanek <va...@fb...> Date: Mon May 26 07:54:05 2025 +0200 doc: fix bp usage Commit c8926d14579528bfcead1e179baf7cb846513db4 ("cortex_a hybrid & context breakpoints") missed doc update. Add info about settig hybrid & context breakpoints to chapter 15.5 Breakpoint and Watchpoint commands Change-Id: I4a6fdc83a4c30ad8437c49796de8e6d8c6375c0c Signed-off-by: Tomas Vanek <va...@fb...> diff --git a/doc/openocd.texi b/doc/openocd.texi index ca357c7802..1174ce9799 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9705,12 +9705,14 @@ hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. -@deffn {Command} {bp} [address len [@option{hw}]] +@deffn {Command} {bp} [address [asid] len [@option{hw} | @option{hw_ctx}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. -This is a software breakpoint, unless @option{hw} is specified -in which case it will be a hardware breakpoint. +This is a software breakpoint, unless @option{hw} or @option{hw_ctx} +is specified in which case it will be a hardware, context or hybrid breakpoint. +The context and hybrid breakpoints require an additional parameter @var{asid}: +address space identifier. (@xref{arm9vectorcatch,,arm9 vector_catch}, or @pxref{xscalevectorcatch,,xscale vector_catch}, for similar mechanisms that do not consume hardware breakpoints.) -- |
From: Tomas V. <to...@us...> - 2025-05-25 09:53:39
|
Liam, I'm aware of the series of Microchip patches and believe me the slow (or almost no) progress makes me sad. The idea of the new patch with just the target configuration file is good, actually the same was requested in Antonio's review https://review.openocd.org/c/openocd/+/8561/comment/56c7814e_16ac017c/ half year ago. Please do not abandon other patches, you may rebase them on top of the new patch (now or later). I do not agree with you that microchip_riscv.cfg is ready. Although it may work somehow, I noticed couple of suspicious things and some evident errors. This config is also very complicated as it serves for several different devices and setups. I doubt anybody of OpenOCD team could seriously review it without having access to the hardware. You may try to submit the config first to the RISC-V specialised OpenOCD fork repository https://github.com/riscv-collab/riscv-openocd Tomas On 23/05/2025 15:43, Lia...@mi... wrote: > Hello, > > we see that an RC1 is coming soon. We have some pull requests open for > drivers that will probably not make it in on time, however the > configuration files for the target is ready and can be used with > already upstreamed drivers such as Olimex, etc for software debug. > What we would like to do is to try get the target configuration file > in and drop the patches for driver support. What would be the best way > to do this? Currently Conor Paxton has patches for all the drivers/ > configuration files (8563 > <https://review.openocd.org/c/openocd/+/8563> and 8561 > <https://review.openocd.org/c/openocd/+/8561>). Should we abandon > these and create a new patch with just the target configuration file? > > Thank you in advance for any advice offered. > > Best regards, > > Liam. > > > (apologies if this is a duplication, issue with mail client) > > > |