Merge branch 'master' into from_upstream
Merged 1ad6ed38b6
Conflicts:
src/rtos/rtos_standard_stackings.c
Change-Id: Ica8109135de0f9aa87455353a4538b161b844b04
This commit is contained in:
commit
61a3f65a0c
|
@ -127,8 +127,6 @@ uninstall-hook:
|
|||
distclean-local:
|
||||
rm -rf Doxyfile doxygen
|
||||
rm -f $(srcdir)/jimtcl/configure.gnu
|
||||
# FIXME: workaround for jimtcl 0.80 only. Remove from jimtcl 0.81
|
||||
rm -f jimtcl/examples.api/Makefile
|
||||
|
||||
# We want every change to have Signed-off-by. This is tricky to enforce in
|
||||
# Travis, because it automatically makes temporary commits when merging. So
|
||||
|
|
|
@ -22,37 +22,59 @@
|
|||
* GNU General Public License for more details. *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
|
||||
/*
|
||||
Parameters
|
||||
r0 - destination address
|
||||
r1 - source address
|
||||
r2 - count
|
||||
r2 - half pages
|
||||
r3 - bytes per half page
|
||||
r4 - flash base
|
||||
Variables
|
||||
r0 - destination write pointer
|
||||
r1 - source read pointer
|
||||
r2 - source limit address
|
||||
r3 - bytes per half page
|
||||
r4 - flash base
|
||||
r5 - pages left in current half page
|
||||
r6 - temporary r/w
|
||||
*/
|
||||
|
||||
/* offsets of registers from flash reg base */
|
||||
#define STM32_FLASH_SR_OFFSET 0x18
|
||||
|
||||
.thumb_func
|
||||
.global _start
|
||||
_start:
|
||||
// r2 = source + count * 4
|
||||
lsls r2, r2, #2
|
||||
adds r2, r1, r2
|
||||
// r2 = source + half pages * bytes per half page
|
||||
muls r2, r2, r3
|
||||
add r2, r1, r2
|
||||
// Go to compare
|
||||
b test_done
|
||||
write_half_page:
|
||||
// initialize pages left in current half page
|
||||
mov r5, r3
|
||||
write_word:
|
||||
// load word from address in r1 and increase r1 by 4
|
||||
ldmia r1!, {r3}
|
||||
ldmia r1!, {r6}
|
||||
// store word to address in r0 and increase r0 by 4
|
||||
stmia r0!, {r3}
|
||||
test_done:
|
||||
// compare r1 and r2
|
||||
cmp r1, r2
|
||||
// loop if not equal
|
||||
stmia r0!, {r6}
|
||||
// check for end of half page
|
||||
subs r5, r5, #4
|
||||
bne write_word
|
||||
wait_busy:
|
||||
// read status register into r6, loop while bottom bit is set
|
||||
ldr r6, [r4, #STM32_FLASH_SR_OFFSET]
|
||||
lsls r6, r6, #31
|
||||
bne wait_busy
|
||||
test_done:
|
||||
// compare r1 and r2, loop if not equal
|
||||
cmp r1, r2
|
||||
bne write_half_page
|
||||
|
||||
// Set breakpoint to exit
|
||||
bkpt #0x00
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0x92,0x00,0x8a,0x18,0x01,0xe0,0x08,0xc9,0x08,0xc0,0x91,0x42,0xfb,0xd1,0x00,0xbe,
|
||||
0x5a,0x43,0x0a,0x44,0x07,0xe0,0x1d,0x46,0x40,0xc9,0x40,0xc0,0x04,0x3d,0xfb,0xd1,
|
||||
0xa6,0x69,0xf6,0x07,0xfc,0xd1,0x91,0x42,0xf5,0xd1,0x00,0xbe,
|
||||
|
|
143
doc/openocd.texi
143
doc/openocd.texi
|
@ -2367,6 +2367,14 @@ The USB bus topology can be queried with the command @emph{lsusb -t} or @emph{dm
|
|||
This command is only available if your libusb1 is at least version 1.0.16.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {adapter serial} serial_string
|
||||
Specifies the @var{serial_string} of the adapter to use.
|
||||
If this command is not specified, serial strings are not checked.
|
||||
Only the following adapter drivers use the serial string from this command:
|
||||
aice (aice_usb), arm-jtag-ew, cmsis_dap, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus,
|
||||
openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110.
|
||||
@end deffn
|
||||
|
||||
@section Interface Drivers
|
||||
|
||||
Each of the interface drivers listed here must be explicitly
|
||||
|
@ -2419,11 +2427,6 @@ cmsis_dap_vid_pid 0xc251 0xf001 0x0d28 0x0204
|
|||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {cmsis_dap_serial} [serial]
|
||||
Specifies the @var{serial} of the CMSIS-DAP device to use.
|
||||
If not specified, serial numbers are not considered.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {cmsis_dap_backend} [@option{auto}|@option{usb_bulk}|@option{hid}]
|
||||
Specifies how to communicate with the adapter:
|
||||
|
||||
|
@ -2459,7 +2462,7 @@ This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial
|
|||
Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H.
|
||||
|
||||
The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device,
|
||||
bypassing intermediate libraries like libftdi or D2XX.
|
||||
bypassing intermediate libraries like libftdi.
|
||||
|
||||
Support for new FTDI based adapters can be added completely through
|
||||
configuration files, without the need to patch and rebuild OpenOCD.
|
||||
|
@ -2508,15 +2511,6 @@ of the adapter. If not specified, the device description is ignored
|
|||
during device selection.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {ftdi serial} serial-number
|
||||
Specifies the @var{serial-number} of the adapter to use,
|
||||
in case the vendor provides unique IDs and more than one adapter
|
||||
is connected to the host.
|
||||
If not specified, serial numbers are not considered.
|
||||
(Note that USB serial numbers can be arbitrary Unicode strings,
|
||||
and are not restricted to containing only decimal digits.)
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {ftdi channel} channel
|
||||
Selects the channel of the FTDI device to use for MPSSE operations. Most
|
||||
adapters use the default, channel 0, but there are exceptions.
|
||||
|
@ -2637,12 +2631,6 @@ The vendor ID and product ID of the adapter. If not specified, default
|
|||
0x0403:0x6001 is used.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {ft232r serial_desc} @var{serial}
|
||||
Specifies the @var{serial} of the adapter to use, in case the
|
||||
vendor provides unique IDs and more than one adapter is connected to
|
||||
the host. If not specified, serial numbers are not considered.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {ft232r jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo}
|
||||
Set four JTAG GPIO numbers at once.
|
||||
If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used.
|
||||
|
@ -2728,13 +2716,6 @@ USB JTAG/USB-Blaster compatibles over one of the userspace libraries
|
|||
for FTDI chips. These interfaces have several commands, used to
|
||||
configure the driver before initializing the JTAG scan chain:
|
||||
|
||||
@deffn {Config Command} {usb_blaster device_desc} description
|
||||
Provides the USB device description (the @emph{iProduct string})
|
||||
of the FTDI FT245 device. If not
|
||||
specified, the FTDI default value is used. This setting is only valid
|
||||
if compiled with FTD2XX support.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {usb_blaster vid_pid} vid pid
|
||||
The vendor ID and product ID of the FTDI FT245 device. If not specified,
|
||||
default values are used.
|
||||
|
@ -2840,7 +2821,7 @@ Reset the current configuration.
|
|||
@deffn {Command} {jlink config write}
|
||||
Write the current configuration to the internal persistent storage.
|
||||
@end deffn
|
||||
@deffn {Command} {jlink emucom write <channel> <data>}
|
||||
@deffn {Command} {jlink emucom write} <channel> <data>
|
||||
Write data to an EMUCOM channel. The data needs to be encoded as hexadecimal
|
||||
pairs.
|
||||
|
||||
|
@ -2850,7 +2831,7 @@ the EMUCOM channel 0x10:
|
|||
> jlink emucom write 0x10 aa0b23
|
||||
@end example
|
||||
@end deffn
|
||||
@deffn {Command} {jlink emucom read <channel> <length>}
|
||||
@deffn {Command} {jlink emucom read} <channel> <length>
|
||||
Read data from an EMUCOM channel. The read data is encoded as hexadecimal
|
||||
pairs.
|
||||
|
||||
|
@ -2866,12 +2847,6 @@ to the host. If not specified, USB addresses are not considered. Device
|
|||
selection via USB address is not always unambiguous. It is recommended to use
|
||||
the serial number instead, if possible.
|
||||
|
||||
As a configuration command, it can be used only before 'init'.
|
||||
@end deffn
|
||||
@deffn {Config Command} {jlink serial} <serial number>
|
||||
Set the serial number of the interface, in case more than one adapter is
|
||||
connected to the host. If not specified, serial numbers are not considered.
|
||||
|
||||
As a configuration command, it can be used only before 'init'.
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
@ -2914,11 +2889,6 @@ Indicate that a PSoC acquisition sequence needs to be run during adapter init.
|
|||
Please be aware that the acquisition sequence hard-resets the target.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {kitprog_serial} serial
|
||||
Select a KitProg device by its @var{serial}. If left unspecified, the first
|
||||
device detected by OpenOCD will be used.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {kitprog acquire_psoc}
|
||||
Run a PSoC acquisition sequence immediately. Typically, this should not be used
|
||||
outside of the target-specific configuration scripts since it hard-resets the
|
||||
|
@ -3033,9 +3003,6 @@ parport cable wiggler
|
|||
|
||||
@deffn {Interface Driver} {presto}
|
||||
ASIX PRESTO USB JTAG programmer.
|
||||
@deffn {Config Command} {presto serial} serial_string
|
||||
Configures the USB serial number of the Presto device to use.
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Driver} {rlink}
|
||||
|
@ -3072,10 +3039,6 @@ version reported is V2.J21.S4.
|
|||
Currently Not Supported.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {hla_serial} serial
|
||||
Specifies the serial number of the adapter.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {hla_layout} (@option{stlink}|@option{icdi}|@option{nulink})
|
||||
Specifies the adapter layout to use.
|
||||
@end deffn
|
||||
|
@ -3124,10 +3087,6 @@ ST-LINK server software module}.
|
|||
@emph{Note:} ST-Link TCP server does not support the SWIM transport.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {st-link serial} serial
|
||||
Specifies the serial number of the adapter.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {st-link vid_pid} [vid pid]+
|
||||
Pairs of vendor IDs and product IDs of the device.
|
||||
@end deffn
|
||||
|
@ -3167,11 +3126,6 @@ LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB
|
|||
debug probe with the added capability to supply power to the target board. The
|
||||
following commands are supported by the XDS110 driver:
|
||||
|
||||
@deffn {Config Command} {xds110 serial} serial_string
|
||||
Specifies the serial number of which XDS110 probe to use. Otherwise, the first
|
||||
XDS110 found will be used.
|
||||
@end deffn
|
||||
|
||||
@deffn {Config Command} {xds110 supply} voltage_in_millivolts
|
||||
Available only on the XDS110 stand-alone probe. Sets the voltage level of the
|
||||
XDS110 power supply. A value of 0 leaves the supply off. Otherwise, the supply
|
||||
|
@ -3214,6 +3168,8 @@ able to coexist nicely with both sysfs bitbanging and various
|
|||
peripherals' kernel drivers. The driver restores the previous
|
||||
configuration on exit.
|
||||
|
||||
GPIO numbers >= 32 can't be used for performance reasons.
|
||||
|
||||
See @file{interface/raspberrypi-native.cfg} for a sample config and
|
||||
pinout.
|
||||
|
||||
|
@ -3476,11 +3432,6 @@ Declares a single DAP which uses SWD transport.
|
|||
Parameters are currently the same as "jtag newtap" but this is
|
||||
expected to change.
|
||||
@end deffn
|
||||
@deffn {Command} {swd wcr trn prescale}
|
||||
Updates TRN (turnaround delay) and prescaling.fields of the
|
||||
Wire Control Register (WCR).
|
||||
No parameters: displays current settings.
|
||||
@end deffn
|
||||
|
||||
@subsection SPI Transport
|
||||
@cindex SPI
|
||||
|
@ -4409,6 +4360,20 @@ A DAP may also provide optional @var{configparams}:
|
|||
register during initial examination and when checking the sticky error bit.
|
||||
This bit is normally checked after setting the CSYSPWRUPREQ bit, but some
|
||||
devices do not set the ack bit until sometime later.
|
||||
|
||||
@item @code{-dp-id} @var{number}
|
||||
@*Debug port identification number for SWD DPv2 multidrop.
|
||||
The @var{number} is written to bits 0..27 of DP TARGETSEL during DP selection.
|
||||
To find the id number of a single connected device read DP TARGETID:
|
||||
@code{device.dap dpreg 0x24}
|
||||
Use bits 0..27 of TARGETID.
|
||||
|
||||
@item @code{-instance-id} @var{number}
|
||||
@*Instance identification number for SWD DPv2 multidrop.
|
||||
The @var{number} is written to bits 28..31 of DP TARGETSEL during DP selection.
|
||||
To find the instance number of a single connected device read DP DLPIDR:
|
||||
@code{device.dap dpreg 0x34}
|
||||
The instance number is in bits 28..31 of DLPIDR value.
|
||||
@end itemize
|
||||
@end deffn
|
||||
|
||||
|
@ -5585,6 +5550,10 @@ will not work. These include all @command{*_image} and
|
|||
functionality is available through the @command{flash write_bank},
|
||||
@command{flash read_bank}, and @command{flash verify_bank} commands.
|
||||
|
||||
According to device size, 1- to 4-byte addresses are sent. However, some
|
||||
flash chips additionally have to be switched to 4-byte addresses by an extra
|
||||
command, see below.
|
||||
|
||||
@itemize
|
||||
@item @var{ir} ... is loaded into the JTAG IR to map the flash as the JTAG DR.
|
||||
For the bitstreams generated from @file{xilinx_bscan_spi.py} this is the
|
||||
|
@ -5597,6 +5566,29 @@ set _XILINX_USER1 0x02
|
|||
flash bank $_FLASHNAME spi 0x0 0 0 0 \
|
||||
$_TARGETNAME $_XILINX_USER1
|
||||
@end example
|
||||
|
||||
@deffn Command {jtagspi set} bank_id name total_size page_size read_cmd unused pprg_cmd mass_erase_cmd sector_size sector_erase_cmd
|
||||
Sets flash parameters: @var{name} human readable string, @var{total_size}
|
||||
size in bytes, @var{page_size} is write page size. @var{read_cmd} and @var{pprg_cmd}
|
||||
are commands for read and page program, respectively. @var{mass_erase_cmd},
|
||||
@var{sector_size} and @var{sector_erase_cmd} are optional.
|
||||
@example
|
||||
jtagspi set 0 w25q128 0x1000000 0x100 0x03 0 0x02 0xC7 0x10000 0xD8
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn Command {jtagspi cmd} bank_id resp_num cmd_byte ...
|
||||
Sends command @var{cmd_byte} and at most 20 following bytes and reads
|
||||
@var{resp_num} bytes afterwards. E.g. for 'Enter 4-byte address mode'
|
||||
@example
|
||||
jtagspi cmd 0 0 0xB7
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn Command {jtagspi always_4byte} bank_id [ on | off ]
|
||||
Some devices use 4-byte addresses for all commands except the legacy 0x03 read
|
||||
regardless of device size. This command controls the corresponding hack.
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} {xcf}
|
||||
|
@ -7098,8 +7090,8 @@ applied to all of them.
|
|||
|
||||
@deffn {Flash Driver} {stm32f1x}
|
||||
All members of the STM32F0, STM32F1 and STM32F3 microcontroller families
|
||||
from STMicroelectronics and all members of the GD32F1x0 and GD32F3x0 microcontroller
|
||||
families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4 cores.
|
||||
from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller
|
||||
families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores.
|
||||
The driver automatically recognizes a number of these chips using
|
||||
the chip identification register, and autoconfigures itself.
|
||||
|
||||
|
@ -7612,7 +7604,7 @@ Some tms470-specific commands are defined:
|
|||
Saves programming keys in a register, to enable flash erase and write commands.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {tms470 osc_mhz} clock_mhz
|
||||
@deffn {Command} {tms470 osc_megahertz} clock_mhz
|
||||
Reports the clock speed, which is used to calculate timings.
|
||||
@end deffn
|
||||
|
||||
|
@ -8647,7 +8639,7 @@ If the control block location is not known, OpenOCD starts searching for it.
|
|||
Stop RTT.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {rtt polling_interval [interval]}
|
||||
@deffn {Command} {rtt polling_interval} [interval]
|
||||
Display the polling interval.
|
||||
If @var{interval} is provided, set the polling interval.
|
||||
The polling interval determines (in milliseconds) how often the up-channels are
|
||||
|
@ -9502,7 +9494,7 @@ cores @emph{except the ARM1176} use the same six bits.
|
|||
display information about target caches
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {cortex_a dacrfixup [@option{on}|@option{off}]}
|
||||
@deffn {Command} {cortex_a dacrfixup} [@option{on}|@option{off}]
|
||||
Work around issues with software breakpoints when the program text is
|
||||
mapped read-only by the operating system. This option sets the CP15 DACR
|
||||
to "all-manager" to bypass MMU permission checks on memory access.
|
||||
|
@ -9540,12 +9532,12 @@ possible (4096) entries are printed.
|
|||
@subsection ARMv7-R specific commands
|
||||
@cindex Cortex-R
|
||||
|
||||
@deffn {Command} {cortex_r dbginit}
|
||||
@deffn {Command} {cortex_r4 dbginit}
|
||||
Initialize core debug
|
||||
Enables debug by unlocking the Software Lock and clearing sticky powerdown indications
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {cortex_r maskisr} [@option{on}|@option{off}]
|
||||
@deffn {Command} {cortex_r4 maskisr} [@option{on}|@option{off}]
|
||||
Selects whether interrupts will be processed when single stepping
|
||||
@end deffn
|
||||
|
||||
|
@ -10108,14 +10100,6 @@ included in the generated target descriptor file.
|
|||
addreg rtest 0x1234 org.gnu.gdb.or1k.group0 system
|
||||
@end example
|
||||
|
||||
|
||||
@end deffn
|
||||
@deffn {Command} {readgroup} (@option{group})
|
||||
Display all registers in @emph{group}.
|
||||
|
||||
@emph{group} can be "system",
|
||||
"dmmu", "immu", "dcache", "icache", "mac", "debug", "perf", "power", "pic",
|
||||
"timer" or any new group created with addreg command.
|
||||
@end deffn
|
||||
|
||||
@section RISC-V Architecture
|
||||
|
@ -10232,11 +10216,6 @@ Set the maximum time to wait for a hart to come out of reset after reset is
|
|||
deasserted.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {riscv set_scratch_ram} none|[address]
|
||||
Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'.
|
||||
This is used to access 64-bit floating point registers on 32-bit targets.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {riscv set_prefer_sba} on|off
|
||||
@emph{DEPRECATED -- avoid using this.
|
||||
Use the command @command{riscv set_mem_access} instead.}
|
||||
|
|
2
jimtcl
2
jimtcl
|
@ -1 +1 @@
|
|||
Subproject commit 2d66360c61d2a89d4008e8bad12ae3aa5f0331e2
|
||||
Subproject commit 70b007b63669a709b0e8aef34a22658047815cc2
|
|
@ -528,8 +528,7 @@ static COMMAND_HELPER(create_nand_device, const char *bank_name,
|
|||
}
|
||||
|
||||
if (controller->commands) {
|
||||
retval = register_commands(CMD_CTX, NULL,
|
||||
controller->commands);
|
||||
retval = register_commands(CMD_CTX, NULL, controller->commands);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -251,6 +251,7 @@ static const struct samd_part saml21_parts[] = {
|
|||
|
||||
/* SAMR34/R35 parts have integrated SAML21 with a lora radio */
|
||||
{ 0x28, "SAMR34J18", 256, 32 },
|
||||
{ 0x2B, "SAMR35J18", 256, 32 },
|
||||
};
|
||||
|
||||
/* Known SAML22 parts. */
|
||||
|
|
|
@ -119,9 +119,9 @@ static const struct efm32_family_data efm32_families[] = {
|
|||
{ 16, "EFR32MG1P Mighty", .series = 1 },
|
||||
{ 17, "EFR32MG1B Mighty", .series = 1 },
|
||||
{ 18, "EFR32MG1V Mighty", .series = 1 },
|
||||
{ 19, "EFR32MG1P Blue", .series = 1 },
|
||||
{ 20, "EFR32MG1B Blue", .series = 1 },
|
||||
{ 21, "EFR32MG1V Blue", .series = 1 },
|
||||
{ 19, "EFR32BG1P Blue", .series = 1 },
|
||||
{ 20, "EFR32BG1B Blue", .series = 1 },
|
||||
{ 21, "EFR32BG1V Blue", .series = 1 },
|
||||
{ 25, "EFR32FG1P Flex", .series = 1 },
|
||||
{ 26, "EFR32FG1B Flex", .series = 1 },
|
||||
{ 27, "EFR32FG1V Flex", .series = 1 },
|
||||
|
|
|
@ -29,9 +29,12 @@
|
|||
|
||||
struct jtagspi_flash_bank {
|
||||
struct jtag_tap *tap;
|
||||
const struct flash_device *dev;
|
||||
struct flash_device dev;
|
||||
char devname[32];
|
||||
bool probed;
|
||||
bool always_4byte; /* use always 4-byte address except for basic read 0x03 */
|
||||
uint32_t ir;
|
||||
unsigned int addr_len; /* address length in bytes */
|
||||
};
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
|
||||
|
@ -46,6 +49,7 @@ FLASH_BANK_COMMAND_HANDLER(jtagspi_flash_bank_command)
|
|||
LOG_ERROR("no memory for flash bank info");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
bank->sectors = NULL;
|
||||
bank->driver_priv = info;
|
||||
|
||||
info->tap = NULL;
|
||||
|
@ -69,70 +73,59 @@ static void jtagspi_set_ir(struct flash_bank *bank)
|
|||
jtag_add_ir_scan(info->tap, &field, TAP_IDLE);
|
||||
}
|
||||
|
||||
static void flip_u8(uint8_t *in, uint8_t *out, int len)
|
||||
static void flip_u8(const uint8_t *in, uint8_t *out, unsigned int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
out[i] = flip_u32(in[i], 8);
|
||||
}
|
||||
|
||||
static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
||||
uint32_t *addr, uint8_t *data, int len)
|
||||
uint8_t *write_buffer, unsigned int write_len, uint8_t *data_buffer, int data_len)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
assert(write_buffer || write_len == 0);
|
||||
assert(data_buffer || data_len == 0);
|
||||
|
||||
struct scan_field fields[6];
|
||||
uint8_t marker = 1;
|
||||
uint8_t xfer_bits_buf[4];
|
||||
uint8_t addr_buf[3];
|
||||
uint8_t *data_buf;
|
||||
uint32_t xfer_bits;
|
||||
int is_read, lenb, n;
|
||||
|
||||
/* LOG_DEBUG("cmd=0x%02x len=%i", cmd, len); */
|
||||
LOG_DEBUG("cmd=0x%02x write_len=%d data_len=%d", cmd, write_len, data_len);
|
||||
|
||||
is_read = (len < 0);
|
||||
/* negative data_len == read operation */
|
||||
const bool is_read = (data_len < 0);
|
||||
if (is_read)
|
||||
len = -len;
|
||||
|
||||
n = 0;
|
||||
data_len = -data_len;
|
||||
|
||||
int n = 0;
|
||||
const uint8_t marker = 1;
|
||||
fields[n].num_bits = 1;
|
||||
fields[n].out_value = ▮
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
xfer_bits = 8 + len - 1;
|
||||
/* cmd + read/write - 1 due to the counter implementation */
|
||||
if (addr)
|
||||
xfer_bits += 24;
|
||||
h_u32_to_be(xfer_bits_buf, xfer_bits);
|
||||
flip_u8(xfer_bits_buf, xfer_bits_buf, 4);
|
||||
fields[n].num_bits = 32;
|
||||
fields[n].out_value = xfer_bits_buf;
|
||||
/* transfer length = cmd + address + read/write,
|
||||
* -1 due to the counter implementation */
|
||||
uint8_t xfer_bits[4];
|
||||
h_u32_to_be(xfer_bits, ((sizeof(cmd) + write_len + data_len) * CHAR_BIT) - 1);
|
||||
flip_u8(xfer_bits, xfer_bits, sizeof(xfer_bits));
|
||||
fields[n].num_bits = sizeof(xfer_bits) * CHAR_BIT;
|
||||
fields[n].out_value = xfer_bits;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
cmd = flip_u32(cmd, 8);
|
||||
fields[n].num_bits = 8;
|
||||
flip_u8(&cmd, &cmd, sizeof(cmd));
|
||||
fields[n].num_bits = sizeof(cmd) * CHAR_BIT;
|
||||
fields[n].out_value = &cmd;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
|
||||
if (addr) {
|
||||
h_u24_to_be(addr_buf, *addr);
|
||||
flip_u8(addr_buf, addr_buf, 3);
|
||||
fields[n].num_bits = 24;
|
||||
fields[n].out_value = addr_buf;
|
||||
if (write_len) {
|
||||
flip_u8(write_buffer, write_buffer, write_len);
|
||||
fields[n].num_bits = write_len * CHAR_BIT;
|
||||
fields[n].out_value = write_buffer;
|
||||
fields[n].in_value = NULL;
|
||||
n++;
|
||||
}
|
||||
|
||||
lenb = DIV_ROUND_UP(len, 8);
|
||||
data_buf = malloc(lenb);
|
||||
if (lenb > 0) {
|
||||
if (!data_buf) {
|
||||
LOG_ERROR("no memory for spi buffer");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (data_len > 0) {
|
||||
if (is_read) {
|
||||
fields[n].num_bits = jtag_tap_count_enabled();
|
||||
fields[n].out_value = NULL;
|
||||
|
@ -140,36 +133,263 @@ static int jtagspi_cmd(struct flash_bank *bank, uint8_t cmd,
|
|||
n++;
|
||||
|
||||
fields[n].out_value = NULL;
|
||||
fields[n].in_value = data_buf;
|
||||
fields[n].in_value = data_buffer;
|
||||
} else {
|
||||
flip_u8(data, data_buf, lenb);
|
||||
fields[n].out_value = data_buf;
|
||||
flip_u8(data_buffer, data_buffer, data_len);
|
||||
fields[n].out_value = data_buffer;
|
||||
fields[n].in_value = NULL;
|
||||
}
|
||||
fields[n].num_bits = len;
|
||||
fields[n].num_bits = data_len * CHAR_BIT;
|
||||
n++;
|
||||
}
|
||||
|
||||
jtagspi_set_ir(bank);
|
||||
/* passing from an IR scan to SHIFT-DR clears BYPASS registers */
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
jtag_add_dr_scan(info->tap, n, fields, TAP_IDLE);
|
||||
int retval = jtag_execute_queue();
|
||||
|
||||
if (is_read)
|
||||
flip_u8(data_buf, data, lenb);
|
||||
free(data_buf);
|
||||
flip_u8(data_buffer, data_buffer, data_len);
|
||||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jtagspi_handle_set)
|
||||
{
|
||||
struct flash_bank *bank = NULL;
|
||||
struct jtagspi_flash_bank *info = NULL;
|
||||
struct flash_sector *sectors = NULL;
|
||||
uint32_t temp;
|
||||
unsigned int index = 1;
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
/* there are 6 mandatory arguments:
|
||||
* devname, size_in_bytes, pagesize, read_cmd, unused, pprog_cmd */
|
||||
if (index + 6 > CMD_ARGC) {
|
||||
command_print(CMD, "jtagspi: not enough arguments");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
info = bank->driver_priv;
|
||||
|
||||
/* invalidate all old info */
|
||||
if (info->probed) {
|
||||
bank->size = 0;
|
||||
bank->num_sectors = 0;
|
||||
if (bank->sectors)
|
||||
free(bank->sectors);
|
||||
bank->sectors = NULL;
|
||||
info->always_4byte = false;
|
||||
info->probed = false;
|
||||
}
|
||||
memset(&info->dev, 0, sizeof(info->dev));
|
||||
|
||||
strncpy(info->devname, CMD_ARGV[index++], sizeof(info->devname) - 1);
|
||||
info->devname[sizeof(info->devname) - 1] = '\0';
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp);
|
||||
info->dev.size_in_bytes = temp;
|
||||
if ((temp & (temp - 1)) || (temp < (1UL << 8))) {
|
||||
command_print(CMD, "jtagspi: device size must be 2^n with n >= 8");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp);
|
||||
info->dev.pagesize = temp;
|
||||
if (info->dev.pagesize == 0)
|
||||
info->dev.pagesize = SPIFLASH_DEF_PAGESIZE;
|
||||
if ((temp & (temp - 1)) || (temp > info->dev.size_in_bytes)) {
|
||||
command_print(CMD, "jtagspi: page size must be 2^n and <= device size");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.read_cmd);
|
||||
if ((info->dev.read_cmd != 0x03) &&
|
||||
(info->dev.read_cmd != 0x13)) {
|
||||
command_print(CMD, "jtagspi: only 0x03/0x13 READ allowed");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.qread_cmd);
|
||||
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.pprog_cmd);
|
||||
if ((info->dev.pprog_cmd != 0x02) &&
|
||||
(info->dev.pprog_cmd != 0x12)) {
|
||||
command_print(CMD, "jtagspi: only 0x02/0x12 PPRG allowed");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* remaining params are optional */
|
||||
if (index < CMD_ARGC)
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.chip_erase_cmd);
|
||||
else
|
||||
info->dev.chip_erase_cmd = 0x00;
|
||||
|
||||
if (index < CMD_ARGC) {
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[index++], temp);
|
||||
info->dev.sectorsize = temp;
|
||||
if ((info->dev.sectorsize > info->dev.size_in_bytes) ||
|
||||
(info->dev.sectorsize < info->dev.pagesize) || (temp & (temp - 1))) {
|
||||
command_print(CMD, "jtagspi: sector size must be 2^n and <= device size");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
if (index < CMD_ARGC)
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], info->dev.erase_cmd);
|
||||
else {
|
||||
command_print(CMD, "jtagspi: erase command missing");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
} else {
|
||||
/* no sector size / sector erase cmd given, treat whole bank as a single sector */
|
||||
info->dev.erase_cmd = 0x00;
|
||||
info->dev.sectorsize = info->dev.size_in_bytes;
|
||||
}
|
||||
|
||||
if (index < CMD_ARGC) {
|
||||
command_print(CMD, "jtagspi: extra arguments");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
/* set correct size value */
|
||||
bank->size = info->dev.size_in_bytes;
|
||||
|
||||
/* calculate address length in bytes */
|
||||
if (bank->size <= (1UL << 8))
|
||||
info->addr_len = 1;
|
||||
else if (bank->size <= (1UL << 16))
|
||||
info->addr_len = 2;
|
||||
else if (bank->size <= (1UL << 24))
|
||||
info->addr_len = 3;
|
||||
else {
|
||||
info->addr_len = 4;
|
||||
LOG_WARNING("4-byte addresses needed, might need extra command to enable");
|
||||
}
|
||||
|
||||
/* create and fill sectors array */
|
||||
bank->num_sectors =
|
||||
info->dev.size_in_bytes / info->dev.sectorsize;
|
||||
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
if (!sectors) {
|
||||
LOG_ERROR("Not enough memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
|
||||
sectors[sector].offset = sector * (info->dev.sectorsize);
|
||||
sectors[sector].size = info->dev.sectorsize;
|
||||
sectors[sector].is_erased = -1;
|
||||
sectors[sector].is_protected = 0;
|
||||
}
|
||||
|
||||
bank->sectors = sectors;
|
||||
info->dev.name = info->devname;
|
||||
if (info->dev.size_in_bytes / 4096)
|
||||
LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " kbytes",
|
||||
info->dev.name, info->dev.size_in_bytes / 1024);
|
||||
else
|
||||
LOG_INFO("flash \'%s\' id = unknown\nflash size = %" PRIu32 " bytes",
|
||||
info->dev.name, info->dev.size_in_bytes);
|
||||
info->probed = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jtagspi_handle_cmd)
|
||||
{
|
||||
struct flash_bank *bank;
|
||||
unsigned int index = 1;
|
||||
const int max = 21;
|
||||
uint8_t num_write, num_read, write_buffer[max], read_buffer[1 << CHAR_BIT];
|
||||
uint8_t data, *ptr;
|
||||
char temp[4], output[(2 + max + (1 << CHAR_BIT)) * 3 + 8];
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if (CMD_ARGC < 3) {
|
||||
command_print(CMD, "jtagspi: not enough arguments");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
num_write = CMD_ARGC - 2;
|
||||
if (num_write > max) {
|
||||
LOG_ERROR("at most %d bytes may be send", max);
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index++], num_read);
|
||||
|
||||
snprintf(output, sizeof(output), "spi: ");
|
||||
for (ptr = &write_buffer[0] ; index < CMD_ARGC; index++) {
|
||||
COMMAND_PARSE_NUMBER(u8, CMD_ARGV[index], data);
|
||||
*ptr++ = data;
|
||||
snprintf(temp, sizeof(temp), "%02" PRIx8 " ", data);
|
||||
strncat(output, temp, sizeof(output) - strlen(output) - 1);
|
||||
}
|
||||
strncat(output, "-> ", sizeof(output) - strlen(output) - 1);
|
||||
|
||||
/* process command */
|
||||
ptr = &read_buffer[0];
|
||||
jtagspi_cmd(bank, write_buffer[0], &write_buffer[1], num_write - 1, ptr, -num_read);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
for ( ; num_read > 0; num_read--) {
|
||||
snprintf(temp, sizeof(temp), "%02" PRIx8 " ", *ptr++);
|
||||
strncat(output, temp, sizeof(output) - strlen(output) - 1);
|
||||
}
|
||||
command_print(CMD, "%s", output);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jtagspi_handle_always_4byte)
|
||||
{
|
||||
struct flash_bank *bank;
|
||||
struct jtagspi_flash_bank *jtagspi_info;
|
||||
int retval;
|
||||
|
||||
LOG_DEBUG("%s", __func__);
|
||||
|
||||
if ((CMD_ARGC != 1) && (CMD_ARGC != 2))
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
jtagspi_info = bank->driver_priv;
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
command_print(CMD, jtagspi_info->always_4byte ? "on" : "off");
|
||||
else
|
||||
COMMAND_PARSE_BOOL(CMD_ARGV[1], jtagspi_info->always_4byte, "on", "off");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtagspi_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
struct flash_sector *sectors;
|
||||
const struct flash_device *p;
|
||||
uint8_t in_buf[3];
|
||||
uint32_t id, sectorsize;
|
||||
|
||||
if (info->probed)
|
||||
if (bank->sectors) {
|
||||
free(bank->sectors);
|
||||
bank->sectors = NULL;
|
||||
}
|
||||
info->probed = false;
|
||||
|
||||
if (!bank->target->tap) {
|
||||
|
@ -178,38 +398,46 @@ static int jtagspi_probe(struct flash_bank *bank)
|
|||
}
|
||||
info->tap = bank->target->tap;
|
||||
|
||||
jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, in_buf, -24);
|
||||
jtagspi_cmd(bank, SPIFLASH_READ_ID, NULL, 0, in_buf, -3);
|
||||
/* the table in spi.c has the manufacturer byte (first) as the lsb */
|
||||
id = le_to_h_u24(in_buf);
|
||||
|
||||
info->dev = NULL;
|
||||
for (const struct flash_device *p = flash_devices; p->name ; p++)
|
||||
memset(&info->dev, 0, sizeof(info->dev));
|
||||
for (p = flash_devices; p->name ; p++)
|
||||
if (p->device_id == id) {
|
||||
info->dev = p;
|
||||
memcpy(&info->dev, p, sizeof(info->dev));
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(info->dev)) {
|
||||
LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id);
|
||||
if (!(p->name)) {
|
||||
LOG_ERROR("Unknown flash device (ID 0x%06" PRIx32 ")", id & 0xFFFFFF);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
|
||||
info->dev->name, info->dev->device_id);
|
||||
LOG_INFO("Found flash device \'%s\' (ID 0x%06" PRIx32 ")",
|
||||
info->dev.name, info->dev.device_id & 0xFFFFFF);
|
||||
|
||||
/* Set correct size value */
|
||||
bank->size = info->dev->size_in_bytes;
|
||||
if (bank->size <= (1UL << 16))
|
||||
LOG_WARNING("device needs 2-byte addresses - not implemented");
|
||||
if (bank->size > (1UL << 24))
|
||||
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
|
||||
bank->size = info->dev.size_in_bytes;
|
||||
|
||||
/* calculate address length in bytes */
|
||||
if (bank->size <= (1UL << 8))
|
||||
info->addr_len = 1;
|
||||
else if (bank->size <= (1UL << 16))
|
||||
info->addr_len = 2;
|
||||
else if (bank->size <= (1UL << 24))
|
||||
info->addr_len = 3;
|
||||
else {
|
||||
info->addr_len = 4;
|
||||
LOG_WARNING("4-byte addresses needed, might need extra command to enable");
|
||||
}
|
||||
|
||||
/* if no sectors, treat whole bank as single sector */
|
||||
sectorsize = info->dev->sectorsize ?
|
||||
info->dev->sectorsize : info->dev->size_in_bytes;
|
||||
sectorsize = info->dev.sectorsize ?
|
||||
info->dev.sectorsize : info->dev.size_in_bytes;
|
||||
|
||||
/* create and fill sectors array */
|
||||
bank->num_sectors = info->dev->size_in_bytes / sectorsize;
|
||||
bank->num_sectors = info->dev.size_in_bytes / sectorsize;
|
||||
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
|
||||
if (!sectors) {
|
||||
LOG_ERROR("not enough memory");
|
||||
|
@ -228,27 +456,35 @@ static int jtagspi_probe(struct flash_bank *bank)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtagspi_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
|
||||
if (info->probed)
|
||||
return ERROR_OK;
|
||||
return jtagspi_probe(bank);
|
||||
}
|
||||
|
||||
static int jtagspi_read_status(struct flash_bank *bank, uint32_t *status)
|
||||
{
|
||||
uint8_t buf;
|
||||
int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, &buf, -8);
|
||||
int err = jtagspi_cmd(bank, SPIFLASH_READ_STATUS, NULL, 0, &buf, -1);
|
||||
if (err == ERROR_OK) {
|
||||
*status = buf;
|
||||
/* LOG_DEBUG("status=0x%08" PRIx32, *status); */
|
||||
LOG_DEBUG("status=0x%02" PRIx32, *status);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
|
||||
{
|
||||
uint32_t status;
|
||||
int64_t t0 = timeval_ms();
|
||||
int64_t dt;
|
||||
|
||||
do {
|
||||
dt = timeval_ms() - t0;
|
||||
|
||||
uint32_t status = (uint32_t)-1;
|
||||
int retval = jtagspi_read_status(bank, &status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
@ -266,16 +502,15 @@ static int jtagspi_wait(struct flash_bank *bank, int timeout_ms)
|
|||
|
||||
static int jtagspi_write_enable(struct flash_bank *bank)
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, NULL, 0);
|
||||
jtagspi_cmd(bank, SPIFLASH_WRITE_ENABLE, NULL, 0, NULL, 0);
|
||||
|
||||
uint32_t status = (uint32_t)-1;
|
||||
int retval = jtagspi_read_status(bank, &status);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((status & SPIFLASH_WE_BIT) == 0) {
|
||||
LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status);
|
||||
LOG_ERROR("Cannot enable write to flash. Status=0x%02" PRIx32, status);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
|
@ -287,28 +522,51 @@ static int jtagspi_bulk_erase(struct flash_bank *bank)
|
|||
int retval;
|
||||
int64_t t0 = timeval_ms();
|
||||
|
||||
if (info->dev->chip_erase_cmd == 0x00)
|
||||
if (info->dev.chip_erase_cmd == 0x00)
|
||||
return ERROR_FLASH_OPER_UNSUPPORTED;
|
||||
|
||||
retval = jtagspi_write_enable(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
jtagspi_cmd(bank, info->dev->chip_erase_cmd, NULL, NULL, 0);
|
||||
|
||||
jtagspi_cmd(bank, info->dev.chip_erase_cmd, NULL, 0, NULL, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = jtagspi_wait(bank, bank->num_sectors * JTAGSPI_MAX_TIMEOUT);
|
||||
LOG_INFO("took %" PRId64 " ms", timeval_ms() - t0);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static uint8_t *fill_addr(uint32_t addr, unsigned int addr_len, uint8_t *buffer)
|
||||
{
|
||||
for (buffer += addr_len; addr_len > 0; --addr_len) {
|
||||
*--buffer = addr;
|
||||
addr >>= 8;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int jtagspi_sector_erase(struct flash_bank *bank, unsigned int sector)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
int retval;
|
||||
uint8_t addr[sizeof(uint32_t)];
|
||||
int64_t t0 = timeval_ms();
|
||||
|
||||
retval = jtagspi_write_enable(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
jtagspi_cmd(bank, info->dev->erase_cmd, &bank->sectors[sector].offset, NULL, 0);
|
||||
|
||||
/* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */
|
||||
unsigned int addr_len = info->always_4byte ? 4 : info->addr_len;
|
||||
|
||||
retval = jtagspi_cmd(bank, info->dev.erase_cmd, fill_addr(bank->sectors[sector].offset, addr_len, addr),
|
||||
addr_len, NULL, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT);
|
||||
LOG_INFO("sector %u took %" PRId64 " ms", sector, timeval_ms() - t0);
|
||||
return retval;
|
||||
|
@ -339,8 +597,9 @@ static int jtagspi_erase(struct flash_bank *bank, unsigned int first,
|
|||
}
|
||||
}
|
||||
|
||||
if (first == 0 && last == (bank->num_sectors - 1)
|
||||
&& info->dev->chip_erase_cmd != info->dev->erase_cmd) {
|
||||
if (first == 0 && last == (bank->num_sectors - 1) &&
|
||||
info->dev.chip_erase_cmd != 0x00 &&
|
||||
info->dev.chip_erase_cmd != info->dev.erase_cmd) {
|
||||
LOG_DEBUG("Trying bulk erase.");
|
||||
retval = jtagspi_bulk_erase(bank);
|
||||
if (retval == ERROR_OK)
|
||||
|
@ -349,7 +608,7 @@ static int jtagspi_erase(struct flash_bank *bank, unsigned int first,
|
|||
LOG_WARNING("Bulk flash erase failed. Falling back to sector erase.");
|
||||
}
|
||||
|
||||
if (info->dev->erase_cmd == 0x00)
|
||||
if (info->dev.erase_cmd == 0x00)
|
||||
return ERROR_FLASH_OPER_UNSUPPORTED;
|
||||
|
||||
for (unsigned int sector = first; sector <= last; sector++) {
|
||||
|
@ -374,49 +633,93 @@ static int jtagspi_protect(struct flash_bank *bank, int set, unsigned int first,
|
|||
static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
uint32_t pagesize, currsize;
|
||||
uint8_t addr[sizeof(uint32_t)];
|
||||
int retval;
|
||||
|
||||
if (!(info->probed)) {
|
||||
LOG_ERROR("Flash bank not yet probed.");
|
||||
LOG_ERROR("Flash bank not probed.");
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
jtagspi_cmd(bank, SPIFLASH_READ, &offset, buffer, -count*8);
|
||||
/* if no sectorsize, use reasonable default */
|
||||
pagesize = info->dev.sectorsize ? info->dev.sectorsize : info->dev.pagesize;
|
||||
if (pagesize == 0)
|
||||
pagesize = (info->dev.size_in_bytes <= SPIFLASH_DEF_PAGESIZE) ?
|
||||
info->dev.size_in_bytes : SPIFLASH_DEF_PAGESIZE;
|
||||
|
||||
/* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */
|
||||
unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len;
|
||||
|
||||
while (count > 0) {
|
||||
/* length up to end of current page */
|
||||
currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset;
|
||||
/* but no more than remaining size */
|
||||
currsize = (count < currsize) ? count : currsize;
|
||||
|
||||
retval = jtagspi_cmd(bank, info->dev.read_cmd, fill_addr(offset, addr_len, addr),
|
||||
addr_len, buffer, -currsize);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("page read error");
|
||||
return retval;
|
||||
}
|
||||
LOG_DEBUG("read page at 0x%08" PRIx32, offset);
|
||||
offset += currsize;
|
||||
buffer += currsize;
|
||||
count -= currsize;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtagspi_page_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
uint8_t addr[sizeof(uint32_t)];
|
||||
int retval;
|
||||
|
||||
retval = jtagspi_write_enable(bank);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
jtagspi_cmd(bank, SPIFLASH_PAGE_PROGRAM, &offset, (uint8_t *) buffer, count*8);
|
||||
|
||||
/* ATXP032/064/128 use always 4-byte addresses except for 0x03 read */
|
||||
unsigned int addr_len = ((info->dev.read_cmd != 0x03) && info->always_4byte) ? 4 : info->addr_len;
|
||||
|
||||
retval = jtagspi_cmd(bank, info->dev.pprog_cmd, fill_addr(offset, addr_len, addr),
|
||||
addr_len, (uint8_t *) buffer, count);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
return jtagspi_wait(bank, JTAGSPI_MAX_TIMEOUT);
|
||||
}
|
||||
|
||||
static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct jtagspi_flash_bank *info = bank->driver_priv;
|
||||
uint32_t pagesize, currsize;
|
||||
int retval;
|
||||
uint32_t n, pagesize;
|
||||
|
||||
if (!(info->probed)) {
|
||||
LOG_ERROR("Flash bank not yet probed.");
|
||||
LOG_ERROR("Flash bank not probed.");
|
||||
return ERROR_FLASH_BANK_NOT_PROBED;
|
||||
}
|
||||
|
||||
/* if no write pagesize, use reasonable default */
|
||||
pagesize = info->dev->pagesize ? info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
|
||||
pagesize = info->dev.pagesize ? info->dev.pagesize : SPIFLASH_DEF_PAGESIZE;
|
||||
|
||||
for (n = 0; n < count; n += pagesize) {
|
||||
retval = jtagspi_page_write(bank, buffer + n, offset + n,
|
||||
MIN(count - n, pagesize));
|
||||
while (count > 0) {
|
||||
/* length up to end of current page */
|
||||
currsize = ((offset + pagesize) & ~(pagesize - 1)) - offset;
|
||||
/* but no more than remaining size */
|
||||
currsize = (count < currsize) ? count : currsize;
|
||||
|
||||
retval = jtagspi_page_write(bank, buffer, offset, currsize);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("page write error");
|
||||
return retval;
|
||||
}
|
||||
LOG_DEBUG("wrote page at 0x%08" PRIx32, offset + n);
|
||||
LOG_DEBUG("wrote page at 0x%08" PRIx32, offset);
|
||||
offset += currsize;
|
||||
buffer += currsize;
|
||||
count -= currsize;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -430,22 +733,72 @@ static int jtagspi_info(struct flash_bank *bank, struct command_invocation *cmd)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
command_print_sameline(cmd, "\nSPIFI flash information:\n"
|
||||
" Device \'%s\' (ID 0x%08" PRIx32 ")\n",
|
||||
info->dev->name, info->dev->device_id);
|
||||
command_print_sameline(cmd, "flash \'%s\', device id = 0x%06" PRIx32
|
||||
", flash size = %" PRIu32 " %sbytes\n(page size = %" PRIu32
|
||||
", read = 0x%02" PRIx8 ", qread = 0x%02" PRIx8
|
||||
", pprog = 0x%02" PRIx8 ", mass_erase = 0x%02" PRIx8
|
||||
", sector size = %" PRIu32 " %sbytes, sector_erase = 0x%02" PRIx8 ")",
|
||||
info->dev.name, info->dev.device_id & 0xFFFFFF,
|
||||
bank->size / 4096 ? bank->size / 1024 : bank->size,
|
||||
bank->size / 4096 ? "k" : "", info->dev.pagesize,
|
||||
info->dev.read_cmd, info->dev.qread_cmd,
|
||||
info->dev.pprog_cmd, info->dev.chip_erase_cmd,
|
||||
info->dev.sectorsize / 4096 ?
|
||||
info->dev.sectorsize / 1024 : info->dev.sectorsize,
|
||||
info->dev.sectorsize / 4096 ? "k" : "",
|
||||
info->dev.erase_cmd);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration jtagspi_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "set",
|
||||
.handler = jtagspi_handle_set,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id name chip_size page_size read_cmd unused pprg_cmd "
|
||||
"[ mass_erase_cmd ] [ sector_size sector_erase_cmd ]",
|
||||
.help = "Set device parameters if not autodetected.",
|
||||
},
|
||||
{
|
||||
.name = "cmd",
|
||||
.handler = jtagspi_handle_cmd,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id num_resp cmd_byte ...",
|
||||
.help = "Send low-level command cmd_byte and following bytes, read num_bytes.",
|
||||
},
|
||||
{
|
||||
.name = "always_4byte",
|
||||
.handler = jtagspi_handle_always_4byte,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "bank_id [ on | off ]",
|
||||
.help = "Use always 4-byte address except for basic 0x03.",
|
||||
},
|
||||
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration jtagspi_command_handlers[] = {
|
||||
{
|
||||
.name = "jtagspi",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "jtagspi command group",
|
||||
.usage = "",
|
||||
.chain = jtagspi_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct flash_driver jtagspi_flash = {
|
||||
.name = "jtagspi",
|
||||
.commands = jtagspi_command_handlers,
|
||||
.flash_bank_command = jtagspi_flash_bank_command,
|
||||
.erase = jtagspi_erase,
|
||||
.protect = jtagspi_protect,
|
||||
.write = jtagspi_write,
|
||||
.read = jtagspi_read,
|
||||
.probe = jtagspi_probe,
|
||||
.auto_probe = jtagspi_probe,
|
||||
.auto_probe = jtagspi_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.info = jtagspi_info,
|
||||
.free_driver_priv = default_flash_free_driver_priv,
|
||||
|
|
|
@ -1015,7 +1015,7 @@ static const struct command_registration psoc6_exec_command_handlers[] = {
|
|||
.name = "reset_halt",
|
||||
.handler = psoc6_handle_reset_halt,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = NULL,
|
||||
.usage = "",
|
||||
.help = "Tries to simulate broken Vector Catch",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
|
|
|
@ -441,7 +441,6 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
|
|||
|
||||
struct flash_driver rp2040_flash = {
|
||||
.name = "rp2040_flash",
|
||||
.commands = NULL,
|
||||
.flash_bank_command = rp2040_flash_bank_command,
|
||||
.erase = rp2040_flash_erase,
|
||||
.write = rp2040_flash_write,
|
||||
|
|
|
@ -640,6 +640,9 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id)
|
|||
case CORTEX_M4_PARTNO: /* STM32F3x devices */
|
||||
device_id_register = 0xE0042000;
|
||||
break;
|
||||
case CORTEX_M23_PARTNO: /* GD32E23x devices */
|
||||
device_id_register = 0x40015800;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Cannot identify target as a stm32x");
|
||||
return ERROR_FAIL;
|
||||
|
@ -674,6 +677,9 @@ static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_i
|
|||
case CORTEX_M4_PARTNO: /* STM32F3x devices */
|
||||
flash_size_reg = 0x1FFFF7CC;
|
||||
break;
|
||||
case CORTEX_M23_PARTNO: /* GD32E23x devices */
|
||||
flash_size_reg = 0x1FFFF7E0;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Cannot identify target as a stm32x");
|
||||
return ERROR_FAIL;
|
||||
|
@ -756,8 +762,8 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
page_size = 1024;
|
||||
stm32x_info->ppage_size = 4;
|
||||
max_flash_size_in_kb = 128;
|
||||
/* GigaDevice GD32F1x0 & GD32F3x0 series devices share DEV_ID
|
||||
with STM32F101/2/3 medium-density line,
|
||||
/* GigaDevice GD32F1x0 & GD32F3x0 & GD32E23x series devices
|
||||
share DEV_ID with STM32F101/2/3 medium-density line,
|
||||
however they use a REV_ID different from any STM32 device.
|
||||
The main difference is another offset of user option bits
|
||||
(like WDG_SW, nRST_STOP, nRST_STDBY) in option byte register
|
||||
|
@ -774,6 +780,11 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
break;
|
||||
case 0x1909: /* gd32e23x */
|
||||
stm32x_info->user_data_offset = 16;
|
||||
stm32x_info->option_offset = 6;
|
||||
max_flash_size_in_kb = 64;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x412: /* stm32f1x low-density */
|
||||
|
@ -984,6 +995,10 @@ static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *c
|
|||
device_str = "GD32F3x0";
|
||||
break;
|
||||
|
||||
case 0x1909: /* gd32e23x */
|
||||
device_str = "GD32E23x";
|
||||
break;
|
||||
|
||||
case 0x2000:
|
||||
rev_str = "B";
|
||||
break;
|
||||
|
@ -1530,7 +1545,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static const struct command_registration stm32x_exec_command_handlers[] = {
|
||||
static const struct command_registration stm32f1x_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "lock",
|
||||
.handler = stm32x_handle_lock_command,
|
||||
|
@ -1578,20 +1593,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
|
|||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration stm32x_command_handlers[] = {
|
||||
static const struct command_registration stm32f1x_command_handlers[] = {
|
||||
{
|
||||
.name = "stm32f1x",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "stm32f1x flash command group",
|
||||
.usage = "",
|
||||
.chain = stm32x_exec_command_handlers,
|
||||
.chain = stm32f1x_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct flash_driver stm32f1x_flash = {
|
||||
.name = "stm32f1x",
|
||||
.commands = stm32x_command_handlers,
|
||||
.commands = stm32f1x_command_handlers,
|
||||
.flash_bank_command = stm32x_flash_bank_command,
|
||||
.erase = stm32x_erase,
|
||||
.protect = stm32x_protect,
|
||||
|
|
|
@ -1747,7 +1747,7 @@ COMMAND_HANDLER(stm32x_handle_otp_command)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static const struct command_registration stm32x_exec_command_handlers[] = {
|
||||
static const struct command_registration stm32f2x_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "lock",
|
||||
.handler = stm32x_handle_lock_command,
|
||||
|
@ -1800,20 +1800,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
|
|||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration stm32x_command_handlers[] = {
|
||||
static const struct command_registration stm32f2x_command_handlers[] = {
|
||||
{
|
||||
.name = "stm32f2x",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "stm32f2x flash command group",
|
||||
.usage = "",
|
||||
.chain = stm32x_exec_command_handlers,
|
||||
.chain = stm32f2x_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct flash_driver stm32f2x_flash = {
|
||||
.name = "stm32f2x",
|
||||
.commands = stm32x_command_handlers,
|
||||
.commands = stm32f2x_command_handlers,
|
||||
.flash_bank_command = stm32x_flash_bank_command,
|
||||
.erase = stm32x_erase,
|
||||
.protect = stm32x_protect,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "imp.h"
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/armv7m.h>
|
||||
#include <target/cortex_m.h>
|
||||
|
||||
|
||||
/* Erase time can be as high as 1000ms, 10x this and it's toast... */
|
||||
|
@ -100,6 +100,11 @@
|
|||
#define FLASH_REG_BASE_B0 0x52002000
|
||||
#define FLASH_REG_BASE_B1 0x52002100
|
||||
|
||||
/* Supported device IDs */
|
||||
#define DEVID_STM32H74_H75XX 0x450
|
||||
#define DEVID_STM32H7A_H7BXX 0x480
|
||||
#define DEVID_STM32H72_H73XX 0x483
|
||||
|
||||
struct stm32h7x_rev {
|
||||
uint16_t rev;
|
||||
const char *str;
|
||||
|
@ -139,24 +144,24 @@ enum stm32h7x_opt_rdp {
|
|||
OPT_RDP_L2 = 0xcc
|
||||
};
|
||||
|
||||
static const struct stm32h7x_rev stm32_450_revs[] = {
|
||||
static const struct stm32h7x_rev stm32h74_h75xx_revs[] = {
|
||||
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" },
|
||||
};
|
||||
|
||||
static const struct stm32h7x_rev stm32_480_revs[] = {
|
||||
static const struct stm32h7x_rev stm32h7a_h7bxx_revs[] = {
|
||||
{ 0x1000, "A"},
|
||||
};
|
||||
|
||||
static const struct stm32h7x_rev stm32_483_revs[] = {
|
||||
static const struct stm32h7x_rev stm32h72_h73xx_revs[] = {
|
||||
{ 0x1000, "A" }, { 0x1001, "Z" },
|
||||
};
|
||||
|
||||
static uint32_t stm32x_compute_flash_cr_450_483(uint32_t cmd, int snb)
|
||||
static uint32_t stm32h74_h75xx_compute_flash_cr(uint32_t cmd, int snb)
|
||||
{
|
||||
return cmd | (snb << 8);
|
||||
}
|
||||
|
||||
static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb)
|
||||
static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb)
|
||||
{
|
||||
/* save FW and START bits, to be right shifted by 2 bits later */
|
||||
const uint32_t tmp = cmd & (FLASH_FW | FLASH_START);
|
||||
|
@ -169,9 +174,9 @@ static uint32_t stm32x_compute_flash_cr_480(uint32_t cmd, int snb)
|
|||
|
||||
static const struct stm32h7x_part_info stm32h7x_parts[] = {
|
||||
{
|
||||
.id = 0x450,
|
||||
.revs = stm32_450_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32_450_revs),
|
||||
.id = DEVID_STM32H74_H75XX,
|
||||
.revs = stm32h74_h75xx_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32h74_h75xx_revs),
|
||||
.device_str = "STM32H74x/75x",
|
||||
.page_size_kb = 128,
|
||||
.block_size = 32,
|
||||
|
@ -181,12 +186,12 @@ static const struct stm32h7x_part_info stm32h7x_parts[] = {
|
|||
.fsize_addr = 0x1FF1E880,
|
||||
.wps_group_size = 1,
|
||||
.wps_mask = 0xFF,
|
||||
.compute_flash_cr = stm32x_compute_flash_cr_450_483,
|
||||
.compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
|
||||
},
|
||||
{
|
||||
.id = 0x480,
|
||||
.revs = stm32_480_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32_480_revs),
|
||||
.id = DEVID_STM32H7A_H7BXX,
|
||||
.revs = stm32h7a_h7bxx_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32h7a_h7bxx_revs),
|
||||
.device_str = "STM32H7Ax/7Bx",
|
||||
.page_size_kb = 8,
|
||||
.block_size = 16,
|
||||
|
@ -196,12 +201,12 @@ static const struct stm32h7x_part_info stm32h7x_parts[] = {
|
|||
.fsize_addr = 0x08FFF80C,
|
||||
.wps_group_size = 4,
|
||||
.wps_mask = 0xFFFFFFFF,
|
||||
.compute_flash_cr = stm32x_compute_flash_cr_480,
|
||||
.compute_flash_cr = stm32h7a_h7bxx_compute_flash_cr,
|
||||
},
|
||||
{
|
||||
.id = 0x483,
|
||||
.revs = stm32_483_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32_483_revs),
|
||||
.id = DEVID_STM32H72_H73XX,
|
||||
.revs = stm32h72_h73xx_revs,
|
||||
.num_revs = ARRAY_SIZE(stm32h72_h73xx_revs),
|
||||
.device_str = "STM32H72x/73x",
|
||||
.page_size_kb = 128,
|
||||
.block_size = 32,
|
||||
|
@ -211,7 +216,7 @@ static const struct stm32h7x_part_info stm32h7x_parts[] = {
|
|||
.fsize_addr = 0x1FF1E880,
|
||||
.wps_group_size = 1,
|
||||
.wps_mask = 0xFF,
|
||||
.compute_flash_cr = stm32x_compute_flash_cr_450_483,
|
||||
.compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -754,6 +759,7 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
|
|||
static int stm32x_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
|
||||
uint16_t flash_size_in_kb;
|
||||
uint32_t device_id;
|
||||
|
@ -792,15 +798,19 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base);
|
||||
|
||||
/* get flash size from target */
|
||||
/* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */
|
||||
retval = ERROR_FAIL;
|
||||
if (device_id == DEVID_STM32H74_H75XX && cortex_m->core_info->partno == CORTEX_M4_PARTNO)
|
||||
LOG_WARNING("%s cannot read the flash size register", target_name(target));
|
||||
else
|
||||
retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
/* read error when device has invalid value, set max flash size */
|
||||
flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb;
|
||||
LOG_INFO("assuming %" PRIu16 "k flash", flash_size_in_kb);
|
||||
} else
|
||||
LOG_INFO("flash size probed value %" PRIu16, flash_size_in_kb);
|
||||
|
||||
|
||||
|
||||
LOG_INFO("flash size probed value %" PRIu16 "k", flash_size_in_kb);
|
||||
|
||||
/* setup bank size */
|
||||
const uint32_t bank1_base = FLASH_BANK0_ADDRESS;
|
||||
|
@ -808,8 +818,8 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
bool has_dual_bank = stm32x_info->part_info->has_dual_bank;
|
||||
|
||||
switch (device_id) {
|
||||
case 0x450:
|
||||
case 0x480:
|
||||
case DEVID_STM32H74_H75XX:
|
||||
case DEVID_STM32H7A_H7BXX:
|
||||
/* For STM32H74x/75x and STM32H7Ax/Bx
|
||||
* - STM32H7xxxI devices contains dual bank, 1 Mbyte each
|
||||
* - STM32H7xxxG devices contains dual bank, 512 Kbyte each
|
||||
|
@ -822,7 +832,7 @@ static int stm32x_probe(struct flash_bank *bank)
|
|||
/* flash size is 2M or 1M */
|
||||
flash_size_in_kb /= 2;
|
||||
break;
|
||||
case 0x483:
|
||||
case DEVID_STM32H72_H73XX:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("unsupported device");
|
||||
|
@ -1141,7 +1151,7 @@ COMMAND_HANDLER(stm32x_handle_option_write_command)
|
|||
return stm32x_modify_option(bank, reg_offset, value, mask);
|
||||
}
|
||||
|
||||
static const struct command_registration stm32x_exec_command_handlers[] = {
|
||||
static const struct command_registration stm32h7x_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "lock",
|
||||
.handler = stm32x_handle_lock_command,
|
||||
|
@ -1180,20 +1190,20 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
|
|||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration stm32x_command_handlers[] = {
|
||||
static const struct command_registration stm32h7x_command_handlers[] = {
|
||||
{
|
||||
.name = "stm32h7x",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "stm32h7x flash command group",
|
||||
.usage = "",
|
||||
.chain = stm32x_exec_command_handlers,
|
||||
.chain = stm32h7x_exec_command_handlers,
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
const struct flash_driver stm32h7x_flash = {
|
||||
.name = "stm32h7x",
|
||||
.commands = stm32x_command_handlers,
|
||||
.commands = stm32h7x_command_handlers,
|
||||
.flash_bank_command = stm32x_flash_bank_command,
|
||||
.erase = stm32x_erase,
|
||||
.protect = stm32x_protect,
|
||||
|
|
|
@ -425,12 +425,12 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
|
||||
|
||||
uint32_t hp_nb = stm32lx_info->part_info.page_size / 2;
|
||||
uint32_t buffer_size = 16384;
|
||||
uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */
|
||||
struct working_area *write_algorithm;
|
||||
struct working_area *source;
|
||||
uint32_t address = bank->base + offset;
|
||||
|
||||
struct reg_param reg_params[3];
|
||||
struct reg_param reg_params[5];
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
@ -440,6 +440,10 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
};
|
||||
|
||||
/* Make sure we're performing a half-page aligned write. */
|
||||
if (offset % hp_nb) {
|
||||
LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (count % hp_nb) {
|
||||
LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count);
|
||||
return ERROR_FAIL;
|
||||
|
@ -476,6 +480,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
|
||||
LOG_WARNING("no large enough working area available, can't do block memory writes");
|
||||
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
|
||||
} else {
|
||||
/* Make sure we're still asking for an integral number of half-pages */
|
||||
buffer_size -= buffer_size % hp_nb;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,6 +491,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
|
||||
init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
|
||||
|
||||
/* Enable half-page write */
|
||||
retval = stm32lx_enable_write_half_page(bank);
|
||||
|
@ -494,6 +503,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_params[4]);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -524,8 +535,12 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
buf_set_u32(reg_params[0].value, 0, 32, address);
|
||||
/* The source address of the copy (R1) */
|
||||
buf_set_u32(reg_params[1].value, 0, 32, source->address);
|
||||
/* The length of the copy (R2) */
|
||||
buf_set_u32(reg_params[2].value, 0, 32, this_count / 4);
|
||||
/* The number of half pages to copy (R2) */
|
||||
buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb);
|
||||
/* The size in byes of a half page (R3) */
|
||||
buf_set_u32(reg_params[3].value, 0, 32, hp_nb);
|
||||
/* The flash base address (R4) */
|
||||
buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base);
|
||||
|
||||
/* 5: Execute the bunch of code */
|
||||
retval = target_run_algorithm(target, 0, NULL,
|
||||
|
@ -593,6 +608,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
|
|||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_params[4]);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -1285,8 +1285,7 @@ COMMAND_HANDLER(handle_flash_bank_command)
|
|||
|
||||
/* register flash specific commands */
|
||||
if (driver->commands) {
|
||||
int retval = register_commands(CMD_CTX, NULL,
|
||||
driver->commands);
|
||||
int retval = register_commands(CMD_CTX, NULL, driver->commands);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("couldn't register '%s' commands",
|
||||
driver_name);
|
||||
|
|
|
@ -121,3 +121,6 @@ proc stm32l5x args { eval stm32l4x $args }
|
|||
proc stm32u5x args { eval stm32l4x $args }
|
||||
proc stm32wbx args { eval stm32l4x $args }
|
||||
proc stm32wlx args { eval stm32l4x $args }
|
||||
|
||||
# gd32e23x uses the same flash driver as the stm32f1x
|
||||
proc gd32e23x args { eval stm32f1x $args }
|
||||
|
|
|
@ -137,41 +137,6 @@ static void command_log_capture_finish(struct log_capture_state *state)
|
|||
free(state);
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: workaround for memory leak in jimtcl 0.80
|
||||
* Jim API Jim_CreateCommand() converts the command name in a Jim object and
|
||||
* does not free the object. Fixed for jimtcl 0.81 by e4416cf86f0b
|
||||
* Use the internal jimtcl API Jim_CreateCommandObj, not exported by jim.h,
|
||||
* and override the bugged API through preprocessor's macro.
|
||||
* This workaround works only when jimtcl is compiled as OpenOCD submodule.
|
||||
* It's broken on macOS, so it's currently restricted on Linux only.
|
||||
* If jimtcl is linked-in from a precompiled library, either static or dynamic,
|
||||
* the symbol Jim_CreateCommandObj is not exported and the build will use the
|
||||
* bugged API.
|
||||
* To be removed when OpenOCD will switch to jimtcl 0.81
|
||||
*/
|
||||
#if JIM_VERSION == 80 && defined __linux__
|
||||
static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
|
||||
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc);
|
||||
int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
|
||||
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
|
||||
__attribute__((weak, alias("workaround_createcommand")));
|
||||
static int workaround_createcommand(Jim_Interp *interp, const char *cmdName,
|
||||
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
|
||||
{
|
||||
if ((void *)Jim_CreateCommandObj == (void *)workaround_createcommand)
|
||||
return Jim_CreateCommand(interp, cmdName, cmdProc, privData, delProc);
|
||||
|
||||
Jim_Obj *cmd_name = Jim_NewStringObj(interp, cmdName, -1);
|
||||
Jim_IncrRefCount(cmd_name);
|
||||
int retval = Jim_CreateCommandObj(interp, cmd_name, cmdProc, privData, delProc);
|
||||
Jim_DecrRefCount(interp, cmd_name);
|
||||
return retval;
|
||||
}
|
||||
#define Jim_CreateCommand workaround_createcommand
|
||||
#endif /* JIM_VERSION == 80 && defined __linux__*/
|
||||
/* FIXME: end of workaround for memory leak in jimtcl 0.80 */
|
||||
|
||||
static int command_retval_set(Jim_Interp *interp, int retval)
|
||||
{
|
||||
int *return_retval = Jim_GetAssocData(interp, "retval");
|
||||
|
|
|
@ -143,6 +143,23 @@ extern int debug_level;
|
|||
#define LOG_OUTPUT(expr ...) \
|
||||
log_printf(LOG_LVL_OUTPUT, __FILE__, __LINE__, __func__, expr)
|
||||
|
||||
/* Output a log entry that is related to a given target */
|
||||
|
||||
#define LOG_TARGET_DEBUG_IO(target, fmt_str, ...) \
|
||||
LOG_DEBUG_IO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TARGET_DEBUG(target, fmt_str, ...) \
|
||||
LOG_DEBUG("[%s] " fmt_str, target_name(target), ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TARGET_INFO(target, fmt_str, ...) \
|
||||
LOG_INFO("[%s] " fmt_str, target_name(target), ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TARGET_WARNING(target, fmt_str, ...) \
|
||||
LOG_WARNING("[%s] " fmt_str, target_name(target), ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TARGET_ERROR(target, fmt_str, ...) \
|
||||
LOG_ERROR("[%s] " fmt_str, target_name(target), ##__VA_ARGS__)
|
||||
|
||||
/* general failures
|
||||
* error codes < 100
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
noinst_LTLIBRARIES += %D%/libjtag.la
|
||||
|
||||
JTAG_SRCS = %D%/commands.c
|
||||
%C%_libjtag_la_LIBADD =
|
||||
|
||||
if HLADAPTER
|
||||
|
@ -18,20 +17,20 @@ include %D%/drivers/Makefile.am
|
|||
|
||||
%C%_libjtag_la_SOURCES = \
|
||||
%D%/adapter.c \
|
||||
%D%/adapter.h \
|
||||
%D%/commands.c \
|
||||
%D%/core.c \
|
||||
%D%/interface.c \
|
||||
%D%/interfaces.c \
|
||||
%D%/tcl.c \
|
||||
%D%/swim.c \
|
||||
%D%/commands.h \
|
||||
%D%/driver.h \
|
||||
%D%/interface.h \
|
||||
%D%/interfaces.h \
|
||||
%D%/minidriver.h \
|
||||
%D%/jtag.h \
|
||||
%D%/swd.h \
|
||||
%D%/swim.h \
|
||||
%D%/tcl.h \
|
||||
$(JTAG_SRCS)
|
||||
%D%/tcl.h
|
||||
|
||||
STARTUP_TCL_SRCS += %D%/startup.tcl
|
||||
|
|
|
@ -1,41 +1,22 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* Copyright (C) 2007-2010 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2009 SoftPLC Corporation *
|
||||
* http://softplc.com *
|
||||
* dick@softplc.com *
|
||||
* *
|
||||
* Copyright (C) 2009 Zachary T Welch *
|
||||
* zw@superlucidity.net *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>
|
||||
* Copyright (C) 2007-2010 Øyvind Harboe <oyvind.harboe@zylin.com>
|
||||
* Copyright (C) 2009 SoftPLC Corporation, http://softplc.com, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net>
|
||||
* Copyright (C) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "adapter.h"
|
||||
#include "jtag.h"
|
||||
#include "minidriver.h"
|
||||
#include "interface.h"
|
||||
#include "interfaces.h"
|
||||
#include <transport/transport.h>
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
@ -45,6 +26,281 @@
|
|||
struct adapter_driver *adapter_driver;
|
||||
const char * const jtag_only[] = { "jtag", NULL };
|
||||
|
||||
enum adapter_clk_mode {
|
||||
CLOCK_MODE_UNSELECTED = 0,
|
||||
CLOCK_MODE_KHZ,
|
||||
CLOCK_MODE_RCLK
|
||||
};
|
||||
|
||||
/**
|
||||
* Adapter configuration
|
||||
*/
|
||||
static struct {
|
||||
bool adapter_initialized;
|
||||
char *usb_location;
|
||||
char *serial;
|
||||
enum adapter_clk_mode clock_mode;
|
||||
int speed_khz;
|
||||
int rclk_fallback_speed_khz;
|
||||
} adapter_config;
|
||||
|
||||
bool is_adapter_initialized(void)
|
||||
{
|
||||
return adapter_config.adapter_initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do low-level setup like initializing registers, output signals,
|
||||
* and clocking.
|
||||
*/
|
||||
int adapter_init(struct command_context *cmd_ctx)
|
||||
{
|
||||
if (is_adapter_initialized())
|
||||
return ERROR_OK;
|
||||
|
||||
if (!adapter_driver) {
|
||||
/* nothing was previously specified by "adapter driver" command */
|
||||
LOG_ERROR("Debug Adapter has to be specified, "
|
||||
"see \"adapter driver\" command");
|
||||
return ERROR_JTAG_INVALID_INTERFACE;
|
||||
}
|
||||
|
||||
int retval;
|
||||
retval = adapter_driver->init();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
adapter_config.adapter_initialized = true;
|
||||
|
||||
if (!adapter_driver->speed) {
|
||||
LOG_INFO("This adapter doesn't support configurable speed");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (adapter_config.clock_mode == CLOCK_MODE_UNSELECTED) {
|
||||
LOG_ERROR("An adapter speed is not selected in the init script."
|
||||
" Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
int requested_khz = adapter_get_speed_khz();
|
||||
int actual_khz = requested_khz;
|
||||
int speed_var = 0;
|
||||
retval = adapter_get_speed(&speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = adapter_driver->speed(speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = adapter_get_speed_readable(&actual_khz);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_INFO("adapter-specific clock speed value %d", speed_var);
|
||||
else if (actual_khz) {
|
||||
/* Adaptive clocking -- JTAG-specific */
|
||||
if ((adapter_config.clock_mode == CLOCK_MODE_RCLK)
|
||||
|| ((adapter_config.clock_mode == CLOCK_MODE_KHZ) && !requested_khz)) {
|
||||
LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz"
|
||||
, actual_khz);
|
||||
} else
|
||||
LOG_INFO("clock speed %d kHz", actual_khz);
|
||||
} else
|
||||
LOG_INFO("RCLK (adaptive clock speed)");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int adapter_quit(void)
|
||||
{
|
||||
if (is_adapter_initialized() && adapter_driver->quit) {
|
||||
/* close the JTAG interface */
|
||||
int result = adapter_driver->quit();
|
||||
if (result != ERROR_OK)
|
||||
LOG_ERROR("failed: %d", result);
|
||||
}
|
||||
|
||||
free(adapter_config.serial);
|
||||
free(adapter_config.usb_location);
|
||||
|
||||
struct jtag_tap *t = jtag_all_taps();
|
||||
while (t) {
|
||||
struct jtag_tap *n = t->next_tap;
|
||||
jtag_tap_free(t);
|
||||
t = n;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
unsigned int adapter_get_speed_khz(void)
|
||||
{
|
||||
return adapter_config.speed_khz;
|
||||
}
|
||||
|
||||
static int adapter_khz_to_speed(unsigned int khz, int *speed)
|
||||
{
|
||||
LOG_DEBUG("convert khz to adapter specific speed value");
|
||||
adapter_config.speed_khz = khz;
|
||||
if (!is_adapter_initialized())
|
||||
return ERROR_OK;
|
||||
LOG_DEBUG("have adapter set up");
|
||||
if (!adapter_driver->khz) {
|
||||
LOG_ERROR("Translation from khz to adapter speed not implemented");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
int speed_div1;
|
||||
int retval = adapter_driver->khz(adapter_get_speed_khz(), &speed_div1);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
*speed = speed_div1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int adapter_rclk_to_speed(unsigned int fallback_speed_khz, int *speed)
|
||||
{
|
||||
int retval = adapter_khz_to_speed(0, speed);
|
||||
if ((retval != ERROR_OK) && fallback_speed_khz) {
|
||||
LOG_DEBUG("trying fallback speed...");
|
||||
retval = adapter_khz_to_speed(fallback_speed_khz, speed);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int adapter_set_speed(int speed)
|
||||
{
|
||||
/* this command can be called during CONFIG,
|
||||
* in which case adapter isn't initialized */
|
||||
return is_adapter_initialized() ? adapter_driver->speed(speed) : ERROR_OK;
|
||||
}
|
||||
|
||||
int adapter_config_khz(unsigned int khz)
|
||||
{
|
||||
LOG_DEBUG("handle adapter khz");
|
||||
adapter_config.clock_mode = CLOCK_MODE_KHZ;
|
||||
int speed = 0;
|
||||
int retval = adapter_khz_to_speed(khz, &speed);
|
||||
return (retval != ERROR_OK) ? retval : adapter_set_speed(speed);
|
||||
}
|
||||
|
||||
int adapter_config_rclk(unsigned int fallback_speed_khz)
|
||||
{
|
||||
LOG_DEBUG("handle adapter rclk");
|
||||
adapter_config.clock_mode = CLOCK_MODE_RCLK;
|
||||
adapter_config.rclk_fallback_speed_khz = fallback_speed_khz;
|
||||
int speed = 0;
|
||||
int retval = adapter_rclk_to_speed(fallback_speed_khz, &speed);
|
||||
return (retval != ERROR_OK) ? retval : adapter_set_speed(speed);
|
||||
}
|
||||
|
||||
int adapter_get_speed(int *speed)
|
||||
{
|
||||
switch (adapter_config.clock_mode) {
|
||||
case CLOCK_MODE_KHZ:
|
||||
adapter_khz_to_speed(adapter_get_speed_khz(), speed);
|
||||
break;
|
||||
case CLOCK_MODE_RCLK:
|
||||
adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown adapter clock mode");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int adapter_get_speed_readable(int *khz)
|
||||
{
|
||||
int speed_var = 0;
|
||||
int retval = adapter_get_speed(&speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!is_adapter_initialized())
|
||||
return ERROR_OK;
|
||||
if (!adapter_driver->speed_div) {
|
||||
LOG_ERROR("Translation from adapter speed to khz not implemented");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return adapter_driver->speed_div(speed_var, khz);
|
||||
}
|
||||
|
||||
const char *adapter_get_required_serial(void)
|
||||
{
|
||||
return adapter_config.serial;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1 char: bus
|
||||
* 2 * 7 chars: max 7 ports
|
||||
* 1 char: test for overflow
|
||||
* ------
|
||||
* 16 chars
|
||||
*/
|
||||
#define USB_MAX_LOCATION_LENGTH 16
|
||||
|
||||
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
|
||||
static void adapter_usb_set_location(const char *location)
|
||||
{
|
||||
if (strnlen(location, USB_MAX_LOCATION_LENGTH) == USB_MAX_LOCATION_LENGTH)
|
||||
LOG_WARNING("usb location string is too long!!");
|
||||
|
||||
free(adapter_config.usb_location);
|
||||
|
||||
adapter_config.usb_location = strndup(location, USB_MAX_LOCATION_LENGTH);
|
||||
}
|
||||
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
|
||||
|
||||
const char *adapter_usb_get_location(void)
|
||||
{
|
||||
return adapter_config.usb_location;
|
||||
}
|
||||
|
||||
bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len)
|
||||
{
|
||||
size_t path_step, string_length;
|
||||
char *ptr, *loc;
|
||||
bool equal = false;
|
||||
|
||||
if (!adapter_usb_get_location())
|
||||
return equal;
|
||||
|
||||
/* strtok need non const char */
|
||||
loc = strndup(adapter_usb_get_location(), USB_MAX_LOCATION_LENGTH);
|
||||
string_length = strnlen(loc, USB_MAX_LOCATION_LENGTH);
|
||||
|
||||
ptr = strtok(loc, "-");
|
||||
if (!ptr) {
|
||||
LOG_WARNING("no '-' in usb path\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
string_length -= strnlen(ptr, string_length);
|
||||
/* check bus mismatch */
|
||||
if (atoi(ptr) != dev_bus)
|
||||
goto done;
|
||||
|
||||
path_step = 0;
|
||||
while (path_step < path_len) {
|
||||
ptr = strtok(NULL, ".");
|
||||
|
||||
/* no more tokens in path */
|
||||
if (!ptr)
|
||||
break;
|
||||
|
||||
/* path mismatch at some step */
|
||||
if (path_step < path_len && atoi(ptr) != port_path[path_step])
|
||||
break;
|
||||
|
||||
path_step++;
|
||||
string_length -= strnlen(ptr, string_length) + 1;
|
||||
};
|
||||
|
||||
/* walked the full path, all elements match */
|
||||
if (path_step == path_len && !string_length)
|
||||
equal = true;
|
||||
|
||||
done:
|
||||
free(loc);
|
||||
return equal;
|
||||
}
|
||||
|
||||
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
{
|
||||
struct jim_getopt_info goi;
|
||||
|
@ -114,8 +370,7 @@ COMMAND_HANDLER(handle_adapter_driver_command)
|
|||
continue;
|
||||
|
||||
if (adapter_drivers[i]->commands) {
|
||||
retval = register_commands(CMD_CTX, NULL,
|
||||
adapter_drivers[i]->commands);
|
||||
retval = register_commands(CMD_CTX, NULL, adapter_drivers[i]->commands);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
@ -389,13 +644,13 @@ COMMAND_HANDLER(handle_adapter_speed_command)
|
|||
unsigned khz = 0;
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz);
|
||||
|
||||
retval = jtag_config_khz(khz);
|
||||
retval = adapter_config_khz(khz);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int cur_speed = jtag_get_speed_khz();
|
||||
retval = jtag_get_speed_readable(&cur_speed);
|
||||
int cur_speed = adapter_get_speed_khz();
|
||||
retval = adapter_get_speed_readable(&cur_speed);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
@ -407,6 +662,16 @@ COMMAND_HANDLER(handle_adapter_speed_command)
|
|||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_serial_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
free(adapter_config.serial);
|
||||
adapter_config.serial = strdup(CMD_ARGV[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_adapter_reset_de_assert)
|
||||
{
|
||||
enum values {
|
||||
|
@ -497,9 +762,9 @@ COMMAND_HANDLER(handle_adapter_reset_de_assert)
|
|||
COMMAND_HANDLER(handle_usb_location_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
jtag_usb_set_location(CMD_ARGV[0]);
|
||||
adapter_usb_set_location(CMD_ARGV[0]);
|
||||
|
||||
command_print(CMD, "adapter usb location: %s", jtag_usb_get_location());
|
||||
command_print(CMD, "adapter usb location: %s", adapter_usb_get_location());
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -554,6 +819,13 @@ static const struct command_registration adapter_command_handlers[] = {
|
|||
"With or without argument, display current setting.",
|
||||
.usage = "[khz]",
|
||||
},
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = handle_adapter_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Set the serial number of the adapter",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "list",
|
||||
.handler = handle_adapter_list_command,
|
||||
|
@ -635,7 +907,7 @@ static const struct command_registration interface_command_handlers[] = {
|
|||
* @todo Remove internal assumptions that all debug adapters use JTAG for
|
||||
* transport. Various types and data structures are not named generically.
|
||||
*/
|
||||
int interface_register_commands(struct command_context *ctx)
|
||||
int adapter_register_commands(struct command_context *ctx)
|
||||
{
|
||||
return register_commands(ctx, NULL, interface_command_handlers);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>
|
||||
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENOCD_JTAG_ADAPTER_H
|
||||
#define OPENOCD_JTAG_ADAPTER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct command_context;
|
||||
|
||||
/** Register the adapter's commands */
|
||||
int adapter_register_commands(struct command_context *ctx);
|
||||
|
||||
/** Initialize debug adapter upon startup. */
|
||||
int adapter_init(struct command_context *cmd_ctx);
|
||||
|
||||
/** Shutdown the debug adapter upon program exit. */
|
||||
int adapter_quit(void);
|
||||
|
||||
/** @returns true if adapter has been initialized */
|
||||
bool is_adapter_initialized(void);
|
||||
|
||||
/** @returns USB location string set with command 'adapter usb location' */
|
||||
const char *adapter_usb_get_location(void);
|
||||
|
||||
/** @returns true if USB location string is "<dev_bus>-<port_path[0]>[.<port_path[1]>[...]]" */
|
||||
bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len);
|
||||
|
||||
/** @returns The current adapter speed setting. */
|
||||
int adapter_get_speed(int *speed);
|
||||
|
||||
/**
|
||||
* Given a @a speed setting, use the interface @c speed_div callback to
|
||||
* adjust the setting.
|
||||
* @param speed The speed setting to convert back to readable kHz.
|
||||
* @returns ERROR_OK if the interface has not been initialized or on success;
|
||||
* otherwise, the error code produced by the @c speed_div callback.
|
||||
*/
|
||||
int adapter_get_speed_readable(int *speed);
|
||||
|
||||
/** Attempt to configure the adapter for the specified kHz. */
|
||||
int adapter_config_khz(unsigned int khz);
|
||||
|
||||
/**
|
||||
* Attempt to enable RTCK/RCLK. If that fails, fallback to the
|
||||
* specified frequency.
|
||||
*/
|
||||
int adapter_config_rclk(unsigned int fallback_speed_khz);
|
||||
|
||||
/** Retrieves the clock speed of the adapter in kHz. */
|
||||
unsigned int adapter_get_speed_khz(void);
|
||||
|
||||
/** Retrieves the serial number set with command 'adapter serial' */
|
||||
const char *adapter_get_required_serial(void);
|
||||
|
||||
#endif /* OPENOCD_JTAG_ADAPTER_H */
|
|
@ -20,6 +20,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <transport/transport.h>
|
||||
|
@ -269,7 +270,7 @@ COMMAND_HANDLER(aice_handle_aice_info_command)
|
|||
LOG_DEBUG("aice_handle_aice_info_command");
|
||||
|
||||
command_print(CMD, "Description: %s", param.device_desc);
|
||||
command_print(CMD, "Serial number: %s", param.serial);
|
||||
command_print(CMD, "Serial number: %s", adapter_get_required_serial());
|
||||
if (strncmp(aice_port->name, "aice_pipe", 9) == 0)
|
||||
command_print(CMD, "Adapter: %s", param.adapter_name);
|
||||
|
||||
|
@ -308,18 +309,6 @@ COMMAND_HANDLER(aice_handle_aice_desc_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(aice_handle_aice_serial_command)
|
||||
{
|
||||
LOG_DEBUG("aice_handle_aice_serial_command");
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
param.serial = strdup(CMD_ARGV[0]);
|
||||
else
|
||||
LOG_ERROR("expected exactly one argument to aice serial <serial-number>");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(aice_handle_aice_vid_pid_command)
|
||||
{
|
||||
LOG_DEBUG("aice_handle_aice_vid_pid_command");
|
||||
|
@ -438,13 +427,6 @@ static const struct command_registration aice_subcommand_handlers[] = {
|
|||
.help = "set the aice device description",
|
||||
.usage = "[description string]",
|
||||
},
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = &aice_handle_aice_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the AICE device",
|
||||
.usage = "[serial string]",
|
||||
},
|
||||
{
|
||||
.name = "vid_pid",
|
||||
.handler = &aice_handle_aice_vid_pid_command,
|
||||
|
|
|
@ -107,8 +107,6 @@ struct aice_port_param_s {
|
|||
/** */
|
||||
const char *device_desc;
|
||||
/** */
|
||||
const char *serial;
|
||||
/** */
|
||||
uint16_t vid;
|
||||
/** */
|
||||
uint16_t pid;
|
||||
|
|
|
@ -284,8 +284,7 @@ static int jim_aice_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
|||
}
|
||||
|
||||
/* */
|
||||
static const struct command_registration
|
||||
aice_transport_jtag_subcommand_handlers[] = {
|
||||
static const struct command_registration aice_transport_jtag_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "init",
|
||||
.mode = COMMAND_ANY,
|
||||
|
@ -387,8 +386,7 @@ static const struct command_registration aice_transport_command_handlers[] = {
|
|||
/* */
|
||||
static int aice_transport_register_commands(struct command_context *cmd_ctx)
|
||||
{
|
||||
return register_commands(cmd_ctx, NULL,
|
||||
aice_transport_command_handlers);
|
||||
return register_commands(cmd_ctx, NULL, aice_transport_command_handlers);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
|
|
@ -2086,7 +2086,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
|||
const uint16_t pids[] = { param->pid, 0 };
|
||||
struct libusb_device_handle *devh;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &devh, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(vids, pids, &devh, NULL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
|
||||
|
@ -2110,7 +2110,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
|
|||
/* reopen jlink after usb_reset
|
||||
* on win32 this may take a second or two to re-enumerate */
|
||||
int retval;
|
||||
while ((retval = jtag_libusb_open(vids, pids, NULL, &devh, NULL)) != ERROR_OK) {
|
||||
while ((retval = jtag_libusb_open(vids, pids, &devh, NULL)) != ERROR_OK) {
|
||||
usleep(1000);
|
||||
timeout--;
|
||||
if (!timeout)
|
||||
|
|
211
src/jtag/core.c
211
src/jtag/core.c
|
@ -30,6 +30,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "adapter.h"
|
||||
#include "jtag.h"
|
||||
#include "swd.h"
|
||||
#include "interface.h"
|
||||
|
@ -123,15 +124,6 @@ struct jtag_event_callback {
|
|||
/* callbacks to inform high-level handlers about JTAG state changes */
|
||||
static struct jtag_event_callback *jtag_event_callbacks;
|
||||
|
||||
/* speed in kHz*/
|
||||
static int speed_khz;
|
||||
/* speed to fallback to when RCLK is requested but not supported */
|
||||
static int rclk_fallback_speed_khz;
|
||||
static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode;
|
||||
|
||||
/* FIXME: change name to this variable, it is not anymore JTAG only */
|
||||
static struct adapter_driver *jtag;
|
||||
|
||||
extern struct adapter_driver *adapter_driver;
|
||||
|
||||
void jtag_set_flush_queue_sleep(int ms)
|
||||
|
@ -505,7 +497,7 @@ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state)
|
|||
{
|
||||
int retval;
|
||||
|
||||
if (!(jtag->jtag_ops->supported & DEBUG_CAP_TMS_SEQ))
|
||||
if (!(adapter_driver->jtag_ops->supported & DEBUG_CAP_TMS_SEQ))
|
||||
return ERROR_JTAG_NOT_IMPLEMENTED;
|
||||
|
||||
jtag_checks();
|
||||
|
@ -627,7 +619,7 @@ static int adapter_system_reset(int req_srst)
|
|||
|
||||
/* Maybe change SRST signal state */
|
||||
if (jtag_srst != req_srst) {
|
||||
retval = jtag->reset(0, req_srst);
|
||||
retval = adapter_driver->reset(0, req_srst);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("SRST error");
|
||||
return ERROR_FAIL;
|
||||
|
@ -764,7 +756,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
|||
int new_srst = 0;
|
||||
int new_trst = 0;
|
||||
|
||||
if (!jtag->reset) {
|
||||
if (!adapter_driver->reset) {
|
||||
legacy_jtag_add_reset(req_tlr_or_trst, req_srst);
|
||||
return;
|
||||
}
|
||||
|
@ -813,7 +805,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
|
|||
/* guarantee jtag queue empty before changing reset status */
|
||||
jtag_execute_queue();
|
||||
|
||||
retval = jtag->reset(new_trst, new_srst);
|
||||
retval = adapter_driver->reset(new_trst, new_srst);
|
||||
if (retval != ERROR_OK) {
|
||||
jtag_set_error(retval);
|
||||
LOG_ERROR("TRST/SRST error");
|
||||
|
@ -933,7 +925,7 @@ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *ma
|
|||
|
||||
int default_interface_jtag_execute_queue(void)
|
||||
{
|
||||
if (!jtag) {
|
||||
if (!is_adapter_initialized()) {
|
||||
LOG_ERROR("No JTAG interface configured yet. "
|
||||
"Issue 'init' command in startup scripts "
|
||||
"before communicating with targets.");
|
||||
|
@ -949,11 +941,11 @@ int default_interface_jtag_execute_queue(void)
|
|||
* The fix can be applied immediately after next release (v0.11.0 ?)
|
||||
*/
|
||||
LOG_ERROR("JTAG API jtag_execute_queue() called on non JTAG interface");
|
||||
if (!jtag->jtag_ops || !jtag->jtag_ops->execute_queue)
|
||||
if (!adapter_driver->jtag_ops || !adapter_driver->jtag_ops->execute_queue)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int result = jtag->jtag_ops->execute_queue();
|
||||
int result = adapter_driver->jtag_ops->execute_queue();
|
||||
|
||||
struct jtag_command *cmd = jtag_command_queue;
|
||||
while (debug_level >= LOG_LVL_DEBUG_IO && cmd) {
|
||||
|
@ -1502,65 +1494,6 @@ void jtag_tap_free(struct jtag_tap *tap)
|
|||
free(tap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do low-level setup like initializing registers, output signals,
|
||||
* and clocking.
|
||||
*/
|
||||
int adapter_init(struct command_context *cmd_ctx)
|
||||
{
|
||||
if (jtag)
|
||||
return ERROR_OK;
|
||||
|
||||
if (!adapter_driver) {
|
||||
/* nothing was previously specified by "adapter driver" command */
|
||||
LOG_ERROR("Debug Adapter has to be specified, "
|
||||
"see \"adapter driver\" command");
|
||||
return ERROR_JTAG_INVALID_INTERFACE;
|
||||
}
|
||||
|
||||
int retval;
|
||||
retval = adapter_driver->init();
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
jtag = adapter_driver;
|
||||
|
||||
if (!jtag->speed) {
|
||||
LOG_INFO("This adapter doesn't support configurable speed");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (clock_mode == CLOCK_MODE_UNSELECTED) {
|
||||
LOG_ERROR("An adapter speed is not selected in the init script."
|
||||
" Insert a call to \"adapter speed\" or \"jtag_rclk\" to proceed.");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
int requested_khz = jtag_get_speed_khz();
|
||||
int actual_khz = requested_khz;
|
||||
int jtag_speed_var = 0;
|
||||
retval = jtag_get_speed(&jtag_speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = jtag->speed(jtag_speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = jtag_get_speed_readable(&actual_khz);
|
||||
if (retval != ERROR_OK)
|
||||
LOG_INFO("adapter-specific clock speed value %d", jtag_speed_var);
|
||||
else if (actual_khz) {
|
||||
/* Adaptive clocking -- JTAG-specific */
|
||||
if ((clock_mode == CLOCK_MODE_RCLK)
|
||||
|| ((clock_mode == CLOCK_MODE_KHZ) && !requested_khz)) {
|
||||
LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz"
|
||||
, actual_khz);
|
||||
} else
|
||||
LOG_INFO("clock speed %d kHz", actual_khz);
|
||||
} else
|
||||
LOG_INFO("RCLK (adaptive clock speed)");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int jtag_init_inner(struct command_context *cmd_ctx)
|
||||
{
|
||||
struct jtag_tap *tap;
|
||||
|
@ -1641,25 +1574,6 @@ int jtag_init_inner(struct command_context *cmd_ctx)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int adapter_quit(void)
|
||||
{
|
||||
if (jtag && jtag->quit) {
|
||||
/* close the JTAG interface */
|
||||
int result = jtag->quit();
|
||||
if (result != ERROR_OK)
|
||||
LOG_ERROR("failed: %d", result);
|
||||
}
|
||||
|
||||
struct jtag_tap *t = jtag_all_taps();
|
||||
while (t) {
|
||||
struct jtag_tap *n = t->next_tap;
|
||||
jtag_tap_free(t);
|
||||
t = n;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int swd_init_reset(struct command_context *cmd_ctx)
|
||||
{
|
||||
int retval, retval1;
|
||||
|
@ -1767,97 +1681,6 @@ int jtag_init(struct command_context *cmd_ctx)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
unsigned jtag_get_speed_khz(void)
|
||||
{
|
||||
return speed_khz;
|
||||
}
|
||||
|
||||
static int adapter_khz_to_speed(unsigned khz, int *speed)
|
||||
{
|
||||
LOG_DEBUG("convert khz to interface specific speed value");
|
||||
speed_khz = khz;
|
||||
if (!jtag)
|
||||
return ERROR_OK;
|
||||
LOG_DEBUG("have interface set up");
|
||||
if (!jtag->khz) {
|
||||
LOG_ERROR("Translation from khz to jtag_speed not implemented");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
int speed_div1;
|
||||
int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
*speed = speed_div1;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int *speed)
|
||||
{
|
||||
int retval = adapter_khz_to_speed(0, speed);
|
||||
if ((retval != ERROR_OK) && fallback_speed_khz) {
|
||||
LOG_DEBUG("trying fallback speed...");
|
||||
retval = adapter_khz_to_speed(fallback_speed_khz, speed);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int jtag_set_speed(int speed)
|
||||
{
|
||||
/* this command can be called during CONFIG,
|
||||
* in which case jtag isn't initialized */
|
||||
return jtag ? jtag->speed(speed) : ERROR_OK;
|
||||
}
|
||||
|
||||
int jtag_config_khz(unsigned khz)
|
||||
{
|
||||
LOG_DEBUG("handle jtag khz");
|
||||
clock_mode = CLOCK_MODE_KHZ;
|
||||
int speed = 0;
|
||||
int retval = adapter_khz_to_speed(khz, &speed);
|
||||
return (retval != ERROR_OK) ? retval : jtag_set_speed(speed);
|
||||
}
|
||||
|
||||
int jtag_config_rclk(unsigned fallback_speed_khz)
|
||||
{
|
||||
LOG_DEBUG("handle jtag rclk");
|
||||
clock_mode = CLOCK_MODE_RCLK;
|
||||
rclk_fallback_speed_khz = fallback_speed_khz;
|
||||
int speed = 0;
|
||||
int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed);
|
||||
return (retval != ERROR_OK) ? retval : jtag_set_speed(speed);
|
||||
}
|
||||
|
||||
int jtag_get_speed(int *speed)
|
||||
{
|
||||
switch (clock_mode) {
|
||||
case CLOCK_MODE_KHZ:
|
||||
adapter_khz_to_speed(jtag_get_speed_khz(), speed);
|
||||
break;
|
||||
case CLOCK_MODE_RCLK:
|
||||
jtag_rclk_to_speed(rclk_fallback_speed_khz, speed);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("BUG: unknown jtag clock mode");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int jtag_get_speed_readable(int *khz)
|
||||
{
|
||||
int jtag_speed_var = 0;
|
||||
int retval = jtag_get_speed(&jtag_speed_var);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!jtag)
|
||||
return ERROR_OK;
|
||||
if (!jtag->speed_div) {
|
||||
LOG_ERROR("Translation from jtag_speed to khz not implemented");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return jtag->speed_div(jtag_speed_var, khz);
|
||||
}
|
||||
|
||||
void jtag_set_verify(bool enable)
|
||||
{
|
||||
jtag_verify = enable;
|
||||
|
@ -1880,14 +1703,14 @@ bool jtag_will_verify_capture_ir(void)
|
|||
|
||||
int jtag_power_dropout(int *dropout)
|
||||
{
|
||||
if (!jtag) {
|
||||
if (!is_adapter_initialized()) {
|
||||
/* TODO: as the jtag interface is not valid all
|
||||
* we can do at the moment is exit OpenOCD */
|
||||
LOG_ERROR("No Valid JTAG Interface Configured.");
|
||||
exit(-1);
|
||||
}
|
||||
if (jtag->power_dropout)
|
||||
return jtag->power_dropout(dropout);
|
||||
if (adapter_driver->power_dropout)
|
||||
return adapter_driver->power_dropout(dropout);
|
||||
|
||||
*dropout = 0; /* by default we can't detect power dropout */
|
||||
return ERROR_OK;
|
||||
|
@ -1895,8 +1718,8 @@ int jtag_power_dropout(int *dropout)
|
|||
|
||||
int jtag_srst_asserted(int *srst_asserted)
|
||||
{
|
||||
if (jtag->srst_asserted)
|
||||
return jtag->srst_asserted(srst_asserted);
|
||||
if (adapter_driver->srst_asserted)
|
||||
return adapter_driver->srst_asserted(srst_asserted);
|
||||
|
||||
*srst_asserted = 0; /* by default we can't detect srst asserted */
|
||||
return ERROR_OK;
|
||||
|
@ -2089,8 +1912,8 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
|||
uint32_t port_size, unsigned int *trace_freq,
|
||||
unsigned int traceclkin_freq, uint16_t *prescaler)
|
||||
{
|
||||
if (jtag->config_trace) {
|
||||
return jtag->config_trace(enabled, pin_protocol, port_size, trace_freq,
|
||||
if (adapter_driver->config_trace) {
|
||||
return adapter_driver->config_trace(enabled, pin_protocol, port_size, trace_freq,
|
||||
traceclkin_freq, prescaler);
|
||||
} else if (enabled) {
|
||||
LOG_ERROR("The selected interface does not support tracing");
|
||||
|
@ -2102,8 +1925,8 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol,
|
|||
|
||||
int adapter_poll_trace(uint8_t *buf, size_t *size)
|
||||
{
|
||||
if (jtag->poll_trace)
|
||||
return jtag->poll_trace(buf, size);
|
||||
if (adapter_driver->poll_trace)
|
||||
return adapter_driver->poll_trace(buf, size);
|
||||
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Dominic Rath *
|
||||
* Dominic.Rath@gmx.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_JTAG_DRIVER_H
|
||||
#define OPENOCD_JTAG_DRIVER_H
|
||||
|
||||
struct command_context;
|
||||
|
||||
int interface_register_commands(struct command_context *ctx);
|
||||
|
||||
#endif /* OPENOCD_JTAG_DRIVER_H */
|
|
@ -19,7 +19,6 @@ DRIVERFILES =
|
|||
|
||||
# Standard Driver: common files
|
||||
DRIVERFILES += %D%/driver.c
|
||||
DRIVERFILES += %D%/jtag_usb_common.c
|
||||
|
||||
if USE_LIBUSB1
|
||||
DRIVERFILES += %D%/libusb_helper.c
|
||||
|
@ -187,7 +186,6 @@ endif
|
|||
DRIVERHEADERS = \
|
||||
%D%/bitbang.h \
|
||||
%D%/bitq.h \
|
||||
%D%/jtag_usb_common.h \
|
||||
%D%/libftdi_helper.h \
|
||||
%D%/libusb_helper.h \
|
||||
%D%/cmsis_dap.h \
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
|
@ -198,7 +199,7 @@ static void amt_jtagaccel_state_move(void)
|
|||
aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
|
||||
AMT_AW(aw_scan_tms_5);
|
||||
int jtag_speed = 0;
|
||||
int retval = jtag_get_speed(&jtag_speed);
|
||||
int retval = adapter_get_speed(&jtag_speed);
|
||||
assert(retval == ERROR_OK);
|
||||
if (jtag_speed > 3 || rtck_enabled)
|
||||
amt_wait_scan_busy();
|
||||
|
@ -254,7 +255,7 @@ static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffe
|
|||
uint8_t aw_tms_scan;
|
||||
uint8_t tms_scan[2];
|
||||
int jtag_speed_var;
|
||||
int retval = jtag_get_speed(&jtag_speed_var);
|
||||
int retval = adapter_get_speed(&jtag_speed_var);
|
||||
assert(retval == ERROR_OK);
|
||||
|
||||
if (ir_scan)
|
||||
|
|
|
@ -688,7 +688,7 @@ static struct armjtagew *armjtagew_usb_open(void)
|
|||
const uint16_t pids[] = { USB_PID, 0 };
|
||||
struct libusb_device_handle *dev;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
struct armjtagew *result = malloc(sizeof(struct armjtagew));
|
||||
|
|
|
@ -198,7 +198,7 @@ static int bcm2835gpio_speed(int speed)
|
|||
|
||||
static int is_gpio_valid(int gpio)
|
||||
{
|
||||
return gpio >= 0 && gpio <= 53;
|
||||
return gpio >= 0 && gpio <= 31;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(bcm2835gpio_handle_jtag_gpionums)
|
||||
|
|
|
@ -434,10 +434,26 @@ static int bitbang_swd_switch_seq(enum swd_special_seq seq)
|
|||
LOG_DEBUG("JTAG-to-SWD");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len);
|
||||
break;
|
||||
case JTAG_TO_DORMANT:
|
||||
LOG_DEBUG("JTAG-to-DORMANT");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len);
|
||||
break;
|
||||
case SWD_TO_JTAG:
|
||||
LOG_DEBUG("SWD-to-JTAG");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len);
|
||||
break;
|
||||
case SWD_TO_DORMANT:
|
||||
LOG_DEBUG("SWD-to-DORMANT");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len);
|
||||
break;
|
||||
case DORMANT_TO_SWD:
|
||||
LOG_DEBUG("DORMANT-to-SWD");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len);
|
||||
break;
|
||||
case DORMANT_TO_JTAG:
|
||||
LOG_DEBUG("DORMANT-to-JTAG");
|
||||
bitbang_swd_exchange(false, (uint8_t *)swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Sequence %d not supported", seq);
|
||||
return ERROR_FAIL;
|
||||
|
@ -465,7 +481,7 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
|
|||
for (;;) {
|
||||
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
|
||||
|
||||
cmd |= SWD_CMD_START | (1 << 7);
|
||||
cmd |= SWD_CMD_START | SWD_CMD_PARK;
|
||||
bitbang_swd_exchange(false, &cmd, 0, 8);
|
||||
|
||||
bitbang_interface->swdio_drive(false);
|
||||
|
@ -476,17 +492,22 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
|
|||
uint32_t data = buf_get_u32(trn_ack_data_parity_trn, 1 + 3, 32);
|
||||
int parity = buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 32, 1);
|
||||
|
||||
LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
|
||||
LOG_DEBUG("%s %s read reg %X = %08"PRIx32,
|
||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
||||
cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||
cmd & SWD_CMD_RNW ? "read" : "write",
|
||||
(cmd & SWD_CMD_A32) >> 1,
|
||||
data);
|
||||
|
||||
switch (ack) {
|
||||
case SWD_ACK_OK:
|
||||
if (ack == SWD_ACK_WAIT) {
|
||||
swd_clear_sticky_errors();
|
||||
continue;
|
||||
} else if (ack != SWD_ACK_OK) {
|
||||
queued_retval = swd_ack_to_error_code(ack);
|
||||
return;
|
||||
}
|
||||
|
||||
if (parity != parity_u32(data)) {
|
||||
LOG_DEBUG("Wrong parity detected");
|
||||
LOG_ERROR("Wrong parity detected");
|
||||
queued_retval = ERROR_FAIL;
|
||||
return;
|
||||
}
|
||||
|
@ -495,19 +516,6 @@ static void bitbang_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay
|
|||
if (cmd & SWD_CMD_APNDP)
|
||||
bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);
|
||||
return;
|
||||
case SWD_ACK_WAIT:
|
||||
LOG_DEBUG("SWD_ACK_WAIT");
|
||||
swd_clear_sticky_errors();
|
||||
break;
|
||||
case SWD_ACK_FAULT:
|
||||
LOG_DEBUG("SWD_ACK_FAULT");
|
||||
queued_retval = ack;
|
||||
return;
|
||||
default:
|
||||
LOG_DEBUG("No valid acknowledge: ack=%d", ack);
|
||||
queued_retval = ack;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -521,12 +529,15 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
|
|||
return;
|
||||
}
|
||||
|
||||
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
||||
bool check_ack = swd_cmd_returns_ack(cmd);
|
||||
|
||||
for (;;) {
|
||||
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
|
||||
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32, value);
|
||||
buf_set_u32(trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(value));
|
||||
|
||||
cmd |= SWD_CMD_START | (1 << 7);
|
||||
cmd |= SWD_CMD_START | SWD_CMD_PARK;
|
||||
bitbang_swd_exchange(false, &cmd, 0, 8);
|
||||
|
||||
bitbang_interface->swdio_drive(false);
|
||||
|
@ -535,31 +546,27 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
|
|||
bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1);
|
||||
|
||||
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
|
||||
LOG_DEBUG("%s %s %s reg %X = %08"PRIx32,
|
||||
|
||||
LOG_DEBUG("%s%s %s write reg %X = %08"PRIx32,
|
||||
check_ack ? "" : "ack ignored ",
|
||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
||||
cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||
cmd & SWD_CMD_RNW ? "read" : "write",
|
||||
(cmd & SWD_CMD_A32) >> 1,
|
||||
buf_get_u32(trn_ack_data_parity_trn, 1 + 3 + 1, 32));
|
||||
|
||||
switch (ack) {
|
||||
case SWD_ACK_OK:
|
||||
if (check_ack) {
|
||||
if (ack == SWD_ACK_WAIT) {
|
||||
swd_clear_sticky_errors();
|
||||
continue;
|
||||
} else if (ack != SWD_ACK_OK) {
|
||||
queued_retval = swd_ack_to_error_code(ack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd & SWD_CMD_APNDP)
|
||||
bitbang_swd_exchange(true, NULL, 0, ap_delay_clk);
|
||||
return;
|
||||
case SWD_ACK_WAIT:
|
||||
LOG_DEBUG("SWD_ACK_WAIT");
|
||||
swd_clear_sticky_errors();
|
||||
break;
|
||||
case SWD_ACK_FAULT:
|
||||
LOG_DEBUG("SWD_ACK_FAULT");
|
||||
queued_retval = ack;
|
||||
return;
|
||||
default:
|
||||
LOG_DEBUG("No valid acknowledge: ack=%d", ack);
|
||||
queued_retval = ack;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <transport/transport.h>
|
||||
#include "helper/replacements.h"
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
|
@ -75,7 +76,6 @@ static const struct cmsis_dap_backend *const cmsis_dap_backends[] = {
|
|||
/* vid = pid = 0 marks the end of the list */
|
||||
static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 };
|
||||
static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 };
|
||||
static char *cmsis_dap_serial;
|
||||
static int cmsis_dap_backend = -1;
|
||||
static bool swd_mode;
|
||||
|
||||
|
@ -288,13 +288,13 @@ static int cmsis_dap_open(void)
|
|||
if (cmsis_dap_backend >= 0) {
|
||||
/* Use forced backend */
|
||||
backend = cmsis_dap_backends[cmsis_dap_backend];
|
||||
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) != ERROR_OK)
|
||||
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) != ERROR_OK)
|
||||
backend = NULL;
|
||||
} else {
|
||||
/* Try all backends */
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(cmsis_dap_backends); i++) {
|
||||
backend = cmsis_dap_backends[i];
|
||||
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, cmsis_dap_serial) == ERROR_OK)
|
||||
if (backend->open(dap, cmsis_dap_vid, cmsis_dap_pid, adapter_get_required_serial()) == ERROR_OK)
|
||||
break;
|
||||
else
|
||||
backend = NULL;
|
||||
|
@ -324,8 +324,6 @@ static void cmsis_dap_close(struct cmsis_dap *dap)
|
|||
free(cmsis_dap_handle->packet_buffer);
|
||||
free(cmsis_dap_handle);
|
||||
cmsis_dap_handle = NULL;
|
||||
free(cmsis_dap_serial);
|
||||
cmsis_dap_serial = NULL;
|
||||
|
||||
for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
|
||||
free(pending_fifo[i].transfers);
|
||||
|
@ -1133,6 +1131,11 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
|
|||
s = swd_seq_dormant_to_swd;
|
||||
s_len = swd_seq_dormant_to_swd_len;
|
||||
break;
|
||||
case DORMANT_TO_JTAG:
|
||||
LOG_DEBUG("DORMANT-to-JTAG");
|
||||
s = swd_seq_dormant_to_jtag;
|
||||
s_len = swd_seq_dormant_to_jtag_len;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Sequence %d not supported", seq);
|
||||
return ERROR_FAIL;
|
||||
|
@ -1144,7 +1147,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq)
|
|||
|
||||
/* Atmel EDBG needs renew clock setting after SWJ_Sequence
|
||||
* otherwise default frequency is used */
|
||||
return cmsis_dap_cmd_dap_swj_clock(jtag_get_speed_khz());
|
||||
return cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz());
|
||||
}
|
||||
|
||||
static int cmsis_dap_swd_open(void)
|
||||
|
@ -1261,7 +1264,7 @@ static int cmsis_dap_init(void)
|
|||
|
||||
/* Now try to connect to the target
|
||||
* TODO: This is all SWD only @ present */
|
||||
retval = cmsis_dap_cmd_dap_swj_clock(jtag_get_speed_khz());
|
||||
retval = cmsis_dap_cmd_dap_swj_clock(adapter_get_speed_khz());
|
||||
if (retval != ERROR_OK)
|
||||
goto init_err;
|
||||
|
||||
|
@ -2050,16 +2053,6 @@ COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(cmsis_dap_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
cmsis_dap_serial = strdup(CMD_ARGV[0]);
|
||||
else
|
||||
LOG_ERROR("expected exactly one argument to cmsis_dap_serial <serial-number>");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(cmsis_dap_handle_backend_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
|
@ -2116,13 +2109,6 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
|
|||
.help = "the vendor ID and product ID of the CMSIS-DAP device",
|
||||
.usage = "(vid pid)*",
|
||||
},
|
||||
{
|
||||
.name = "cmsis_dap_serial",
|
||||
.handler = &cmsis_dap_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the adapter",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "cmsis_dap_backend",
|
||||
.handler = &cmsis_dap_handle_backend_command,
|
||||
|
|
|
@ -24,7 +24,7 @@ struct cmsis_dap {
|
|||
|
||||
struct cmsis_dap_backend {
|
||||
const char *name;
|
||||
int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial);
|
||||
int (*open)(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial);
|
||||
void (*close)(struct cmsis_dap *dap);
|
||||
int (*read)(struct cmsis_dap *dap, int timeout_ms);
|
||||
int (*write)(struct cmsis_dap *dap, int len, int timeout_ms);
|
||||
|
|
|
@ -55,7 +55,7 @@ static int cmsis_dap_usb_interface = -1;
|
|||
static void cmsis_dap_usb_close(struct cmsis_dap *dap);
|
||||
static int cmsis_dap_usb_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
|
||||
|
||||
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
|
||||
static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial)
|
||||
{
|
||||
int err;
|
||||
struct libusb_context *ctx;
|
||||
|
|
|
@ -48,7 +48,7 @@ struct cmsis_dap_backend_data {
|
|||
static void cmsis_dap_hid_close(struct cmsis_dap *dap);
|
||||
static int cmsis_dap_hid_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
|
||||
|
||||
static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], char *serial)
|
||||
static int cmsis_dap_hid_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t pids[], const char *serial)
|
||||
{
|
||||
hid_device *dev = NULL;
|
||||
int i;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
|
||||
/* project specific includes */
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <helper/time_support.h>
|
||||
|
@ -68,7 +69,6 @@
|
|||
|
||||
#define FT232R_BUF_SIZE_EXTRA 4096
|
||||
|
||||
static char *ft232r_serial_desc;
|
||||
static uint16_t ft232r_vid = 0x0403; /* FTDI */
|
||||
static uint16_t ft232r_pid = 0x6001; /* FT232R */
|
||||
static struct libusb_device_handle *adapter;
|
||||
|
@ -257,7 +257,8 @@ static int ft232r_init(void)
|
|||
{
|
||||
uint16_t avids[] = {ft232r_vid, 0};
|
||||
uint16_t apids[] = {ft232r_pid, 0};
|
||||
if (jtag_libusb_open(avids, apids, ft232r_serial_desc, &adapter, NULL)) {
|
||||
if (jtag_libusb_open(avids, apids, &adapter, NULL)) {
|
||||
const char *ft232r_serial_desc = adapter_get_required_serial();
|
||||
LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n",
|
||||
ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
@ -395,16 +396,6 @@ static int ft232r_bit_name_to_number(const char *name)
|
|||
return -1;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ft232r_handle_serial_desc_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
ft232r_serial_desc = strdup(CMD_ARGV[0]);
|
||||
else
|
||||
LOG_ERROR("require exactly one argument to "
|
||||
"ft232r_serial_desc <serial>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ft232r_handle_vid_pid_command)
|
||||
{
|
||||
if (CMD_ARGC > 2) {
|
||||
|
@ -561,13 +552,6 @@ COMMAND_HANDLER(ft232r_handle_restore_serial_command)
|
|||
}
|
||||
|
||||
static const struct command_registration ft232r_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "serial_desc",
|
||||
.handler = ft232r_handle_serial_desc_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "USB serial descriptor of the adapter",
|
||||
.usage = "serial string",
|
||||
},
|
||||
{
|
||||
.name = "vid_pid",
|
||||
.handler = ft232r_handle_vid_pid_command,
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
#endif
|
||||
|
||||
/* project specific includes */
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <transport/transport.h>
|
||||
|
@ -100,7 +100,6 @@
|
|||
#define SWD_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
|
||||
|
||||
static char *ftdi_device_desc;
|
||||
static char *ftdi_serial;
|
||||
static uint8_t ftdi_channel;
|
||||
static uint8_t ftdi_jtag_mode = JTAG_MODE;
|
||||
|
||||
|
@ -740,7 +739,7 @@ static int ftdi_initialize(void)
|
|||
|
||||
for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
|
||||
mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
|
||||
ftdi_serial, jtag_usb_get_location(), ftdi_channel);
|
||||
adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel);
|
||||
if (mpsse_ctx)
|
||||
break;
|
||||
}
|
||||
|
@ -778,7 +777,7 @@ static int ftdi_initialize(void)
|
|||
|
||||
mpsse_loopback_config(mpsse_ctx, false);
|
||||
|
||||
freq = mpsse_set_frequency(mpsse_ctx, jtag_get_speed_khz() * 1000);
|
||||
freq = mpsse_set_frequency(mpsse_ctx, adapter_get_speed_khz() * 1000);
|
||||
|
||||
return mpsse_flush(mpsse_ctx);
|
||||
}
|
||||
|
@ -796,7 +795,6 @@ static int ftdi_quit(void)
|
|||
}
|
||||
|
||||
free(ftdi_device_desc);
|
||||
free(ftdi_serial);
|
||||
|
||||
free(swd_cmd_queue);
|
||||
|
||||
|
@ -1063,18 +1061,6 @@ COMMAND_HANDLER(ftdi_handle_device_desc_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ftdi_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
free(ftdi_serial);
|
||||
ftdi_serial = strdup(CMD_ARGV[0]);
|
||||
} else {
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ftdi_handle_channel_command)
|
||||
{
|
||||
if (CMD_ARGC == 1)
|
||||
|
@ -1296,13 +1282,6 @@ static const struct command_registration ftdi_subcommand_handlers[] = {
|
|||
.help = "set the USB device description of the FTDI device",
|
||||
.usage = "description_string",
|
||||
},
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = &ftdi_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the FTDI device",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "channel",
|
||||
.handler = &ftdi_handle_channel_command,
|
||||
|
@ -1471,7 +1450,11 @@ static int ftdi_swd_run_queue(void)
|
|||
for (size_t i = 0; i < swd_cmd_queue_length; i++) {
|
||||
int ack = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1, 3);
|
||||
|
||||
LOG_DEBUG_IO("%s %s %s reg %X = %08"PRIx32,
|
||||
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
|
||||
bool check_ack = swd_cmd_returns_ack(swd_cmd_queue[i].cmd);
|
||||
|
||||
LOG_DEBUG_IO("%s%s %s %s reg %X = %08"PRIx32,
|
||||
check_ack ? "" : "ack ignored ",
|
||||
ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
|
||||
swd_cmd_queue[i].cmd & SWD_CMD_APNDP ? "AP" : "DP",
|
||||
swd_cmd_queue[i].cmd & SWD_CMD_RNW ? "read" : "write",
|
||||
|
@ -1479,8 +1462,8 @@ static int ftdi_swd_run_queue(void)
|
|||
buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn,
|
||||
1 + 3 + (swd_cmd_queue[i].cmd & SWD_CMD_RNW ? 0 : 1), 32));
|
||||
|
||||
if (ack != SWD_ACK_OK) {
|
||||
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
|
||||
if (ack != SWD_ACK_OK && check_ack) {
|
||||
queued_retval = swd_ack_to_error_code(ack);
|
||||
goto skip;
|
||||
|
||||
} else if (swd_cmd_queue[i].cmd & SWD_CMD_RNW) {
|
||||
|
@ -1588,11 +1571,31 @@ static int ftdi_swd_switch_seq(enum swd_special_seq seq)
|
|||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE);
|
||||
break;
|
||||
case JTAG_TO_DORMANT:
|
||||
LOG_DEBUG("JTAG-to-DORMANT");
|
||||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_dormant, 0, swd_seq_jtag_to_dormant_len, SWD_MODE);
|
||||
break;
|
||||
case SWD_TO_JTAG:
|
||||
LOG_DEBUG("SWD-to-JTAG");
|
||||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE);
|
||||
break;
|
||||
case SWD_TO_DORMANT:
|
||||
LOG_DEBUG("SWD-to-DORMANT");
|
||||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_dormant, 0, swd_seq_swd_to_dormant_len, SWD_MODE);
|
||||
break;
|
||||
case DORMANT_TO_SWD:
|
||||
LOG_DEBUG("DORMANT-to-SWD");
|
||||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_swd, 0, swd_seq_dormant_to_swd_len, SWD_MODE);
|
||||
break;
|
||||
case DORMANT_TO_JTAG:
|
||||
LOG_DEBUG("DORMANT-to-JTAG");
|
||||
ftdi_swd_swdio_en(true);
|
||||
mpsse_clock_data_out(mpsse_ctx, swd_seq_dormant_to_jtag, 0, swd_seq_dormant_to_jtag_len, SWD_MODE);
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Sequence %d not supported", seq);
|
||||
return ERROR_FAIL;
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include <jtag/interface.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <helper/replacements.h>
|
||||
#include <target/cortex_m.h>
|
||||
|
||||
|
@ -547,7 +547,7 @@ static bool jlink_usb_location_equal(struct jaylink_device *dev)
|
|||
return false;
|
||||
}
|
||||
|
||||
equal = jtag_usb_location_equal(bus, ports, num_ports);
|
||||
equal = adapter_usb_location_equal(bus, ports, num_ports);
|
||||
free(ports);
|
||||
|
||||
return equal;
|
||||
|
@ -573,7 +573,7 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device)
|
|||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
use_usb_location = !!jtag_usb_get_location();
|
||||
use_usb_location = !!adapter_usb_get_location();
|
||||
|
||||
if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) {
|
||||
LOG_ERROR("Multiple devices found, specify the desired device");
|
||||
|
@ -669,6 +669,23 @@ 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)
|
||||
|
@ -811,7 +828,7 @@ static int jlink_init(void)
|
|||
jtag_sleep(3000);
|
||||
jlink_tap_init();
|
||||
|
||||
jlink_speed(jtag_get_speed_khz());
|
||||
jlink_speed(adapter_get_speed_khz());
|
||||
|
||||
if (iface == JAYLINK_TIF_JTAG) {
|
||||
/*
|
||||
|
@ -979,38 +996,11 @@ COMMAND_HANDLER(jlink_usb_command)
|
|||
|
||||
usb_address = tmp;
|
||||
|
||||
use_serial_number = false;
|
||||
use_usb_address = true;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jlink_serial_command)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (CMD_ARGC != 1) {
|
||||
command_print(CMD, "Need exactly one argument for jlink serial");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number);
|
||||
|
||||
if (ret == JAYLINK_ERR) {
|
||||
command_print(CMD, "Invalid serial number: %s", CMD_ARGV[0]);
|
||||
return ERROR_FAIL;
|
||||
} else if (ret != JAYLINK_OK) {
|
||||
command_print(CMD, "jaylink_parse_serial_number() failed: %s",
|
||||
jaylink_strerror(ret));
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
use_serial_number = true;
|
||||
use_usb_address = false;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(jlink_handle_hwstatus_command)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1932,13 +1922,6 @@ static const struct command_registration jlink_subcommand_handlers[] = {
|
|||
.help = "set the USB address of the device that should be used",
|
||||
.usage = "<0-3>"
|
||||
},
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = &jlink_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the device that should be used",
|
||||
.usage = "<serial number>"
|
||||
},
|
||||
{
|
||||
.name = "config",
|
||||
.handler = &jlink_handle_config_command,
|
||||
|
@ -2148,11 +2131,31 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq)
|
|||
s = swd_seq_jtag_to_swd;
|
||||
s_len = swd_seq_jtag_to_swd_len;
|
||||
break;
|
||||
case JTAG_TO_DORMANT:
|
||||
LOG_DEBUG("JTAG-to-DORMANT");
|
||||
s = swd_seq_jtag_to_dormant;
|
||||
s_len = swd_seq_jtag_to_dormant_len;
|
||||
break;
|
||||
case SWD_TO_JTAG:
|
||||
LOG_DEBUG("SWD-to-JTAG");
|
||||
s = swd_seq_swd_to_jtag;
|
||||
s_len = swd_seq_swd_to_jtag_len;
|
||||
break;
|
||||
case SWD_TO_DORMANT:
|
||||
LOG_DEBUG("SWD-to-DORMANT");
|
||||
s = swd_seq_swd_to_dormant;
|
||||
s_len = swd_seq_swd_to_dormant_len;
|
||||
break;
|
||||
case DORMANT_TO_SWD:
|
||||
LOG_DEBUG("DORMANT-to-SWD");
|
||||
s = swd_seq_dormant_to_swd;
|
||||
s_len = swd_seq_dormant_to_swd_len;
|
||||
break;
|
||||
case DORMANT_TO_JTAG:
|
||||
LOG_DEBUG("DORMANT-to-JTAG");
|
||||
s = swd_seq_dormant_to_jtag;
|
||||
s_len = swd_seq_dormant_to_jtag_len;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("Sequence %d not supported", seq);
|
||||
return ERROR_FAIL;
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#include <helper/log.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "jtag_usb_common.h"
|
||||
|
||||
static char *jtag_usb_location;
|
||||
/*
|
||||
* 1 char: bus
|
||||
* 2 * 7 chars: max 7 ports
|
||||
* 1 char: test for overflow
|
||||
* ------
|
||||
* 16 chars
|
||||
*/
|
||||
#define JTAG_USB_MAX_LOCATION_LENGTH 16
|
||||
|
||||
void jtag_usb_set_location(const char *location)
|
||||
{
|
||||
if (strnlen(location, JTAG_USB_MAX_LOCATION_LENGTH) ==
|
||||
JTAG_USB_MAX_LOCATION_LENGTH)
|
||||
LOG_WARNING("usb location string is too long!!\n");
|
||||
|
||||
free(jtag_usb_location);
|
||||
|
||||
jtag_usb_location = strndup(location, JTAG_USB_MAX_LOCATION_LENGTH);
|
||||
}
|
||||
|
||||
const char *jtag_usb_get_location(void)
|
||||
{
|
||||
return jtag_usb_location;
|
||||
}
|
||||
|
||||
bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
|
||||
size_t path_len)
|
||||
{
|
||||
size_t path_step, string_length;
|
||||
char *ptr, *loc;
|
||||
bool equal = false;
|
||||
|
||||
/* strtok need non const char */
|
||||
loc = strndup(jtag_usb_get_location(), JTAG_USB_MAX_LOCATION_LENGTH);
|
||||
string_length = strnlen(loc, JTAG_USB_MAX_LOCATION_LENGTH);
|
||||
|
||||
ptr = strtok(loc, "-");
|
||||
if (!ptr) {
|
||||
LOG_WARNING("no '-' in usb path\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
string_length -= strnlen(ptr, string_length);
|
||||
/* check bus mismatch */
|
||||
if (atoi(ptr) != dev_bus)
|
||||
goto done;
|
||||
|
||||
path_step = 0;
|
||||
while (path_step < path_len) {
|
||||
ptr = strtok(NULL, ".");
|
||||
|
||||
/* no more tokens in path */
|
||||
if (!ptr)
|
||||
break;
|
||||
|
||||
/* path mismatch at some step */
|
||||
if (path_step < path_len && atoi(ptr) != port_path[path_step])
|
||||
break;
|
||||
|
||||
path_step++;
|
||||
string_length -= strnlen(ptr, string_length) + 1;
|
||||
};
|
||||
|
||||
/* walked the full path, all elements match */
|
||||
if (path_step == path_len && !string_length)
|
||||
equal = true;
|
||||
|
||||
done:
|
||||
free(loc);
|
||||
return equal;
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef OPENOCD_JTAG_USB_COMMON_H
|
||||
#define OPENOCD_JTAG_USB_COMMON_H
|
||||
|
||||
#include <helper/replacements.h>
|
||||
#include <helper/types.h>
|
||||
|
||||
void jtag_usb_set_location(const char *location);
|
||||
const char *jtag_usb_get_location(void);
|
||||
bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
|
||||
size_t path_len);
|
||||
|
||||
#endif /* OPENOCD_JTAG_USB_COMMON_H */
|
|
@ -159,7 +159,7 @@ retry_write:
|
|||
/* This means we could not send all data, which is most likely fatal
|
||||
for the jtag_vpi connection (the underlying TCP connection likely not
|
||||
usable anymore) */
|
||||
LOG_ERROR("Could not send all data through jtag_vpi connection.");
|
||||
LOG_ERROR("jtag_vpi: Could not send all data through jtag_vpi connection.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,7 @@ static int jtag_vpi_init(void)
|
|||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
LOG_ERROR("Could not create socket");
|
||||
LOG_ERROR("jtag_vpi: Could not create client socket");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
|
@ -556,13 +556,13 @@ static int jtag_vpi_init(void)
|
|||
serv_addr.sin_addr.s_addr = inet_addr(server_address);
|
||||
|
||||
if (serv_addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
LOG_ERROR("inet_addr error occurred");
|
||||
LOG_ERROR("jtag_vpi: inet_addr error occurred");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||
close(sockfd);
|
||||
LOG_ERROR("Can't connect to %s : %u", server_address, server_port);
|
||||
LOG_ERROR("jtag_vpi: Can't connect to %s : %u", server_address, server_port);
|
||||
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||
}
|
||||
|
||||
|
@ -573,7 +573,7 @@ static int jtag_vpi_init(void)
|
|||
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
|
||||
}
|
||||
|
||||
LOG_INFO("Connection to %s : %u succeed", server_address, server_port);
|
||||
LOG_INFO("jtag_vpi: Connection to %s : %u successful", server_address, server_port);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,6 @@ struct pending_transfer_result {
|
|||
void *buffer;
|
||||
};
|
||||
|
||||
static char *kitprog_serial;
|
||||
static bool kitprog_init_acquire_psoc;
|
||||
|
||||
static int pending_transfer_count, pending_queue_len;
|
||||
|
@ -230,7 +229,6 @@ static int kitprog_quit(void)
|
|||
free(kitprog_handle->packet_buffer);
|
||||
free(kitprog_handle->serial);
|
||||
free(kitprog_handle);
|
||||
free(kitprog_serial);
|
||||
free(pending_transfers);
|
||||
|
||||
return ERROR_OK;
|
||||
|
@ -272,8 +270,7 @@ static int kitprog_usb_open(void)
|
|||
const uint16_t vids[] = { VID, 0 };
|
||||
const uint16_t pids[] = { PID, 0 };
|
||||
|
||||
if (jtag_libusb_open(vids, pids, kitprog_serial,
|
||||
&kitprog_handle->usb_handle, NULL) != ERROR_OK) {
|
||||
if (jtag_libusb_open(vids, pids, &kitprog_handle->usb_handle, NULL) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to open or find the device");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -851,22 +848,6 @@ COMMAND_HANDLER(kitprog_handle_acquire_psoc_command)
|
|||
return retval;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
kitprog_serial = strdup(CMD_ARGV[0]);
|
||||
if (!kitprog_serial) {
|
||||
LOG_ERROR("Failed to allocate memory for the serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("expected exactly one argument to kitprog_serial <serial-number>");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command)
|
||||
{
|
||||
kitprog_init_acquire_psoc = true;
|
||||
|
@ -900,13 +881,6 @@ static const struct command_registration kitprog_command_handlers[] = {
|
|||
.usage = "<cmd>",
|
||||
.chain = kitprog_subcommand_handlers,
|
||||
},
|
||||
{
|
||||
.name = "kitprog_serial",
|
||||
.handler = &kitprog_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the adapter",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "kitprog_init_acquire_psoc",
|
||||
.handler = &kitprog_handle_init_acquire_psoc_command,
|
||||
|
|
|
@ -20,8 +20,11 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <helper/log.h>
|
||||
#include <jtag/drivers/jtag_usb_common.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include "libusb_helper.h"
|
||||
|
||||
/*
|
||||
|
@ -85,7 +88,7 @@ static bool jtag_libusb_location_equal(struct libusb_device *device)
|
|||
}
|
||||
dev_bus = libusb_get_bus_number(device);
|
||||
|
||||
return jtag_usb_location_equal(dev_bus, port_path, path_len);
|
||||
return adapter_usb_location_equal(dev_bus, port_path, path_len);
|
||||
}
|
||||
#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */
|
||||
static bool jtag_libusb_location_equal(struct libusb_device *device)
|
||||
|
@ -154,7 +157,6 @@ static bool jtag_libusb_match_serial(struct libusb_device_handle *device,
|
|||
}
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct libusb_device_handle **out,
|
||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial)
|
||||
{
|
||||
|
@ -162,6 +164,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
|||
int retval = ERROR_FAIL;
|
||||
bool serial_mismatch = false;
|
||||
struct libusb_device_handle *libusb_handle = NULL;
|
||||
const char *serial = adapter_get_required_serial();
|
||||
|
||||
if (libusb_init(&jtag_libusb_context) < 0)
|
||||
return ERROR_FAIL;
|
||||
|
@ -177,7 +180,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
|||
if (!jtag_libusb_match_ids(&dev_desc, vids, pids))
|
||||
continue;
|
||||
|
||||
if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
|
||||
if (adapter_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
|
||||
continue;
|
||||
|
||||
err_code = libusb_open(devs[idx], &libusb_handle);
|
||||
|
|
|
@ -28,7 +28,6 @@ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *d
|
|||
struct libusb_device_descriptor *dev_desc);
|
||||
|
||||
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
|
||||
const char *serial,
|
||||
struct libusb_device_handle **out,
|
||||
adapter_get_alternate_serial_fn adapter_get_alternate_serial);
|
||||
void jtag_libusb_close(struct libusb_device_handle *dev);
|
||||
|
|
|
@ -360,7 +360,11 @@ static int linuxgpiod_init(void)
|
|||
goto out_error;
|
||||
|
||||
if (is_gpio_valid(trst_gpio)) {
|
||||
if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
|
||||
gpiod_trst = helper_get_open_drain_output_line("trst", trst_gpio, 1);
|
||||
else
|
||||
gpiod_trst = helper_get_output_line("trst", trst_gpio, 1);
|
||||
|
||||
if (!gpiod_trst)
|
||||
goto out_error;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
/* project specific includes */
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/hla/hla_layout.h>
|
||||
#include <jtag/hla/hla_transport.h>
|
||||
|
@ -1054,8 +1055,9 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
|
|||
goto error_open;
|
||||
}
|
||||
|
||||
if (param->serial) {
|
||||
size_t len = mbstowcs(NULL, param->serial, 0);
|
||||
const char *serial = adapter_get_required_serial();
|
||||
if (serial) {
|
||||
size_t len = mbstowcs(NULL, serial, 0);
|
||||
|
||||
target_serial = calloc(len + 1, sizeof(wchar_t));
|
||||
if (!target_serial) {
|
||||
|
@ -1063,7 +1065,7 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
|
|||
goto error_open;
|
||||
}
|
||||
|
||||
if (mbstowcs(target_serial, param->serial, len + 1) == (size_t)(-1)) {
|
||||
if (mbstowcs(target_serial, serial, len + 1) == (size_t)(-1)) {
|
||||
LOG_WARNING("unable to convert serial");
|
||||
free(target_serial);
|
||||
target_serial = NULL;
|
||||
|
|
|
@ -706,7 +706,7 @@ struct opendous_jtag *opendous_usb_open(void)
|
|||
struct opendous_jtag *result;
|
||||
|
||||
struct libusb_device_handle *devh;
|
||||
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh, NULL) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
jtag_libusb_set_configuration(devh, 0);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
* Driver for OpenJTAG Project (www.openjtag.org) *
|
||||
* Compatible with libftdi and ftd2xx drivers. *
|
||||
* Compatible with libftdi drivers. *
|
||||
* *
|
||||
* Cypress CY7C65215 support *
|
||||
* Copyright (C) 2015 Vianney le Clément de Saint-Marcq, Essensium NV *
|
||||
|
@ -449,7 +449,7 @@ static int openjtag_init_cy7c65215(void)
|
|||
int ret;
|
||||
|
||||
usbh = NULL;
|
||||
ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL);
|
||||
ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, &usbh, NULL);
|
||||
if (ret != ERROR_OK) {
|
||||
LOG_ERROR("unable to open cy7c65215 device");
|
||||
goto err;
|
||||
|
|
|
@ -374,7 +374,7 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue *queue)
|
|||
static int osbdm_open(struct osbdm *osbdm)
|
||||
{
|
||||
(void)memset(osbdm, 0, sizeof(*osbdm));
|
||||
if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh, NULL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include "bitbang.h"
|
||||
|
||||
|
@ -457,9 +458,9 @@ COMMAND_HANDLER(parport_handle_parport_toggling_time_command)
|
|||
}
|
||||
|
||||
parport_toggling_time_ns = ns;
|
||||
retval = jtag_get_speed(&wait_states);
|
||||
retval = adapter_get_speed(&wait_states);
|
||||
if (retval != ERROR_OK) {
|
||||
/* if jtag_get_speed fails then the clock_mode
|
||||
/* if adapter_get_speed fails then the clock_mode
|
||||
* has not been configured, this happens if parport_toggling_time is
|
||||
* called before the adapter speed is set */
|
||||
LOG_INFO("no parport speed set - defaulting to zero wait states");
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <helper/time_support.h>
|
||||
#include "bitq.h"
|
||||
|
@ -132,7 +133,7 @@ static int presto_read(uint8_t *buf, uint32_t size)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int presto_open_libftdi(char *req_serial)
|
||||
static int presto_open_libftdi(const char *req_serial)
|
||||
{
|
||||
uint8_t presto_data;
|
||||
|
||||
|
@ -195,7 +196,7 @@ static int presto_open_libftdi(char *req_serial)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int presto_open(char *req_serial)
|
||||
static int presto_open(const char *req_serial)
|
||||
{
|
||||
presto->buff_out_pos = 0;
|
||||
presto->buff_in_pos = 0;
|
||||
|
@ -506,43 +507,10 @@ static int presto_jtag_speed(int speed)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *presto_serial;
|
||||
|
||||
COMMAND_HANDLER(presto_handle_serial_command)
|
||||
{
|
||||
if (CMD_ARGC == 1) {
|
||||
free(presto_serial);
|
||||
presto_serial = strdup(CMD_ARGV[0]);
|
||||
} else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration presto_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = presto_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Configure USB serial number of Presto device.",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration presto_command_handlers[] = {
|
||||
{
|
||||
.name = "presto",
|
||||
.mode = COMMAND_ANY,
|
||||
.help = "perform presto management",
|
||||
.chain = presto_subcommand_handlers,
|
||||
.usage = "",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static int presto_jtag_init(void)
|
||||
{
|
||||
const char *presto_serial = adapter_get_required_serial();
|
||||
|
||||
if (presto_open(presto_serial) != ERROR_OK) {
|
||||
presto_close();
|
||||
if (presto_serial)
|
||||
|
@ -562,10 +530,6 @@ static int presto_jtag_quit(void)
|
|||
bitq_cleanup();
|
||||
presto_close();
|
||||
LOG_INFO("PRESTO closed");
|
||||
|
||||
free(presto_serial);
|
||||
presto_serial = NULL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
@ -576,7 +540,6 @@ static struct jtag_interface presto_interface = {
|
|||
struct adapter_driver presto_adapter_driver = {
|
||||
.name = "presto",
|
||||
.transports = jtag_only,
|
||||
.commands = presto_command_handlers,
|
||||
|
||||
.init = presto_jtag_init,
|
||||
.quit = presto_jtag_quit,
|
||||
|
|
|
@ -1461,7 +1461,7 @@ static int rlink_init(void)
|
|||
|
||||
const uint16_t vids[] = { USB_IDVENDOR, 0 };
|
||||
const uint16_t pids[] = { USB_IDPRODUCT, 0 };
|
||||
if (jtag_libusb_open(vids, pids, NULL, &hdev, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(vids, pids, &hdev, NULL) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
struct libusb_device_descriptor descriptor;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,6 +23,7 @@
|
|||
|
||||
/* project specific includes */
|
||||
#include <helper/binarybuffer.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/hla/hla_layout.h>
|
||||
#include <jtag/hla/hla_transport.h>
|
||||
|
@ -681,11 +682,11 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
|
|||
|
||||
for (uint8_t i = 0; param->vid[i] && param->pid[i]; ++i)
|
||||
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", param->transport,
|
||||
param->vid[i], param->pid[i], param->serial ? param->serial : "");
|
||||
param->vid[i], param->pid[i], adapter_get_required_serial() ? adapter_get_required_serial() : "");
|
||||
|
||||
/* TI (Stellaris) ICDI provides its serial number in the USB descriptor;
|
||||
no need to provide a callback here. */
|
||||
jtag_libusb_open(param->vid, param->pid, param->serial, &h->usb_dev, NULL);
|
||||
jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL);
|
||||
|
||||
if (!h->usb_dev) {
|
||||
LOG_ERROR("open failed");
|
||||
|
|
|
@ -210,7 +210,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
|||
bool renumeration = false;
|
||||
int ret;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) {
|
||||
if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) {
|
||||
LOG_INFO("Altera USB-Blaster II (uninitialized) found");
|
||||
LOG_INFO("Loading firmware...");
|
||||
ret = load_usb_blaster_firmware(temp, low);
|
||||
|
@ -224,15 +224,13 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
|
|||
const uint16_t pids_renum[] = { low->ublast_pid, 0 };
|
||||
|
||||
if (renumeration == false) {
|
||||
if (jtag_libusb_open(vids_renum, pids_renum, NULL,
|
||||
&low->libusb_dev, NULL) != ERROR_OK) {
|
||||
if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) {
|
||||
LOG_ERROR("Altera USB-Blaster II not found");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
int retry = 10;
|
||||
while (jtag_libusb_open(vids_renum, pids_renum, NULL,
|
||||
&low->libusb_dev, NULL) != ERROR_OK && retry--) {
|
||||
while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) {
|
||||
usleep(1000000);
|
||||
LOG_INFO("Waiting for reenumerate...");
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ struct ublast_lowlevel {
|
|||
uint16_t ublast_pid;
|
||||
uint16_t ublast_vid_uninit;
|
||||
uint16_t ublast_pid_uninit;
|
||||
char *ublast_device_desc;
|
||||
struct libusb_device_handle *libusb_dev;
|
||||
char *firmware_path;
|
||||
|
||||
|
|
|
@ -119,7 +119,6 @@ struct ublast_info {
|
|||
|
||||
char *lowlevel_name;
|
||||
struct ublast_lowlevel *drv;
|
||||
char *ublast_device_desc;
|
||||
uint16_t ublast_vid, ublast_pid;
|
||||
uint16_t ublast_vid_uninit, ublast_pid_uninit;
|
||||
int flags;
|
||||
|
@ -140,7 +139,7 @@ static struct ublast_info info = {
|
|||
};
|
||||
|
||||
/*
|
||||
* Available lowlevel drivers (FTDI, FTD2xx, ...)
|
||||
* Available lowlevel drivers (FTDI, libusb, ...)
|
||||
*/
|
||||
struct drvs_map {
|
||||
char *name;
|
||||
|
@ -874,7 +873,6 @@ static int ublast_init(void)
|
|||
info.drv->ublast_pid = info.ublast_pid;
|
||||
info.drv->ublast_vid_uninit = info.ublast_vid_uninit;
|
||||
info.drv->ublast_pid_uninit = info.ublast_pid_uninit;
|
||||
info.drv->ublast_device_desc = info.ublast_device_desc;
|
||||
info.drv->firmware_path = info.firmware_path;
|
||||
|
||||
info.flags |= info.drv->flags;
|
||||
|
@ -908,16 +906,6 @@ static int ublast_quit(void)
|
|||
return info.drv->close(info.drv);
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ublast_handle_device_desc_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
info.ublast_device_desc = strdup(CMD_ARGV[0]);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(ublast_handle_vid_pid_command)
|
||||
{
|
||||
if (CMD_ARGC > 4) {
|
||||
|
@ -1031,13 +1019,6 @@ COMMAND_HANDLER(ublast_firmware_command)
|
|||
|
||||
|
||||
static const struct command_registration ublast_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "device_desc",
|
||||
.handler = ublast_handle_device_desc_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the USB device description of the USB-Blaster",
|
||||
.usage = "description-string",
|
||||
},
|
||||
{
|
||||
.name = "vid_pid",
|
||||
.handler = ublast_handle_vid_pid_command,
|
||||
|
|
|
@ -354,7 +354,7 @@ struct usbprog_jtag *usbprog_jtag_open(void)
|
|||
const uint16_t pids[] = { PID, 0 };
|
||||
struct libusb_device_handle *dev;
|
||||
|
||||
if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK)
|
||||
if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK)
|
||||
return NULL;
|
||||
|
||||
struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag));
|
||||
|
|
|
@ -87,7 +87,6 @@ struct versaloon_interface_t versaloon_interface = {
|
|||
.ep_out = VERSALOON_OUTP,
|
||||
.ep_in = VERSALOON_INP,
|
||||
.interface = VERSALOON_IFACE,
|
||||
.serialstring = NULL,
|
||||
.buf_size = 256,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -94,8 +94,6 @@ struct versaloon_usb_setting_t {
|
|||
uint8_t ep_out;
|
||||
uint8_t ep_in;
|
||||
uint8_t interface;
|
||||
char *serialstring;
|
||||
|
||||
uint16_t buf_size;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <jtag/swd.h>
|
||||
|
@ -323,7 +324,7 @@ static int vsllink_init(void)
|
|||
versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0,
|
||||
GPIO_TRST, GPIO_TRST);
|
||||
versaloon_interface.adaptors.swd.init(0);
|
||||
vsllink_swd_frequency(jtag_get_speed_khz() * 1000);
|
||||
vsllink_swd_frequency(adapter_get_speed_khz() * 1000);
|
||||
vsllink_swd_switch_seq(JTAG_TO_SWD);
|
||||
|
||||
} else {
|
||||
|
@ -339,7 +340,7 @@ static int vsllink_init(void)
|
|||
}
|
||||
|
||||
versaloon_interface.adaptors.jtag_raw.init(0);
|
||||
versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz());
|
||||
versaloon_interface.adaptors.jtag_raw.config(0, adapter_get_speed_khz());
|
||||
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
|
||||
GPIO_TRST, GPIO_SRST, GPIO_SRST);
|
||||
}
|
||||
|
@ -498,21 +499,6 @@ COMMAND_HANDLER(vsllink_handle_usb_pid_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(vsllink_handle_usb_serial_command)
|
||||
{
|
||||
if (CMD_ARGC > 1)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
free(versaloon_interface.usb_setting.serialstring);
|
||||
|
||||
if (CMD_ARGC == 1)
|
||||
versaloon_interface.usb_setting.serialstring = strdup(CMD_ARGV[0]);
|
||||
else
|
||||
versaloon_interface.usb_setting.serialstring = NULL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(vsllink_handle_usb_bulkin_command)
|
||||
{
|
||||
if (CMD_ARGC != 1)
|
||||
|
@ -785,14 +771,14 @@ static int vsllink_check_usb_strings(
|
|||
char desc_string[256];
|
||||
int retval;
|
||||
|
||||
if (versaloon_interface.usb_setting.serialstring) {
|
||||
if (adapter_get_required_serial()) {
|
||||
retval = libusb_get_string_descriptor_ascii(usb_device_handle,
|
||||
usb_desc->iSerialNumber, (unsigned char *)desc_string,
|
||||
sizeof(desc_string));
|
||||
if (retval < 0)
|
||||
return ERROR_FAIL;
|
||||
|
||||
if (strncmp(desc_string, versaloon_interface.usb_setting.serialstring,
|
||||
if (strncmp(desc_string, adapter_get_required_serial(),
|
||||
sizeof(desc_string)))
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
@ -902,13 +888,6 @@ static const struct command_registration vsllink_subcommand_handlers[] = {
|
|||
.help = "Set USB PID",
|
||||
.usage = "<pid>",
|
||||
},
|
||||
{
|
||||
.name = "usb_serial",
|
||||
.handler = &vsllink_handle_usb_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "Set or disable check for USB serial",
|
||||
.usage = "[<serial>]",
|
||||
},
|
||||
{
|
||||
.name = "usb_bulkin",
|
||||
.handler = &vsllink_handle_usb_bulkin_command,
|
||||
|
|
|
@ -20,15 +20,13 @@
|
|||
#endif
|
||||
|
||||
#include <transport/transport.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/swd.h>
|
||||
#include <jtag/interface.h>
|
||||
#include <jtag/commands.h>
|
||||
#include <jtag/tcl.h>
|
||||
#include <libusb.h>
|
||||
|
||||
/* XDS110 USB serial number length */
|
||||
#define XDS110_SERIAL_LEN 8
|
||||
|
||||
/* XDS110 stand-alone probe voltage supply limits */
|
||||
#define XDS110_MIN_VOLTAGE 1800
|
||||
#define XDS110_MAX_VOLTAGE 3600
|
||||
|
@ -238,8 +236,6 @@ struct xds110_info {
|
|||
/* TCK speed and delay count*/
|
||||
uint32_t speed;
|
||||
uint32_t delay_count;
|
||||
/* XDS110 serial number */
|
||||
char serial[XDS110_SERIAL_LEN + 1];
|
||||
/* XDS110 voltage supply setting */
|
||||
uint32_t voltage;
|
||||
/* XDS110 firmware and hardware version */
|
||||
|
@ -269,7 +265,6 @@ static struct xds110_info xds110 = {
|
|||
.is_ap_dirty = false,
|
||||
.speed = XDS110_DEFAULT_TCK_SPEED,
|
||||
.delay_count = 0,
|
||||
.serial = {0},
|
||||
.voltage = 0,
|
||||
.firmware = 0,
|
||||
.hardware = 0,
|
||||
|
@ -371,7 +366,7 @@ static bool usb_connect(void)
|
|||
*data = '\0';
|
||||
|
||||
/* May be the requested device if serial number matches */
|
||||
if (xds110.serial[0] == 0) {
|
||||
if (!adapter_get_required_serial()) {
|
||||
/* No serial number given; match first XDS110 found */
|
||||
found = true;
|
||||
break;
|
||||
|
@ -380,7 +375,7 @@ static bool usb_connect(void)
|
|||
result = libusb_get_string_descriptor_ascii(dev,
|
||||
desc.iSerialNumber, data, max_data);
|
||||
if (result > 0 &&
|
||||
strcmp((char *)data, (char *)xds110.serial) == 0) {
|
||||
strcmp((char *)data, adapter_get_required_serial()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1395,8 +1390,8 @@ static void xds110_show_info(void)
|
|||
(((firmware >> 12) & 0xf) * 10) + ((firmware >> 8) & 0xf),
|
||||
(((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf));
|
||||
LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware);
|
||||
if (xds110.serial[0] != 0)
|
||||
LOG_INFO("XDS110: serial number = %s", xds110.serial);
|
||||
if (adapter_get_required_serial())
|
||||
LOG_INFO("XDS110: serial number = %s", adapter_get_required_serial());
|
||||
if (xds110.is_swd_mode) {
|
||||
LOG_INFO("XDS110: connected to target via SWD");
|
||||
LOG_INFO("XDS110: SWCLK set to %" PRIu32 " kHz", xds110.speed);
|
||||
|
@ -2024,34 +2019,6 @@ COMMAND_HANDLER(xds110_handle_info_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(xds110_handle_serial_command)
|
||||
{
|
||||
wchar_t serial[XDS110_SERIAL_LEN + 1];
|
||||
|
||||
xds110.serial[0] = 0;
|
||||
|
||||
if (CMD_ARGC == 1) {
|
||||
size_t len = mbstowcs(0, CMD_ARGV[0], 0);
|
||||
if (len > XDS110_SERIAL_LEN) {
|
||||
LOG_ERROR("XDS110: serial number is limited to %d characters",
|
||||
XDS110_SERIAL_LEN);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if ((size_t)-1 == mbstowcs(serial, CMD_ARGV[0], len + 1)) {
|
||||
LOG_ERROR("XDS110: unable to convert serial number");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
xds110.serial[i] = (char)serial[i];
|
||||
|
||||
xds110.serial[len] = 0;
|
||||
} else
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(xds110_handle_supply_voltage_command)
|
||||
{
|
||||
uint32_t voltage = 0;
|
||||
|
@ -2082,13 +2049,6 @@ static const struct command_registration xds110_subcommand_handlers[] = {
|
|||
.help = "show XDS110 info",
|
||||
.usage = "",
|
||||
},
|
||||
{
|
||||
.name = "serial",
|
||||
.handler = &xds110_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the XDS110 probe serial number",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "supply",
|
||||
.handler = &xds110_handle_supply_voltage_command,
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
static struct hl_interface_s hl_if = {
|
||||
.param = {
|
||||
.device_desc = NULL,
|
||||
.serial = NULL,
|
||||
.vid = { 0 },
|
||||
.pid = { 0 },
|
||||
.transport = HL_TRANSPORT_UNKNOWN,
|
||||
|
@ -136,7 +135,6 @@ static int hl_interface_quit(void)
|
|||
jtag_command_queue_reset();
|
||||
|
||||
free((void *)hl_if.param.device_desc);
|
||||
free((void *)hl_if.param.serial);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -238,19 +236,6 @@ COMMAND_HANDLER(hl_interface_handle_device_desc_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(hl_interface_handle_serial_command)
|
||||
{
|
||||
LOG_DEBUG("hl_interface_handle_serial_command");
|
||||
|
||||
if (CMD_ARGC == 1) {
|
||||
hl_if.param.serial = strdup(CMD_ARGV[0]);
|
||||
} else {
|
||||
LOG_ERROR("expected exactly one argument to hl_serial <serial-number>");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(hl_interface_handle_layout_command)
|
||||
{
|
||||
LOG_DEBUG("hl_interface_handle_layout_command");
|
||||
|
@ -354,13 +339,6 @@ static const struct command_registration hl_interface_command_handlers[] = {
|
|||
.help = "set the device description of the adapter",
|
||||
.usage = "description_string",
|
||||
},
|
||||
{
|
||||
.name = "hla_serial",
|
||||
.handler = &hl_interface_handle_serial_command,
|
||||
.mode = COMMAND_CONFIG,
|
||||
.help = "set the serial number of the adapter",
|
||||
.usage = "serial_string",
|
||||
},
|
||||
{
|
||||
.name = "hla_layout",
|
||||
.handler = &hl_interface_handle_layout_command,
|
||||
|
|
|
@ -34,8 +34,6 @@ extern const char *hl_transports[];
|
|||
struct hl_interface_param_s {
|
||||
/** */
|
||||
const char *device_desc;
|
||||
/** */
|
||||
const char *serial;
|
||||
/** List of recognised VIDs */
|
||||
uint16_t vid[HLA_MAX_USB_IDS + 1];
|
||||
/** List of recognised PIDs */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#define OPENOCD_JTAG_HLA_HLA_LAYOUT_H
|
||||
|
||||
#include <target/armv7m_trace.h>
|
||||
#include <target/arm_tpiu_swo.h>
|
||||
|
||||
/** */
|
||||
struct hl_interface_s;
|
||||
|
|
|
@ -45,8 +45,7 @@ COMMAND_HANDLER(hl_transport_reset_command)
|
|||
return hl_interface_init_reset();
|
||||
}
|
||||
|
||||
static const struct command_registration
|
||||
hl_swd_transport_subcommand_handlers[] = {
|
||||
static const struct command_registration hl_swd_transport_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "newdap",
|
||||
.mode = COMMAND_CONFIG,
|
||||
|
@ -67,8 +66,7 @@ static const struct command_registration hl_swd_transport_command_handlers[] = {
|
|||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration
|
||||
hl_transport_jtag_subcommand_handlers[] = {
|
||||
static const struct command_registration hl_transport_jtag_subcommand_handlers[] = {
|
||||
{
|
||||
.name = "newtap",
|
||||
.mode = COMMAND_CONFIG,
|
||||
|
@ -196,15 +194,13 @@ static int hl_jtag_transport_select(struct command_context *cmd_ctx)
|
|||
* That works with only C code ... no Tcl glue required.
|
||||
*/
|
||||
|
||||
return register_commands(cmd_ctx, NULL,
|
||||
hl_jtag_transport_command_handlers);
|
||||
return register_commands(cmd_ctx, NULL, hl_jtag_transport_command_handlers);
|
||||
}
|
||||
|
||||
static int hl_swd_transport_select(struct command_context *cmd_ctx)
|
||||
{
|
||||
LOG_DEBUG("hl_swd_transport_select");
|
||||
return register_commands(cmd_ctx, NULL,
|
||||
hl_swd_transport_command_handlers);
|
||||
return register_commands(cmd_ctx, NULL, hl_swd_transport_command_handlers);
|
||||
}
|
||||
|
||||
static struct transport hl_swd_transport = {
|
||||
|
|
|
@ -217,31 +217,6 @@ int jtag_unregister_event_callback(jtag_event_handler_t f, void *x);
|
|||
|
||||
int jtag_call_event_callbacks(enum jtag_event event);
|
||||
|
||||
|
||||
/** @returns The current JTAG speed setting. */
|
||||
int jtag_get_speed(int *speed);
|
||||
|
||||
/**
|
||||
* Given a @a speed setting, use the interface @c speed_div callback to
|
||||
* adjust the setting.
|
||||
* @param speed The speed setting to convert back to readable KHz.
|
||||
* @returns ERROR_OK if the interface has not been initialized or on success;
|
||||
* otherwise, the error code produced by the @c speed_div callback.
|
||||
*/
|
||||
int jtag_get_speed_readable(int *speed);
|
||||
|
||||
/** Attempt to configure the interface for the specified KHz. */
|
||||
int jtag_config_khz(unsigned khz);
|
||||
|
||||
/**
|
||||
* Attempt to enable RTCK/RCLK. If that fails, fallback to the
|
||||
* specified frequency.
|
||||
*/
|
||||
int jtag_config_rclk(unsigned fallback_speed_khz);
|
||||
|
||||
/** Retrieves the clock speed of the JTAG interface in KHz. */
|
||||
unsigned jtag_get_speed_khz(void);
|
||||
|
||||
enum reset_types {
|
||||
RESET_NONE = 0x0,
|
||||
RESET_HAS_TRST = 0x1,
|
||||
|
@ -285,12 +260,6 @@ void jtag_set_verify_capture_ir(bool enable);
|
|||
/** @returns True if IR scan verification will be performed. */
|
||||
bool jtag_will_verify_capture_ir(void);
|
||||
|
||||
/** Initialize debug adapter upon startup. */
|
||||
int adapter_init(struct command_context *cmd_ctx);
|
||||
|
||||
/** Shutdown the debug adapter upon program exit. */
|
||||
int adapter_quit(void);
|
||||
|
||||
/** Set ms to sleep after jtag_execute_queue() flushes queue. Debug purposes. */
|
||||
void jtag_set_flush_queue_sleep(int ms);
|
||||
|
||||
|
|
|
@ -187,8 +187,8 @@ proc ftdi_location args {
|
|||
|
||||
lappend _telnet_autocomplete_skip xds110_serial
|
||||
proc xds110_serial args {
|
||||
echo "DEPRECATED! use 'xds110 serial' not 'xds110_serial'"
|
||||
eval xds110 serial $args
|
||||
echo "DEPRECATED! use 'adapter serial' not 'xds110_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip xds110_supply_voltage
|
||||
|
@ -215,8 +215,8 @@ proc ftdi_device_desc args {
|
|||
|
||||
lappend _telnet_autocomplete_skip ftdi_serial
|
||||
proc ftdi_serial args {
|
||||
echo "DEPRECATED! use 'ftdi serial' not 'ftdi_serial'"
|
||||
eval ftdi serial $args
|
||||
echo "DEPRECATED! use 'adapter serial' not 'ftdi_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip ftdi_channel
|
||||
|
@ -371,8 +371,8 @@ proc vsllink_usb_pid args {
|
|||
|
||||
lappend _telnet_autocomplete_skip vsllink_usb_serial
|
||||
proc vsllink_usb_serial args {
|
||||
echo "DEPRECATED! use 'vsllink usb_serial' not 'vsllink_usb_serial'"
|
||||
eval vsllink usb_serial $args
|
||||
echo "DEPRECATED! use 'adapter serial' not 'vsllink_usb_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip vsllink_usb_bulkin
|
||||
|
@ -677,8 +677,8 @@ proc usb_blaster_firmware args {
|
|||
|
||||
lappend _telnet_autocomplete_skip ft232r_serial_desc
|
||||
proc ft232r_serial_desc args {
|
||||
echo "DEPRECATED! use 'ft232r serial_desc' not 'ft232r_serial_desc'"
|
||||
eval ft232r serial_desc $args
|
||||
echo "DEPRECATED! use 'adapter serial_desc' not 'ft232r_serial_desc'"
|
||||
eval adapter serial_desc $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip ft232r_vid_pid
|
||||
|
@ -735,4 +735,70 @@ proc ft232r_restore_serial args {
|
|||
eval ft232r restore_serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "aice serial"
|
||||
proc "aice serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'aice serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip cmsis_dap_serial
|
||||
proc cmsis_dap_serial args {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'cmsis_dap_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "ft232r serial_desc"
|
||||
proc "ft232r serial_desc" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'ft232r serial_desc'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "ftdi serial"
|
||||
proc "ftdi serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'ftdi serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip hla_serial
|
||||
proc hla_serial args {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'hla_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "jlink serial"
|
||||
proc "jlink serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'jlink serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip kitprog_serial
|
||||
proc kitprog_serial args {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'kitprog_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "presto serial"
|
||||
proc "presto serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'presto serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "st-link serial"
|
||||
proc "st-link serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'st-link serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "vsllink usb_serial"
|
||||
proc "vsllink usb_serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'vsllink usb_serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
lappend _telnet_autocomplete_skip "xds110 serial"
|
||||
proc "xds110 serial" {args} {
|
||||
echo "DEPRECATED! use 'adapter serial' not 'xds110 serial'"
|
||||
eval adapter serial $args
|
||||
}
|
||||
|
||||
# END MIGRATION AIDS
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef OPENOCD_JTAG_SWD_H
|
||||
#define OPENOCD_JTAG_SWD_H
|
||||
|
||||
#include <helper/log.h>
|
||||
#include <target/arm_adi_v5.h>
|
||||
|
||||
/* Bits in SWD command packets, written from host to target
|
||||
|
@ -32,6 +33,12 @@
|
|||
#define SWD_CMD_PARK (1 << 7) /* driven high by host */
|
||||
/* followed by TRN, 3-bits of ACK, TRN */
|
||||
|
||||
/*
|
||||
* The SWD subsystem error codes
|
||||
*/
|
||||
#define ERROR_SWD_FAIL (-400) /** protocol or parity error */
|
||||
#define ERROR_SWD_FAULT (-401) /** device returned FAULT in ACK field */
|
||||
|
||||
/**
|
||||
* Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg()
|
||||
* and swd_driver.write_reg() methods will use directly.
|
||||
|
@ -53,6 +60,40 @@ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum)
|
|||
|
||||
/* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */
|
||||
|
||||
/**
|
||||
* Test if we can rely on ACK returned by SWD command
|
||||
*
|
||||
* @param cmd Byte constructed by swd_cmd(), START, STOP and TRN are filtered off
|
||||
* @returns true if ACK should be checked, false if should be ignored
|
||||
*/
|
||||
static inline bool swd_cmd_returns_ack(uint8_t cmd)
|
||||
{
|
||||
uint8_t base_cmd = cmd & (SWD_CMD_APNDP | SWD_CMD_RNW | SWD_CMD_A32);
|
||||
|
||||
/* DPv2 does not reply to DP_TARGETSEL write cmd */
|
||||
return base_cmd != swd_cmd(false, false, DP_TARGETSEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert SWD ACK value returned from DP to OpenOCD error code
|
||||
*
|
||||
* @param ack
|
||||
* @returns error code
|
||||
*/
|
||||
static inline int swd_ack_to_error_code(uint8_t ack)
|
||||
{
|
||||
switch (ack) {
|
||||
case SWD_ACK_OK:
|
||||
return ERROR_OK;
|
||||
case SWD_ACK_WAIT:
|
||||
return ERROR_WAIT;
|
||||
case SWD_ACK_FAULT:
|
||||
return ERROR_SWD_FAULT;
|
||||
default:
|
||||
return ERROR_SWD_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following sequences are updated to
|
||||
* ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "adapter.h"
|
||||
#include "jtag.h"
|
||||
#include "swd.h"
|
||||
#include "minidriver.h"
|
||||
|
@ -1040,13 +1041,13 @@ COMMAND_HANDLER(handle_jtag_rclk_command)
|
|||
unsigned khz = 0;
|
||||
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz);
|
||||
|
||||
retval = jtag_config_rclk(khz);
|
||||
retval = adapter_config_rclk(khz);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int cur_khz = jtag_get_speed_khz();
|
||||
retval = jtag_get_speed_readable(&cur_khz);
|
||||
int cur_khz = adapter_get_speed_khz();
|
||||
retval = adapter_get_speed_readable(&cur_khz);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#endif
|
||||
|
||||
#include "openocd.h"
|
||||
#include <jtag/driver.h>
|
||||
#include <jtag/adapter.h>
|
||||
#include <jtag/jtag.h>
|
||||
#include <transport/transport.h>
|
||||
#include <helper/util.h>
|
||||
|
@ -312,7 +312,7 @@ static struct command_context *setup_command_handler(Jim_Interp *interp)
|
|||
&log_register_commands,
|
||||
&rtt_server_register_commands,
|
||||
&transport_register_commands,
|
||||
&interface_register_commands,
|
||||
&adapter_register_commands,
|
||||
&target_register_commands,
|
||||
&flash_register_commands,
|
||||
&nand_register_commands,
|
||||
|
|
|
@ -67,8 +67,7 @@ COMMAND_HANDLER(handle_pld_device_command)
|
|||
/* register pld specific commands */
|
||||
int retval;
|
||||
if (pld_drivers[i]->commands) {
|
||||
retval = register_commands(CMD_CTX, NULL,
|
||||
pld_drivers[i]->commands);
|
||||
retval = register_commands(CMD_CTX, NULL, pld_drivers[i]->commands);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[0]);
|
||||
return ERROR_FAIL;
|
||||
|
|
|
@ -424,7 +424,7 @@ const struct rtos_register_stacking rtos_standard_cortex_m3_stacking = {
|
|||
};
|
||||
|
||||
const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking = {
|
||||
.stack_registers_size = 0x44, /* 4 more for LR*/
|
||||
.stack_registers_size = 0x44,
|
||||
.stack_growth_direction = -1,
|
||||
.num_output_registers = ARMV7M_NUM_CORE_REGS,
|
||||
.calculate_process_stack = rtos_standard_cortex_m4f_stack_align,
|
||||
|
@ -432,7 +432,7 @@ const struct rtos_register_stacking rtos_standard_cortex_m4f_stacking = {
|
|||
};
|
||||
|
||||
const struct rtos_register_stacking rtos_standard_cortex_m4f_fpu_stacking = {
|
||||
.stack_registers_size = 0xcc, /* 4 more for LR + 48 more for FPU S0-S15 register*/
|
||||
.stack_registers_size = 0xcc,
|
||||
.stack_growth_direction = -1,
|
||||
.num_output_registers = ARMV7M_NUM_CORE_REGS,
|
||||
.calculate_process_stack = rtos_standard_cortex_m4f_fpu_stack_align,
|
||||
|
|
|
@ -53,8 +53,24 @@
|
|||
|
||||
#include <jtag/swd.h>
|
||||
|
||||
/* for debug, set do_sync to true to force synchronous transfers */
|
||||
static bool do_sync;
|
||||
|
||||
static struct adiv5_dap *swd_multidrop_selected_dap;
|
||||
|
||||
|
||||
static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
|
||||
uint32_t data);
|
||||
|
||||
|
||||
static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
return swd->switch_seq(seq);
|
||||
}
|
||||
|
||||
static void swd_finish_read(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
|
@ -64,11 +80,6 @@ static void swd_finish_read(struct adiv5_dap *dap)
|
|||
}
|
||||
}
|
||||
|
||||
static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t data);
|
||||
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t *data);
|
||||
|
||||
static void swd_clear_sticky_errors(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
|
@ -93,131 +104,13 @@ static int swd_run_inner(struct adiv5_dap *dap)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int swd_connect(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
uint32_t dpidr = 0xdeadbeef;
|
||||
int status;
|
||||
|
||||
/* FIXME validate transport config ... is the
|
||||
* configured DAP present (check IDCODE)?
|
||||
* Is *only* one DAP configured?
|
||||
*
|
||||
* MUST READ DPIDR
|
||||
*/
|
||||
|
||||
/* Check if we should reset srst already when connecting, but not if reconnecting. */
|
||||
if (!dap->do_reconnect) {
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
|
||||
if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
|
||||
if (jtag_reset_config & RESET_SRST_NO_GATING)
|
||||
adapter_assert_reset();
|
||||
else
|
||||
LOG_WARNING("\'srst_nogate\' reset_config option is required");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int64_t timeout = timeval_ms() + 500;
|
||||
|
||||
do {
|
||||
/* Note, debugport_init() does setup too */
|
||||
swd->switch_seq(JTAG_TO_SWD);
|
||||
|
||||
/* Clear link state, including the SELECT cache. */
|
||||
dap->do_reconnect = false;
|
||||
dap_invalidate_cache(dap);
|
||||
|
||||
status = swd_queue_dp_read(dap, DP_DPIDR, &dpidr);
|
||||
if (status == ERROR_OK) {
|
||||
status = swd_run_inner(dap);
|
||||
if (status == ERROR_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
|
||||
} while (timeval_ms() < timeout);
|
||||
|
||||
if (status != ERROR_OK) {
|
||||
LOG_ERROR("Error connecting DP: cannot read IDR");
|
||||
return status;
|
||||
}
|
||||
|
||||
LOG_INFO("SWD DPIDR %#8.8" PRIx32, dpidr);
|
||||
|
||||
do {
|
||||
dap->do_reconnect = false;
|
||||
|
||||
/* force clear all sticky faults */
|
||||
swd_clear_sticky_errors(dap);
|
||||
|
||||
status = swd_run_inner(dap);
|
||||
if (status != ERROR_WAIT)
|
||||
break;
|
||||
|
||||
alive_sleep(10);
|
||||
|
||||
} while (timeval_ms() < timeout);
|
||||
|
||||
/* IHI 0031E B4.3.2:
|
||||
* "A WAIT response must not be issued to the ...
|
||||
* ... writes to the ABORT register"
|
||||
* swd_clear_sticky_errors() writes to the ABORT register only.
|
||||
*
|
||||
* Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT
|
||||
* in a corner case. Just try if ABORT resolves the problem.
|
||||
*/
|
||||
if (status == ERROR_WAIT) {
|
||||
LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT");
|
||||
|
||||
dap->do_reconnect = false;
|
||||
|
||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
||||
status = swd_run_inner(dap);
|
||||
}
|
||||
|
||||
if (status == ERROR_OK)
|
||||
status = dap_dp_init(dap);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int swd_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
return swd->switch_seq(seq);
|
||||
}
|
||||
|
||||
static inline int check_sync(struct adiv5_dap *dap)
|
||||
{
|
||||
return do_sync ? swd_run_inner(dap) : ERROR_OK;
|
||||
}
|
||||
|
||||
static int swd_check_reconnect(struct adiv5_dap *dap)
|
||||
{
|
||||
if (dap->do_reconnect)
|
||||
return swd_connect(dap);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
||||
return check_sync(dap);
|
||||
}
|
||||
|
||||
/** Select the DP register bank matching bits 7:4 of reg. */
|
||||
static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg)
|
||||
static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned int reg)
|
||||
{
|
||||
/* Only register address 4 is banked. */
|
||||
if ((reg & 0xf) != 4)
|
||||
|
@ -232,24 +125,20 @@ static int swd_queue_dp_bankselect(struct adiv5_dap *dap, unsigned reg)
|
|||
|
||||
dap->select = sel;
|
||||
|
||||
int retval = swd_queue_dp_write(dap, DP_SELECT, sel);
|
||||
int retval = swd_queue_dp_write_inner(dap, DP_SELECT, sel);
|
||||
if (retval != ERROR_OK)
|
||||
dap->select = DP_SELECT_INVALID;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
static int swd_queue_dp_read_inner(struct adiv5_dap *dap, unsigned int reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_queue_dp_bankselect(dap, reg);
|
||||
int retval = swd_queue_dp_bankselect(dap, reg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
@ -258,17 +147,15 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
|||
return check_sync(dap);
|
||||
}
|
||||
|
||||
static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
|
||||
static int swd_queue_dp_write_inner(struct adiv5_dap *dap, unsigned int reg,
|
||||
uint32_t data)
|
||||
{
|
||||
int retval;
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
swd_finish_read(dap);
|
||||
|
||||
if (reg == DP_SELECT) {
|
||||
dap->select = data & (DP_SELECT_APSEL | DP_SELECT_APBANK | DP_SELECT_DPBANK);
|
||||
|
||||
|
@ -290,6 +177,293 @@ static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
|
|||
return check_sync(dap);
|
||||
}
|
||||
|
||||
|
||||
static int swd_multidrop_select_inner(struct adiv5_dap *dap, uint32_t *dpidr_ptr,
|
||||
uint32_t *dlpidr_ptr, bool clear_sticky)
|
||||
{
|
||||
int retval;
|
||||
uint32_t dpidr, dlpidr;
|
||||
|
||||
assert(dap_is_multidrop(dap));
|
||||
|
||||
swd_send_sequence(dap, LINE_RESET);
|
||||
|
||||
retval = swd_queue_dp_write_inner(dap, DP_TARGETSEL, dap->multidrop_targetsel);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (clear_sticky) {
|
||||
/* Clear all sticky errors (including ORUN) */
|
||||
swd_clear_sticky_errors(dap);
|
||||
} else {
|
||||
/* Ideally just clear ORUN flag which is set by reset */
|
||||
retval = swd_queue_dp_write_inner(dap, DP_ABORT, ORUNERRCLR);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = swd_queue_dp_read_inner(dap, DP_DLPIDR, &dlpidr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_run_inner(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if ((dpidr & DP_DPIDR_VERSION_MASK) < (2UL << DP_DPIDR_VERSION_SHIFT)) {
|
||||
LOG_INFO("Read DPIDR 0x%08" PRIx32
|
||||
" has version < 2. A non multidrop capable device connected?",
|
||||
dpidr);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* TODO: check TARGETID if DLIPDR is same for more than one DP */
|
||||
uint32_t expected_dlpidr = DP_DLPIDR_PROTVSN |
|
||||
(dap->multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK);
|
||||
if (dlpidr != expected_dlpidr) {
|
||||
LOG_INFO("Read incorrect DLPIDR 0x%08" PRIx32
|
||||
" (possibly CTRL/STAT value)",
|
||||
dlpidr);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
LOG_DEBUG_IO("Selected DP_TARGETSEL 0x%08" PRIx32, dap->multidrop_targetsel);
|
||||
swd_multidrop_selected_dap = dap;
|
||||
|
||||
if (dpidr_ptr)
|
||||
*dpidr_ptr = dpidr;
|
||||
|
||||
if (dlpidr_ptr)
|
||||
*dlpidr_ptr = dlpidr;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_multidrop_select(struct adiv5_dap *dap)
|
||||
{
|
||||
if (!dap_is_multidrop(dap))
|
||||
return ERROR_OK;
|
||||
|
||||
if (swd_multidrop_selected_dap == dap)
|
||||
return ERROR_OK;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
for (unsigned int retry = 0; ; retry++) {
|
||||
bool clear_sticky = retry > 0;
|
||||
|
||||
retval = swd_multidrop_select_inner(dap, NULL, NULL, clear_sticky);
|
||||
if (retval == ERROR_OK)
|
||||
break;
|
||||
|
||||
swd_multidrop_selected_dap = NULL;
|
||||
if (retry > 3) {
|
||||
LOG_ERROR("Failed to select multidrop %s", adiv5_dap_name(dap));
|
||||
return retval;
|
||||
}
|
||||
|
||||
LOG_DEBUG("Failed to select multidrop %s, retrying...",
|
||||
adiv5_dap_name(dap));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_connect_multidrop(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval;
|
||||
uint32_t dpidr = 0xdeadbeef;
|
||||
uint32_t dlpidr = 0xdeadbeef;
|
||||
int64_t timeout = timeval_ms() + 500;
|
||||
|
||||
do {
|
||||
swd_send_sequence(dap, JTAG_TO_DORMANT);
|
||||
swd_send_sequence(dap, DORMANT_TO_SWD);
|
||||
|
||||
/* Clear link state, including the SELECT cache. */
|
||||
dap->do_reconnect = false;
|
||||
dap_invalidate_cache(dap);
|
||||
swd_multidrop_selected_dap = NULL;
|
||||
|
||||
retval = swd_multidrop_select_inner(dap, &dpidr, &dlpidr, true);
|
||||
if (retval == ERROR_OK)
|
||||
break;
|
||||
|
||||
alive_sleep(1);
|
||||
|
||||
} while (timeval_ms() < timeout);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
swd_multidrop_selected_dap = NULL;
|
||||
LOG_ERROR("Failed to connect multidrop %s", adiv5_dap_name(dap));
|
||||
return retval;
|
||||
}
|
||||
|
||||
LOG_INFO("SWD DPIDR 0x%08" PRIx32 ", DLPIDR 0x%08" PRIx32,
|
||||
dpidr, dlpidr);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_connect_single(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval;
|
||||
uint32_t dpidr = 0xdeadbeef;
|
||||
int64_t timeout = timeval_ms() + 500;
|
||||
|
||||
do {
|
||||
swd_send_sequence(dap, JTAG_TO_SWD);
|
||||
|
||||
/* Clear link state, including the SELECT cache. */
|
||||
dap->do_reconnect = false;
|
||||
dap_invalidate_cache(dap);
|
||||
|
||||
retval = swd_queue_dp_read_inner(dap, DP_DPIDR, &dpidr);
|
||||
if (retval == ERROR_OK) {
|
||||
retval = swd_run_inner(dap);
|
||||
if (retval == ERROR_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
alive_sleep(1);
|
||||
|
||||
} while (timeval_ms() < timeout);
|
||||
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Error connecting DP: cannot read IDR");
|
||||
return retval;
|
||||
}
|
||||
|
||||
LOG_INFO("SWD DPIDR 0x%08" PRIx32, dpidr);
|
||||
|
||||
do {
|
||||
dap->do_reconnect = false;
|
||||
|
||||
/* force clear all sticky faults */
|
||||
swd_clear_sticky_errors(dap);
|
||||
|
||||
retval = swd_run_inner(dap);
|
||||
if (retval != ERROR_WAIT)
|
||||
break;
|
||||
|
||||
alive_sleep(10);
|
||||
|
||||
} while (timeval_ms() < timeout);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int swd_connect(struct adiv5_dap *dap)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* FIXME validate transport config ... is the
|
||||
* configured DAP present (check IDCODE)?
|
||||
*/
|
||||
|
||||
/* Check if we should reset srst already when connecting, but not if reconnecting. */
|
||||
if (!dap->do_reconnect) {
|
||||
enum reset_types jtag_reset_config = jtag_get_reset_config();
|
||||
|
||||
if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
|
||||
if (jtag_reset_config & RESET_SRST_NO_GATING)
|
||||
adapter_assert_reset();
|
||||
else
|
||||
LOG_WARNING("\'srst_nogate\' reset_config option is required");
|
||||
}
|
||||
}
|
||||
|
||||
if (dap_is_multidrop(dap))
|
||||
status = swd_connect_multidrop(dap);
|
||||
else
|
||||
status = swd_connect_single(dap);
|
||||
|
||||
/* IHI 0031E B4.3.2:
|
||||
* "A WAIT response must not be issued to the ...
|
||||
* ... writes to the ABORT register"
|
||||
* swd_clear_sticky_errors() writes to the ABORT register only.
|
||||
*
|
||||
* Unfortunately at least Microchip SAMD51/E53/E54 returns WAIT
|
||||
* in a corner case. Just try if ABORT resolves the problem.
|
||||
*/
|
||||
if (status == ERROR_WAIT) {
|
||||
LOG_WARNING("Connecting DP: stalled AP operation, issuing ABORT");
|
||||
|
||||
dap->do_reconnect = false;
|
||||
|
||||
status = swd_queue_dp_write_inner(dap, DP_ABORT,
|
||||
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
|
||||
|
||||
if (status == ERROR_OK)
|
||||
status = swd_run_inner(dap);
|
||||
}
|
||||
|
||||
if (status == ERROR_OK)
|
||||
status = dap_dp_init(dap);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int swd_check_reconnect(struct adiv5_dap *dap)
|
||||
{
|
||||
if (dap->do_reconnect)
|
||||
return swd_connect(dap);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
/* TODO: Send DAPABORT in swd_multidrop_select_inner()
|
||||
* in the case the multidrop dap is not selected?
|
||||
* swd_queue_ap_abort() is not currently used anyway...
|
||||
*/
|
||||
int retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
swd->write_reg(swd_cmd(false, false, DP_ABORT),
|
||||
DAPABORT | STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0);
|
||||
return check_sync(dap);
|
||||
}
|
||||
|
||||
static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t *data)
|
||||
{
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return swd_queue_dp_read_inner(dap, reg, data);
|
||||
}
|
||||
|
||||
static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg,
|
||||
uint32_t data)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
assert(swd);
|
||||
|
||||
int retval = swd_check_reconnect(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return swd_queue_dp_write_inner(dap, reg, data);
|
||||
}
|
||||
|
||||
/** Select the AP register bank matching bits 7:4 of reg. */
|
||||
static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg)
|
||||
{
|
||||
|
@ -303,7 +477,7 @@ static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg)
|
|||
|
||||
dap->select = sel;
|
||||
|
||||
int retval = swd_queue_dp_write(dap, DP_SELECT, sel);
|
||||
int retval = swd_queue_dp_write_inner(dap, DP_SELECT, sel);
|
||||
if (retval != ERROR_OK)
|
||||
dap->select = DP_SELECT_INVALID;
|
||||
|
||||
|
@ -321,6 +495,10 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg,
|
|||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_queue_ap_bankselect(ap, reg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
@ -342,7 +520,12 @@ static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
|
|||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
swd_finish_read(dap);
|
||||
|
||||
retval = swd_queue_ap_bankselect(ap, reg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
@ -355,7 +538,12 @@ static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg,
|
|||
/** Executes all queued DAP operations. */
|
||||
static int swd_run(struct adiv5_dap *dap)
|
||||
{
|
||||
int retval = swd_multidrop_select(dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
swd_finish_read(dap);
|
||||
|
||||
return swd_run_inner(dap);
|
||||
}
|
||||
|
||||
|
@ -363,9 +551,27 @@ static int swd_run(struct adiv5_dap *dap)
|
|||
static void swd_quit(struct adiv5_dap *dap)
|
||||
{
|
||||
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
|
||||
static bool done;
|
||||
|
||||
/* There is no difference if the sequence is sent at the last
|
||||
* or the first swd_quit() call, send it just once */
|
||||
if (done)
|
||||
return;
|
||||
|
||||
done = true;
|
||||
if (dap_is_multidrop(dap)) {
|
||||
swd->switch_seq(SWD_TO_DORMANT);
|
||||
/* Revisit!
|
||||
* Leaving DPs in dormant state was tested and offers some safety
|
||||
* against DPs mismatch in case of unintentional use of non-multidrop SWD.
|
||||
* To put SWJ-DPs to power-on state issue
|
||||
* swd->switch_seq(DORMANT_TO_JTAG);
|
||||
*/
|
||||
} else {
|
||||
swd->switch_seq(SWD_TO_JTAG);
|
||||
/* flush the queue before exit */
|
||||
}
|
||||
|
||||
/* flush the queue to shift out the sequence before exit */
|
||||
swd->run();
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
|
||||
#define DLCR_TO_TRN(dlcr) ((uint32_t)(1 + ((3 & (dlcr)) >> 8))) /* 1..4 clocks */
|
||||
|
||||
/* Fields of DP_DPIDR register */
|
||||
#define DP_DPIDR_VERSION_SHIFT 12
|
||||
#define DP_DPIDR_VERSION_MASK (0xFUL << DP_DPIDR_VERSION_SHIFT)
|
||||
|
||||
/* Fields of the DP's AP ABORT register */
|
||||
#define DAPABORT (1UL << 0)
|
||||
#define STKCMPCLR (1UL << 1) /* SWD-only */
|
||||
|
@ -89,6 +93,8 @@
|
|||
#define CSYSPWRUPREQ (1UL << 30)
|
||||
#define CSYSPWRUPACK (1UL << 31)
|
||||
|
||||
#define DP_DLPIDR_PROTVSN 1u
|
||||
|
||||
#define DP_SELECT_APSEL 0xFF000000
|
||||
#define DP_SELECT_APBANK 0x000000F0
|
||||
#define DP_SELECT_DPBANK 0x0000000F
|
||||
|
@ -97,6 +103,11 @@
|
|||
#define DP_APSEL_MAX (255)
|
||||
#define DP_APSEL_INVALID (-1)
|
||||
|
||||
#define DP_TARGETSEL_INVALID 0xFFFFFFFFU
|
||||
#define DP_TARGETSEL_DPID_MASK 0x0FFFFFFFU
|
||||
#define DP_TARGETSEL_INSTANCEID_MASK 0xF0000000U
|
||||
#define DP_TARGETSEL_INSTANCEID_SHIFT 28
|
||||
|
||||
|
||||
/* MEM-AP register addresses */
|
||||
#define MEM_AP_REG_CSW 0x00
|
||||
|
@ -191,6 +202,7 @@ enum swd_special_seq {
|
|||
SWD_TO_JTAG,
|
||||
SWD_TO_DORMANT,
|
||||
DORMANT_TO_SWD,
|
||||
DORMANT_TO_JTAG,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -323,6 +335,13 @@ struct adiv5_dap {
|
|||
/** Flag saying whether to ignore the syspwrupack flag in DAP. Some devices
|
||||
* do not set this bit until later in the bringup sequence */
|
||||
bool ignore_syspwrupack;
|
||||
|
||||
/** Value to select DP in SWD multidrop mode or DP_TARGETSEL_INVALID */
|
||||
uint32_t multidrop_targetsel;
|
||||
/** TPARTNO and TDESIGNER fields of multidrop_targetsel have been configured */
|
||||
bool multidrop_dp_id_valid;
|
||||
/** TINSTANCE field of multidrop_targetsel has been configured */
|
||||
bool multidrop_instance_id_valid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -609,6 +628,12 @@ static inline struct adiv5_ap *dap_ap(struct adiv5_dap *dap, uint8_t ap_num)
|
|||
return &dap->ap[ap_num];
|
||||
}
|
||||
|
||||
/** Check if SWD multidrop configuration is valid */
|
||||
static inline bool dap_is_multidrop(struct adiv5_dap *dap)
|
||||
{
|
||||
return dap->multidrop_dp_id_valid && dap->multidrop_instance_id_valid;
|
||||
}
|
||||
|
||||
/* Lookup CoreSight component */
|
||||
int dap_lookup_cs_component(struct adiv5_ap *ap,
|
||||
target_addr_t dbgbase, uint8_t type, target_addr_t *addr, int32_t *idx);
|
||||
|
|
|
@ -155,21 +155,24 @@ int dap_cleanup_all(void)
|
|||
enum dap_cfg_param {
|
||||
CFG_CHAIN_POSITION,
|
||||
CFG_IGNORE_SYSPWRUPACK,
|
||||
CFG_DP_ID,
|
||||
CFG_INSTANCE_ID,
|
||||
};
|
||||
|
||||
static const struct jim_nvp nvp_config_opts[] = {
|
||||
{ .name = "-chain-position", .value = CFG_CHAIN_POSITION },
|
||||
{ .name = "-ignore-syspwrupack", .value = CFG_IGNORE_SYSPWRUPACK },
|
||||
{ .name = "-dp-id", .value = CFG_DP_ID },
|
||||
{ .name = "-instance-id", .value = CFG_INSTANCE_ID },
|
||||
{ .name = NULL, .value = -1 }
|
||||
};
|
||||
|
||||
static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap)
|
||||
{
|
||||
struct jtag_tap *tap = NULL;
|
||||
struct jim_nvp *n;
|
||||
int e;
|
||||
|
||||
/* parse config or cget options ... */
|
||||
/* parse config ... */
|
||||
while (goi->argc > 0) {
|
||||
Jim_SetEmptyResult(goi->interp);
|
||||
|
||||
|
@ -184,31 +187,114 @@ static int dap_configure(struct jim_getopt_info *goi, struct arm_dap_object *dap
|
|||
e = jim_getopt_obj(goi, &o_t);
|
||||
if (e != JIM_OK)
|
||||
return e;
|
||||
|
||||
struct jtag_tap *tap;
|
||||
tap = jtag_tap_by_jim_obj(goi->interp, o_t);
|
||||
if (!tap) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position is invalid", -1);
|
||||
return JIM_ERR;
|
||||
}
|
||||
dap->dap.tap = tap;
|
||||
/* loop for more */
|
||||
break;
|
||||
}
|
||||
case CFG_IGNORE_SYSPWRUPACK:
|
||||
dap->dap.ignore_syspwrupack = true;
|
||||
break;
|
||||
case CFG_DP_ID: {
|
||||
jim_wide w;
|
||||
e = jim_getopt_wide(goi, &w);
|
||||
if (e != JIM_OK) {
|
||||
Jim_SetResultFormatted(goi->interp,
|
||||
"create %s: bad parameter %s",
|
||||
dap->name, n->name);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (w < 0 || w > DP_TARGETSEL_DPID_MASK) {
|
||||
Jim_SetResultFormatted(goi->interp,
|
||||
"create %s: %s out of range",
|
||||
dap->name, n->name);
|
||||
return JIM_ERR;
|
||||
}
|
||||
dap->dap.multidrop_targetsel =
|
||||
(dap->dap.multidrop_targetsel & DP_TARGETSEL_INSTANCEID_MASK)
|
||||
| (w & DP_TARGETSEL_DPID_MASK);
|
||||
dap->dap.multidrop_dp_id_valid = true;
|
||||
break;
|
||||
}
|
||||
case CFG_INSTANCE_ID: {
|
||||
jim_wide w;
|
||||
e = jim_getopt_wide(goi, &w);
|
||||
if (e != JIM_OK) {
|
||||
Jim_SetResultFormatted(goi->interp,
|
||||
"create %s: bad parameter %s",
|
||||
dap->name, n->name);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (w < 0 || w > 15) {
|
||||
Jim_SetResultFormatted(goi->interp,
|
||||
"create %s: %s out of range",
|
||||
dap->name, n->name);
|
||||
return JIM_ERR;
|
||||
}
|
||||
dap->dap.multidrop_targetsel =
|
||||
(dap->dap.multidrop_targetsel & DP_TARGETSEL_DPID_MASK)
|
||||
| ((w << DP_TARGETSEL_INSTANCEID_SHIFT) & DP_TARGETSEL_INSTANCEID_MASK);
|
||||
dap->dap.multidrop_instance_id_valid = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tap) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1);
|
||||
return JIM_ERR;
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
dap_instance_init(&dap->dap);
|
||||
dap->dap.tap = tap;
|
||||
static int dap_check_config(struct adiv5_dap *dap)
|
||||
{
|
||||
if (transport_is_jtag() || transport_is_dapdirect_jtag() || transport_is_hla())
|
||||
return ERROR_OK;
|
||||
|
||||
return JIM_OK;
|
||||
struct arm_dap_object *obj;
|
||||
bool new_multidrop = dap_is_multidrop(dap);
|
||||
bool had_multidrop = new_multidrop;
|
||||
uint32_t targetsel = dap->multidrop_targetsel;
|
||||
unsigned int non_multidrop_count = had_multidrop ? 0 : 1;
|
||||
|
||||
list_for_each_entry(obj, &all_dap, lh) {
|
||||
struct adiv5_dap *dap_it = &obj->dap;
|
||||
|
||||
if (transport_is_swd()) {
|
||||
if (dap_is_multidrop(dap_it)) {
|
||||
had_multidrop = true;
|
||||
if (new_multidrop && dap_it->multidrop_targetsel == targetsel) {
|
||||
uint32_t dp_id = targetsel & DP_TARGETSEL_DPID_MASK;
|
||||
uint32_t instance_id = targetsel >> DP_TARGETSEL_INSTANCEID_SHIFT;
|
||||
LOG_ERROR("%s and %s have the same multidrop selectors -dp-id 0x%08"
|
||||
PRIx32 " and -instance-id 0x%" PRIx32,
|
||||
obj->name, adiv5_dap_name(dap),
|
||||
dp_id, instance_id);
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
} else {
|
||||
non_multidrop_count++;
|
||||
}
|
||||
} else if (transport_is_dapdirect_swd()) {
|
||||
non_multidrop_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (non_multidrop_count > 1) {
|
||||
LOG_ERROR("Two or more SWD non multidrop DAPs are not supported");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (had_multidrop && non_multidrop_count) {
|
||||
LOG_ERROR("Mixing of SWD multidrop DAPs and non multidrop DAPs is not supported");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int dap_create(struct jim_getopt_info *goi)
|
||||
|
@ -242,16 +328,28 @@ static int dap_create(struct jim_getopt_info *goi)
|
|||
if (!dap)
|
||||
return JIM_ERR;
|
||||
|
||||
e = dap_configure(goi, dap);
|
||||
if (e != JIM_OK) {
|
||||
free(dap);
|
||||
return e;
|
||||
}
|
||||
dap_instance_init(&dap->dap);
|
||||
|
||||
cp = Jim_GetString(new_cmd, NULL);
|
||||
dap->name = strdup(cp);
|
||||
|
||||
struct command_registration dap_commands[] = {
|
||||
e = dap_configure(goi, dap);
|
||||
if (e != JIM_OK)
|
||||
goto err;
|
||||
|
||||
if (!dap->dap.tap) {
|
||||
Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1);
|
||||
e = JIM_ERR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
e = dap_check_config(&dap->dap);
|
||||
if (e != ERROR_OK) {
|
||||
e = JIM_ERR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
struct command_registration dap_create_commands[] = {
|
||||
{
|
||||
.name = cp,
|
||||
.mode = COMMAND_ANY,
|
||||
|
@ -264,15 +362,22 @@ static int dap_create(struct jim_getopt_info *goi)
|
|||
|
||||
/* don't expose the instance commands when using hla */
|
||||
if (transport_is_hla())
|
||||
dap_commands[0].chain = NULL;
|
||||
dap_create_commands[0].chain = NULL;
|
||||
|
||||
e = register_commands_with_data(cmd_ctx, NULL, dap_commands, dap);
|
||||
if (e != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap);
|
||||
if (e != ERROR_OK) {
|
||||
e = JIM_ERR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
list_add_tail(&dap->lh, &all_dap);
|
||||
|
||||
return JIM_OK;
|
||||
|
||||
err:
|
||||
free(dap->name);
|
||||
free(dap);
|
||||
return e;
|
||||
}
|
||||
|
||||
static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
|
||||
|
|
|
@ -251,7 +251,7 @@ static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
|
||||
uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
|
||||
{
|
||||
switch (arm_reg_id) {
|
||||
case ARMV7M_R0 ... ARMV7M_R14:
|
||||
|
@ -289,7 +289,7 @@ static uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id)
|
|||
}
|
||||
}
|
||||
|
||||
static bool armv7m_map_reg_packing(unsigned int arm_reg_id,
|
||||
bool armv7m_map_reg_packing(unsigned int arm_reg_id,
|
||||
unsigned int *reg32_id, uint32_t *offset)
|
||||
{
|
||||
|
||||
|
|
|
@ -309,6 +309,11 @@ int armv7m_invalidate_core_regs(struct target *target);
|
|||
|
||||
int armv7m_restore_context(struct target *target);
|
||||
|
||||
uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id);
|
||||
|
||||
bool armv7m_map_reg_packing(unsigned int arm_reg_id,
|
||||
unsigned int *reg32_id, uint32_t *offset);
|
||||
|
||||
int armv7m_checksum_memory(struct target *target,
|
||||
target_addr_t address, uint32_t count, uint32_t *checksum);
|
||||
int armv7m_blank_check_memory(struct target *target,
|
||||
|
|
|
@ -53,6 +53,9 @@
|
|||
* any longer.
|
||||
*/
|
||||
|
||||
/* Timeout for register r/w */
|
||||
#define DHCSR_S_REGRDY_TIMEOUT (500)
|
||||
|
||||
/* Supported Cortex-M Cores */
|
||||
static const struct cortex_m_part_info cortex_m_parts[] = {
|
||||
{
|
||||
|
@ -118,12 +121,41 @@ static int cortex_m_store_core_reg_u32(struct target *target,
|
|||
uint32_t num, uint32_t value);
|
||||
static void cortex_m_dwt_free(struct target *target);
|
||||
|
||||
/** DCB DHCSR register contains S_RETIRE_ST and S_RESET_ST bits cleared
|
||||
* on a read. Call this helper function each time DHCSR is read
|
||||
* to preserve S_RESET_ST state in case of a reset event was detected.
|
||||
*/
|
||||
static inline void cortex_m_cumulate_dhcsr_sticky(struct cortex_m_common *cortex_m,
|
||||
uint32_t dhcsr)
|
||||
{
|
||||
cortex_m->dcb_dhcsr_cumulated_sticky |= dhcsr;
|
||||
}
|
||||
|
||||
/** Read DCB DHCSR register to cortex_m->dcb_dhcsr and cumulate
|
||||
* sticky bits in cortex_m->dcb_dhcsr_cumulated_sticky
|
||||
*/
|
||||
static int cortex_m_read_dhcsr_atomic_sticky(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
|
||||
int retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
|
||||
&cortex_m->dcb_dhcsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cortex_m_load_core_reg_u32(struct target *target,
|
||||
uint32_t regsel, uint32_t *value)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int retval;
|
||||
uint32_t dcrdr;
|
||||
uint32_t dcrdr, tmp_value;
|
||||
int64_t then;
|
||||
|
||||
/* because the DCB_DCRDR is used for the emulated dcc channel
|
||||
* we have to save/restore the DCB_DCRDR when used */
|
||||
|
@ -137,9 +169,29 @@ static int cortex_m_load_core_reg_u32(struct target *target,
|
|||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR, value);
|
||||
/* check if value from register is ready and pre-read it */
|
||||
then = timeval_ms();
|
||||
while (1) {
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR,
|
||||
&cortex_m->dcb_dhcsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DCRDR,
|
||||
&tmp_value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr);
|
||||
if (cortex_m->dcb_dhcsr & S_REGRDY)
|
||||
break;
|
||||
cortex_m->slow_register_read = true; /* Polling (still) needed. */
|
||||
if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) {
|
||||
LOG_ERROR("Timeout waiting for DCRDR transfer ready");
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
*value = tmp_value;
|
||||
|
||||
if (target->dbg_msg_enabled) {
|
||||
/* restore DCB_DCRDR - this needs to be in a separate
|
||||
|
@ -151,11 +203,53 @@ static int cortex_m_load_core_reg_u32(struct target *target,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int cortex_m_store_core_reg_u32(struct target *target,
|
||||
uint32_t regsel, uint32_t value)
|
||||
static int cortex_m_slow_read_all_regs(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
const unsigned int num_regs = armv7m->arm.core_cache->num_regs;
|
||||
|
||||
/* Opportunistically restore fast read, it'll revert to slow
|
||||
* if any register needed polling in cortex_m_load_core_reg_u32(). */
|
||||
cortex_m->slow_register_read = false;
|
||||
|
||||
for (unsigned int reg_id = 0; reg_id < num_regs; reg_id++) {
|
||||
struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id];
|
||||
if (r->exist) {
|
||||
int retval = armv7m->arm.read_core_reg(target, r, reg_id, ARM_MODE_ANY);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cortex_m->slow_register_read)
|
||||
LOG_DEBUG("Switching back to fast register reads");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cortex_m_queue_reg_read(struct target *target, uint32_t regsel,
|
||||
uint32_t *reg_value, uint32_t *dhcsr)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int retval;
|
||||
|
||||
retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DHCSR, dhcsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, reg_value);
|
||||
}
|
||||
|
||||
static int cortex_m_fast_read_all_regs(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int retval;
|
||||
uint32_t dcrdr;
|
||||
|
||||
/* because the DCB_DCRDR is used for the emulated dcc channel
|
||||
|
@ -166,14 +260,157 @@ static int cortex_m_store_core_reg_u32(struct target *target,
|
|||
return retval;
|
||||
}
|
||||
|
||||
const unsigned int num_regs = armv7m->arm.core_cache->num_regs;
|
||||
const unsigned int n_r32 = ARMV7M_LAST_REG - ARMV7M_CORE_FIRST_REG + 1
|
||||
+ ARMV7M_FPU_LAST_REG - ARMV7M_FPU_FIRST_REG + 1;
|
||||
/* we need one 32-bit word for each register except FP D0..D15, which
|
||||
* need two words */
|
||||
uint32_t r_vals[n_r32];
|
||||
uint32_t dhcsr[n_r32];
|
||||
|
||||
unsigned int wi = 0; /* write index to r_vals and dhcsr arrays */
|
||||
unsigned int reg_id; /* register index in the reg_list, ARMV7M_R0... */
|
||||
for (reg_id = 0; reg_id < num_regs; reg_id++) {
|
||||
struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id];
|
||||
if (!r->exist)
|
||||
continue; /* skip non existent registers */
|
||||
|
||||
if (r->size <= 8) {
|
||||
/* Any 8-bit or shorter register is unpacked from a 32-bit
|
||||
* container register. Skip it now. */
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t regsel = armv7m_map_id_to_regsel(reg_id);
|
||||
retval = cortex_m_queue_reg_read(target, regsel, &r_vals[wi],
|
||||
&dhcsr[wi]);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
wi++;
|
||||
|
||||
assert(r->size == 32 || r->size == 64);
|
||||
if (r->size == 32)
|
||||
continue; /* done with 32-bit register */
|
||||
|
||||
assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG);
|
||||
/* the odd part of FP register (S1, S3...) */
|
||||
retval = cortex_m_queue_reg_read(target, regsel + 1, &r_vals[wi],
|
||||
&dhcsr[wi]);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
wi++;
|
||||
}
|
||||
|
||||
assert(wi <= n_r32);
|
||||
|
||||
retval = dap_run(armv7m->debug_ap->dap);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (target->dbg_msg_enabled) {
|
||||
/* restore DCB_DCRDR - this needs to be in a separate
|
||||
* transaction otherwise the emulated DCC channel breaks */
|
||||
retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool not_ready = false;
|
||||
for (unsigned int i = 0; i < wi; i++) {
|
||||
if ((dhcsr[i] & S_REGRDY) == 0) {
|
||||
not_ready = true;
|
||||
LOG_DEBUG("Register %u was not ready during fast read", i);
|
||||
}
|
||||
cortex_m_cumulate_dhcsr_sticky(cortex_m, dhcsr[i]);
|
||||
}
|
||||
|
||||
if (not_ready) {
|
||||
/* Any register was not ready,
|
||||
* fall back to slow read with S_REGRDY polling */
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
|
||||
LOG_DEBUG("read %u 32-bit registers", wi);
|
||||
|
||||
unsigned int ri = 0; /* read index from r_vals array */
|
||||
for (reg_id = 0; reg_id < num_regs; reg_id++) {
|
||||
struct reg *r = &armv7m->arm.core_cache->reg_list[reg_id];
|
||||
if (!r->exist)
|
||||
continue; /* skip non existent registers */
|
||||
|
||||
r->dirty = false;
|
||||
|
||||
unsigned int reg32_id;
|
||||
uint32_t offset;
|
||||
if (armv7m_map_reg_packing(reg_id, ®32_id, &offset)) {
|
||||
/* Unpack a partial register from 32-bit container register */
|
||||
struct reg *r32 = &armv7m->arm.core_cache->reg_list[reg32_id];
|
||||
|
||||
/* The container register ought to precede all regs unpacked
|
||||
* from it in the reg_list. So the value should be ready
|
||||
* to unpack */
|
||||
assert(r32->valid);
|
||||
buf_cpy(r32->value + offset, r->value, r->size);
|
||||
|
||||
} else {
|
||||
assert(r->size == 32 || r->size == 64);
|
||||
buf_set_u32(r->value, 0, 32, r_vals[ri++]);
|
||||
|
||||
if (r->size == 64) {
|
||||
assert(reg_id >= ARMV7M_FPU_FIRST_REG && reg_id <= ARMV7M_FPU_LAST_REG);
|
||||
/* the odd part of FP register (S1, S3...) */
|
||||
buf_set_u32(r->value + 4, 0, 32, r_vals[ri++]);
|
||||
}
|
||||
}
|
||||
r->valid = true;
|
||||
}
|
||||
assert(ri == wi);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cortex_m_store_core_reg_u32(struct target *target,
|
||||
uint32_t regsel, uint32_t value)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
int retval;
|
||||
uint32_t dcrdr;
|
||||
int64_t then;
|
||||
|
||||
/* because the DCB_DCRDR is used for the emulated dcc channel
|
||||
* we have to save/restore the DCB_DCRDR when used */
|
||||
if (target->dbg_msg_enabled) {
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, value);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WNR);
|
||||
retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRSR, regsel | DCRSR_WNR);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* check if value is written into register */
|
||||
then = timeval_ms();
|
||||
while (1) {
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
|
||||
&cortex_m->dcb_dhcsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr);
|
||||
if (cortex_m->dcb_dhcsr & S_REGRDY)
|
||||
break;
|
||||
if (timeval_ms() > then + DHCSR_S_REGRDY_TIMEOUT) {
|
||||
LOG_ERROR("Timeout waiting for DCRDR transfer ready");
|
||||
return ERROR_TIMEOUT_REACHED;
|
||||
}
|
||||
keep_alive();
|
||||
}
|
||||
|
||||
if (target->dbg_msg_enabled) {
|
||||
/* restore DCB_DCRDR - this needs to be in a separate
|
||||
* transaction otherwise the emulated DCC channel breaks */
|
||||
|
@ -301,7 +538,6 @@ static int cortex_m_clear_halt(struct target *target)
|
|||
static int cortex_m_single_step_core(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||
int retval;
|
||||
|
||||
/* Mask interrupts before clearing halt, if not done already. This avoids
|
||||
|
@ -309,13 +545,11 @@ static int cortex_m_single_step_core(struct target *target)
|
|||
* HALT can put the core into an unknown state.
|
||||
*/
|
||||
if (!(cortex_m->dcb_dhcsr & C_MASKINTS)) {
|
||||
retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
|
||||
DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN);
|
||||
retval = cortex_m_write_debug_halt_mask(target, C_MASKINTS, 0);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR,
|
||||
DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN);
|
||||
retval = cortex_m_write_debug_halt_mask(target, C_STEP, C_HALT);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
LOG_DEBUG(" ");
|
||||
|
@ -365,11 +599,12 @@ static int cortex_m_endreset_event(struct target *target)
|
|||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/* Enable debug requests */
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {
|
||||
/* Enable debug requests */
|
||||
retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
@ -431,7 +666,9 @@ static int cortex_m_endreset_event(struct target *target)
|
|||
register_cache_invalidate(armv7m->arm.core_cache);
|
||||
|
||||
/* make sure we have latest dhcsr flags */
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -540,7 +777,6 @@ static int cortex_m_examine_exception_reason(struct target *target)
|
|||
|
||||
static int cortex_m_debug_entry(struct target *target)
|
||||
{
|
||||
int i;
|
||||
uint32_t xPSR;
|
||||
int retval;
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
|
@ -555,7 +791,8 @@ static int cortex_m_debug_entry(struct target *target)
|
|||
cortex_m_set_maskints_for_halt(target);
|
||||
|
||||
cortex_m_clear_halt(target);
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
@ -575,15 +812,20 @@ static int cortex_m_debug_entry(struct target *target)
|
|||
secure_state = (dscsr & DSCSR_CDS) == DSCSR_CDS;
|
||||
}
|
||||
|
||||
/* Examine target state and mode
|
||||
* First load register accessible through core debug port */
|
||||
int num_regs = arm->core_cache->num_regs;
|
||||
|
||||
for (i = 0; i < num_regs; i++) {
|
||||
r = &armv7m->arm.core_cache->reg_list[i];
|
||||
if (r->exist && !r->valid)
|
||||
arm->read_core_reg(target, r, i, ARM_MODE_ANY);
|
||||
/* Load all registers to arm.core_cache */
|
||||
if (!cortex_m->slow_register_read) {
|
||||
retval = cortex_m_fast_read_all_regs(target);
|
||||
if (retval == ERROR_TIMEOUT_REACHED) {
|
||||
cortex_m->slow_register_read = true;
|
||||
LOG_DEBUG("Switched to slow register read");
|
||||
}
|
||||
}
|
||||
|
||||
if (cortex_m->slow_register_read)
|
||||
retval = cortex_m_slow_read_all_regs(target);
|
||||
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
r = arm->cpsr;
|
||||
xPSR = buf_get_u32(r->value, 0, 32);
|
||||
|
@ -639,7 +881,7 @@ static int cortex_m_poll(struct target *target)
|
|||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||
|
||||
/* Read from Debug Halting Control and Status Register */
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK) {
|
||||
target->state = TARGET_UNKNOWN;
|
||||
return retval;
|
||||
|
@ -660,12 +902,13 @@ static int cortex_m_poll(struct target *target)
|
|||
detected_failure = ERROR_FAIL;
|
||||
|
||||
/* refresh status bits */
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (cortex_m->dcb_dhcsr & S_RESET_ST) {
|
||||
if (cortex_m->dcb_dhcsr_cumulated_sticky & S_RESET_ST) {
|
||||
cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST;
|
||||
if (target->state != TARGET_RESET) {
|
||||
target->state = TARGET_RESET;
|
||||
LOG_INFO("%s: external reset detected", target_name(target));
|
||||
|
@ -712,7 +955,12 @@ static int cortex_m_poll(struct target *target)
|
|||
}
|
||||
|
||||
if (target->state == TARGET_UNKNOWN) {
|
||||
/* check if processor is retiring instructions or sleeping */
|
||||
/* Check if processor is retiring instructions or sleeping.
|
||||
* Unlike S_RESET_ST here we test if the target *is* running now,
|
||||
* not if it has been running (possibly in the past). Instructions are
|
||||
* typically processed much faster than OpenOCD polls DHCSR so S_RETIRE_ST
|
||||
* is read always 1. That's the reason not to use dcb_dhcsr_cumulated_sticky.
|
||||
*/
|
||||
if (cortex_m->dcb_dhcsr & S_RETIRE_ST || cortex_m->dcb_dhcsr & S_SLEEP) {
|
||||
target->state = TARGET_RUNNING;
|
||||
retval = ERROR_OK;
|
||||
|
@ -779,7 +1027,6 @@ static int cortex_m_soft_reset_halt(struct target *target)
|
|||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = &cortex_m->armv7m;
|
||||
uint32_t dcb_dhcsr = 0;
|
||||
int retval, timeout = 0;
|
||||
|
||||
/* on single cortex_m MCU soft_reset_halt should be avoided as same functionality
|
||||
|
@ -815,25 +1062,23 @@ static int cortex_m_soft_reset_halt(struct target *target)
|
|||
register_cache_invalidate(cortex_m->armv7m.arm.core_cache);
|
||||
|
||||
while (timeout < 100) {
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval == ERROR_OK) {
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_DFSR,
|
||||
&cortex_m->nvic_dfsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if ((dcb_dhcsr & S_HALT)
|
||||
if ((cortex_m->dcb_dhcsr & S_HALT)
|
||||
&& (cortex_m->nvic_dfsr & DFSR_VCATCH)) {
|
||||
LOG_DEBUG("system reset-halted, DHCSR 0x%08x, "
|
||||
"DFSR 0x%08x",
|
||||
(unsigned) dcb_dhcsr,
|
||||
(unsigned) cortex_m->nvic_dfsr);
|
||||
LOG_DEBUG("system reset-halted, DHCSR 0x%08" PRIx32 ", DFSR 0x%08" PRIx32,
|
||||
cortex_m->dcb_dhcsr, cortex_m->nvic_dfsr);
|
||||
cortex_m_poll(target);
|
||||
/* FIXME restore user's vector catch config */
|
||||
return ERROR_OK;
|
||||
} else
|
||||
LOG_DEBUG("waiting for system reset-halt, "
|
||||
"DHCSR 0x%08x, %d ms",
|
||||
(unsigned) dcb_dhcsr, timeout);
|
||||
"DHCSR 0x%08" PRIx32 ", %d ms",
|
||||
cortex_m->dcb_dhcsr, timeout);
|
||||
}
|
||||
timeout++;
|
||||
alive_sleep(1);
|
||||
|
@ -1082,9 +1327,7 @@ static int cortex_m_step(struct target *target, int current,
|
|||
|
||||
/* Wait for pending handlers to complete or timeout */
|
||||
do {
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap,
|
||||
DCB_DHCSR,
|
||||
&cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK) {
|
||||
target->state = TARGET_UNKNOWN;
|
||||
return retval;
|
||||
|
@ -1119,7 +1362,7 @@ static int cortex_m_step(struct target *target, int current,
|
|||
}
|
||||
}
|
||||
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
|
@ -1197,8 +1440,8 @@ static int cortex_m_assert_reset(struct target *target)
|
|||
}
|
||||
|
||||
/* Enable debug requests */
|
||||
int retval;
|
||||
retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
int retval = cortex_m_read_dhcsr_atomic_sticky(target);
|
||||
|
||||
/* Store important errors instead of failing and proceed to reset assert */
|
||||
|
||||
if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN))
|
||||
|
@ -2142,11 +2385,13 @@ int cortex_m_examine(struct target *target)
|
|||
armv7m->debug_ap->tar_autoincr_block = (1 << 12);
|
||||
}
|
||||
|
||||
/* Enable debug requests */
|
||||
retval = target_read_u32(target, DCB_DHCSR, &cortex_m->dcb_dhcsr);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
cortex_m_cumulate_dhcsr_sticky(cortex_m, cortex_m->dcb_dhcsr);
|
||||
|
||||
if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) {
|
||||
/* Enable debug requests */
|
||||
uint32_t dhcsr = (cortex_m->dcb_dhcsr | C_DEBUGEN) & ~(C_HALT | C_STEP | C_MASKINTS);
|
||||
|
||||
retval = target_write_u32(target, DCB_DHCSR, DBGKEY | (dhcsr & 0x0000FFFFUL));
|
||||
|
@ -2344,7 +2589,7 @@ static int cortex_m_target_create(struct target *target, Jim_Interp *interp)
|
|||
static int cortex_m_verify_pointer(struct command_invocation *cmd,
|
||||
struct cortex_m_common *cm)
|
||||
{
|
||||
if (cm->common_magic != CORTEX_M_COMMON_MAGIC) {
|
||||
if (!is_cortex_m_with_dap_access(cm)) {
|
||||
command_print(cmd, "target is not a Cortex-M");
|
||||
return ERROR_TARGET_INVALID;
|
||||
}
|
||||
|
|
|
@ -213,6 +213,7 @@ struct cortex_m_common {
|
|||
|
||||
/* Context information */
|
||||
uint32_t dcb_dhcsr;
|
||||
uint32_t dcb_dhcsr_cumulated_sticky;
|
||||
uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */
|
||||
uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */
|
||||
|
||||
|
@ -237,6 +238,8 @@ struct cortex_m_common {
|
|||
const struct cortex_m_part_info *core_info;
|
||||
struct armv7m_common armv7m;
|
||||
|
||||
bool slow_register_read; /* A register has not been ready, poll S_REGRDY */
|
||||
|
||||
int apsel;
|
||||
|
||||
/* Whether this target has the erratum that makes C_MASKINTS not apply to
|
||||
|
@ -251,6 +254,19 @@ target_to_cm(struct target *target)
|
|||
struct cortex_m_common, armv7m);
|
||||
}
|
||||
|
||||
static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m)
|
||||
{
|
||||
return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC;
|
||||
}
|
||||
|
||||
static inline bool is_cortex_m_with_dap_access(const struct cortex_m_common *cortex_m)
|
||||
{
|
||||
if (!is_cortex_m_or_hla(cortex_m))
|
||||
return false;
|
||||
|
||||
return !cortex_m->armv7m.is_hla_target;
|
||||
}
|
||||
|
||||
int cortex_m_examine(struct target *target);
|
||||
int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
||||
int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
||||
|
|
|
@ -1416,8 +1416,7 @@ COMMAND_HANDLER(handle_etm_config_command)
|
|||
|
||||
for (i = 0; etm_capture_drivers[i]; i++) {
|
||||
if (strcmp(CMD_ARGV[4], etm_capture_drivers[i]->name) == 0) {
|
||||
int retval = register_commands(CMD_CTX, NULL,
|
||||
etm_capture_drivers[i]->commands);
|
||||
int retval = register_commands(CMD_CTX, NULL, etm_capture_drivers[i]->commands);
|
||||
if (retval != ERROR_OK) {
|
||||
free(etm_ctx);
|
||||
return retval;
|
||||
|
|
|
@ -214,6 +214,8 @@ static int adapter_target_create(struct target *target,
|
|||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
cortex_m->common_magic = CORTEX_M_COMMON_MAGIC;
|
||||
|
||||
adapter_init_arch_info(target, cortex_m, target->tap);
|
||||
|
||||
return ERROR_OK;
|
||||
|
@ -621,7 +623,7 @@ static int adapter_write_memory(struct target *target, target_addr_t address,
|
|||
return adapter->layout->api->write_mem(adapter->handle, address, size, count, buffer);
|
||||
}
|
||||
|
||||
static const struct command_registration adapter_command_handlers[] = {
|
||||
static const struct command_registration hla_command_handlers[] = {
|
||||
{
|
||||
.chain = arm_command_handlers,
|
||||
},
|
||||
|
@ -647,7 +649,7 @@ struct target_type hla_target = {
|
|||
.target_create = adapter_target_create,
|
||||
.target_jim_configure = adiv5_jim_configure,
|
||||
.examine = cortex_m_examine,
|
||||
.commands = adapter_command_handlers,
|
||||
.commands = hla_command_handlers,
|
||||
|
||||
.poll = adapter_poll,
|
||||
.arch_state = armv7m_arch_state,
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
|
||||
#include <helper/align.h>
|
||||
#include <helper/time_support.h>
|
||||
#include <jtag/adapter.h>
|
||||
|
||||
#include "mips32.h"
|
||||
#include "mips32_pracc.h"
|
||||
|
@ -380,7 +381,7 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in
|
|||
}
|
||||
|
||||
unsigned num_clocks =
|
||||
((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
|
||||
((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000;
|
||||
|
||||
uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
|
||||
mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL);
|
||||
|
@ -1010,7 +1011,7 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are
|
|||
|
||||
unsigned num_clocks = 0; /* like in legacy code */
|
||||
if (ejtag_info->mode != 0)
|
||||
num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
|
||||
num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
jtag_add_clocks(num_clocks);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "mips64_pracc.h"
|
||||
|
||||
#include <helper/time_support.h>
|
||||
#include <jtag/adapter.h>
|
||||
|
||||
#define STACK_DEPTH 32
|
||||
|
||||
|
@ -1386,7 +1387,7 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info,
|
|||
/* like in legacy code */
|
||||
unsigned num_clocks = 0;
|
||||
if (ejtag_info->mode != 0)
|
||||
num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
|
||||
num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000;
|
||||
LOG_DEBUG("num_clocks=%d", num_clocks);
|
||||
for (i = 0; i < count; i++) {
|
||||
jtag_add_clocks(num_clocks);
|
||||
|
|
|
@ -881,7 +881,7 @@ done:
|
|||
int target_start_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t entry_point, uint32_t exit_point,
|
||||
target_addr_t entry_point, target_addr_t exit_point,
|
||||
void *arch_info)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
|
@ -925,7 +925,7 @@ done:
|
|||
int target_wait_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t exit_point, int timeout_ms,
|
||||
target_addr_t exit_point, int timeout_ms,
|
||||
void *arch_info)
|
||||
{
|
||||
int retval = ERROR_FAIL;
|
||||
|
|
|
@ -558,7 +558,7 @@ int target_run_algorithm(struct target *target,
|
|||
int target_start_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t entry_point, uint32_t exit_point,
|
||||
target_addr_t entry_point, target_addr_t exit_point,
|
||||
void *arch_info);
|
||||
|
||||
/**
|
||||
|
@ -569,7 +569,7 @@ int target_start_algorithm(struct target *target,
|
|||
int target_wait_algorithm(struct target *target,
|
||||
int num_mem_params, struct mem_param *mem_params,
|
||||
int num_reg_params, struct reg_param *reg_params,
|
||||
uint32_t exit_point, int timeout_ms,
|
||||
target_addr_t exit_point, int timeout_ms,
|
||||
void *arch_info);
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
adapter driver cmsis-dap
|
||||
|
||||
# Optionally specify the serial number of CMSIS-DAP usb device.
|
||||
#cmsis_dap_serial 02200201E6661E601B98E3B9
|
||||
# adapter serial 02200201E6661E601B98E3B9
|
||||
|
|
|
@ -20,7 +20,7 @@ echo "so it could be marked as working or fixed."
|
|||
adapter driver ftdi
|
||||
ftdi vid_pid 0x0403 0x6010
|
||||
ftdi device_desc "FLOSS-JTAG"
|
||||
#ftdi serial "FJ000001"
|
||||
# adapter serial "FJ000001"
|
||||
|
||||
ftdi layout_init 0x0008 0x180b
|
||||
ftdi layout_signal nTRST -data 0x0010 -oe 0x0010
|
||||
|
|
|
@ -11,4 +11,4 @@ adapter driver jlink
|
|||
#
|
||||
# Example: Select J-Link with serial number 123456789
|
||||
#
|
||||
# jlink serial 123456789
|
||||
# adapter serial 123456789
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
adapter driver kitprog
|
||||
|
||||
# Optionally specify the serial number of the KitProg you want to use.
|
||||
#kitprog_serial 1926402735485200
|
||||
# adapter serial 1926402735485200
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
adapter driver aice
|
||||
aice desc "Andes AICE adapter"
|
||||
aice serial "C001-42163"
|
||||
# adapter serial "C001-42163"
|
||||
aice vid_pid 0x1CFC 0x0000
|
||||
aice port aice_usb
|
||||
reset_config trst_and_srst
|
||||
|
|
|
@ -17,4 +17,4 @@ st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0
|
|||
|
||||
# Optionally specify the serial number of usb device
|
||||
# e.g.
|
||||
# st-link serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
|
||||
# adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
|
||||
|
|
|
@ -13,4 +13,4 @@ hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374
|
|||
# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial
|
||||
# number reset issues.
|
||||
# eg.
|
||||
#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
|
||||
# adapter serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
|
||||
|
|
|
@ -14,4 +14,4 @@ hla_vid_pid 0x1cbe 0x00fd
|
|||
# Optionally specify the serial number of TI-ICDI devices, for when using
|
||||
# multiple devices. Serial numbers can be obtained using lsusb -v
|
||||
# Ex.
|
||||
#hla_serial "0F003065"
|
||||
# adapter serial "0F003065"
|
||||
|
|
|
@ -9,4 +9,4 @@ adapter driver xds110
|
|||
|
||||
# Use serial number option to use a specific XDS110
|
||||
# when more than one are connected to the host.
|
||||
#xds110 serial 00000000
|
||||
# adapter serial 00000000
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# script for GigaDevice gd32e23x Cortex-M23 Series
|
||||
|
||||
# https://www.gigadevice.com/microcontroller/gd32e230c8t6/
|
||||
|
||||
#
|
||||
# gd32e23x devices support SWD transports only.
|
||||
#
|
||||
source [find target/swj-dp.tcl]
|
||||
source [find mem_helper.tcl]
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME gd32e23x
|
||||
}
|
||||
|
||||
# Work-area is a space in RAM used for flash programming
|
||||
# By default use 4kB (as found on some GD32E230s)
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x1000
|
||||
}
|
||||
|
||||
# Allow overriding the Flash bank size
|
||||
if { [info exists FLASH_SIZE] } {
|
||||
set _FLASH_SIZE $FLASH_SIZE
|
||||
} else {
|
||||
# autodetect size
|
||||
set _FLASH_SIZE 0
|
||||
}
|
||||
|
||||
#jtag scan chain
|
||||
if { [info exists CPUTAPID] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
# this is the SW-DP tap id not the jtag tap id
|
||||
set _CPUTAPID 0x0bf11477
|
||||
}
|
||||
|
||||
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
# flash size will be probed
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME stm32f1x 0x08000000 $_FLASH_SIZE 0 0 $_TARGETNAME
|
||||
|
||||
# SWD speed (may be updated to higher value in board config file)
|
||||
adapter speed 1000
|
||||
|
||||
reset_config srst_nogate
|
||||
|
||||
if {![using_hla]} {
|
||||
# if srst is not fitted use SYSRESETREQ to
|
||||
# perform a soft reset
|
||||
cortex_m reset_config sysresetreq
|
||||
}
|
||||
|
||||
$_TARGETNAME configure -event examine-end {
|
||||
# Debug clock enable
|
||||
# RCU_APB2EN |= DBGMCUEN
|
||||
mmw 0x40021018 0x00400000 0
|
||||
|
||||
# Stop watchdog counters during halt
|
||||
# DBG_CTL0 |= WWDGT_HOLD | FWDGT_HOLD | STB_HOLD | DSLP_HOLD | SLP_HOLD
|
||||
mmw 0x40015804 0x00000307 0
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
# -*- mode: makefile -*-
|
||||
#
|
||||
default: _complain_
|
||||
include ./local.uses
|
||||
|
||||
%: _complain_
|
||||
|
||||
|
||||
_complain_:
|
||||
@echo ""
|
||||
@echo " Try the target: cygwin.buildtest or linux.buildtest "
|
||||
@echo ""
|
||||
|
||||
remove.install:
|
||||
rm -rf ${INSTALL_DIR}
|
||||
|
||||
.PHONY: remove.install
|
||||
|
||||
cygwin.buildtest:
|
||||
${MAKE} -f Makefile.ftd2xx clean all
|
||||
${MAKE} -f Makefile.openocd cygwin.easy.permutations
|
||||
${MAKE} -f Makefile.openocd mingw32.easy.permutations
|
||||
${MAKE} -f Makefile.libftdi all
|
||||
${MAKE} -f Makefile.openocd cygwin.libftdi
|
||||
|
||||
linux.buildtest:
|
||||
${MAKE} linux.easy.buildtest
|
||||
${MAKE} linux.ftd2xx_installed
|
||||
${MAKE} linux.ft2232_libftdi
|
||||
@echo ""
|
||||
@echo ""
|
||||
@echo "========================================"
|
||||
@echo " Linux Build Tests Complete "
|
||||
@echo "========================================"
|
||||
@echo ""
|
||||
@echo ""
|
||||
|
||||
|
||||
linux.easy.buildtest:
|
||||
@test -d openocd || (echo "Where the source to openocd?" && exit 1)
|
||||
${MAKE} -f Makefile.openocd bootstrap
|
||||
${MAKE} -f Makefile.ftd2xx all
|
||||
${MAKE} -f Makefile.openocd linux.easy.permutations
|
||||
|
||||
linux.ftd2xx_installed:
|
||||
${MAKE} remove.install
|
||||
${MAKE} linux.ftd2xx_installed.setup
|
||||
${MAKE} -f Makefile.openocd $@
|
||||
|
||||
linux.ft2232_libftdi:
|
||||
${MAKE} remove.install
|
||||
${MAKE} -f Makefile.libusb all
|
||||
${MAKE} -f Makefile.confuse all
|
||||
${MAKE} -f Makefile.libftdi all
|
||||
${MAKE} -f Makefile.openocd $@
|
||||
|
||||
# This target is used to "install" files from
|
||||
# the FTDICHIP.COM tar.gz unpack directory
|
||||
# into "a proper place" - where they should be found.
|
||||
linux.ftd2xx_installed.setup:
|
||||
mkdir -p ${INSTALL_DIR}/include
|
||||
mkdir -p ${EXEC_PREFIX}/lib
|
||||
@#
|
||||
@# Sanity check - make sure the .H file is findable
|
||||
@#
|
||||
@f=$(FTD2XX_LINUX_DIR)/ftd2xx.h && \
|
||||
test -f $$f || (echo "Error: $$f not found" ; exit 1)
|
||||
@#
|
||||
@# Header files are simple... just copy them.
|
||||
@#
|
||||
cp $(FTD2XX_LINUX_DIR)/ftd2xx.h $(PREFIX)/include/.
|
||||
cp $(FTD2XX_LINUX_DIR)/WinTypes.h $(PREFIX)/include/.
|
||||
@#
|
||||
@# .SO files are harder.
|
||||
@# (1) copy them, (2) make links
|
||||
@#
|
||||
cp $(FTD2XX_LINUX_DIR)/libftd2xx.so.$(FTD2XX_LINUX_VERSION) $(EXEC_PREFIX)/lib/.
|
||||
cd $(EXEC_PREFIX)/lib && rm -f libftd2xx.so.0
|
||||
cd $(EXEC_PREFIX)/lib && ln -s libftd2xx.so.$(FTD2XX_LINUX_VERSION) libftd2xx.so.0
|
||||
cd $(EXEC_PREFIX)/lib && rm -f libftd2xx.so
|
||||
cd $(EXEC_PREFIX)/lib && ln -s libftd2xx.so.$(FTD2XX_LINUX_VERSION) libftd2xx.so
|
||||
|
||||
|
||||
all.download:
|
||||
mkdir -p ${VIRGINS}
|
||||
${MAKE} -f Makefile.confuse download
|
||||
${MAKE} -f Makefile.libftdi download
|
||||
${MAKE} -f Makefile.ftd2xx download
|
||||
${MAKE} -f Makefile.libusb download
|
||||
|
||||
.PHONY: linux.buildtest \
|
||||
linux.easy.buildtest \
|
||||
linux.ftd2xx_installed \
|
||||
linux.ft22232_libftdi \
|
||||
linux.ftd2xx_installed.setup
|
|
@ -1,46 +0,0 @@
|
|||
# -*- mode: makefile -*-
|
||||
default: _complain_
|
||||
include ./local.uses
|
||||
|
||||
TARFILE_LOCAL=${VIRGINS}/confuse-${LIBCONFUSE_VERSION}.tar.gz
|
||||
TARFILE_URL =http://www.intra2net.com/de/produkte/opensource/ftdi/TGZ/confuse-${LIBCONFUSE_VERSION}.tar.gz
|
||||
|
||||
CONFUSE_SRC_DIR =${HERE}/confuse-${LIBCONFUSE_VERSION}
|
||||
CONFUSE_BUILD_DIR =${HERE}/confuse-build
|
||||
|
||||
download:
|
||||
wget -O ${TARFILE_LOCAL} ${TARFILE_URL}
|
||||
|
||||
unpack:
|
||||
rm -rf ${CONFUSE_SRC_DIR}
|
||||
tar xfz ${TARFILE_LOCAL}
|
||||
|
||||
clean::
|
||||
rm -rf ${CONFUSE_SRC_DIR}
|
||||
|
||||
configure:
|
||||
rm -rf ${CONFUSE_BUILD_DIR}
|
||||
mkdir ${CONFUSE_BUILD_DIR}
|
||||
cd ${CONFUSE_BUILD_DIR} && ${CONFUSE_SRC_DIR}/configure \
|
||||
--prefix=${PREFIX} \
|
||||
--exec-prefix=${EXEC_PREFIX}
|
||||
|
||||
clean::
|
||||
rm -rf ${CONFUSE_BUILD_DIR}
|
||||
|
||||
build:
|
||||
cd ${CONFUSE_BUILD_DIR} && ${MAKE}
|
||||
|
||||
install:
|
||||
cd ${CONFUSE_BUILD_DIR} && ${MAKE} install
|
||||
|
||||
all: unpack configure build install
|
||||
|
||||
_complain_:
|
||||
@echo ""
|
||||
@echo "Please try one of these targets: bootstrap, clean, configure, build, install"
|
||||
@echo " Or read the makefile and learn about the permutation test targets"
|
||||
@echo ""
|
||||
@echo "You also might find the download and unpack targets helpful."
|
||||
@echo ""
|
||||
@exit 1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue