Compare commits

...

439 Commits

Author SHA1 Message Date
Paul Fertser
7b8b2f9443 The openocd-0.9.0 release
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
2015-05-18 00:06:36 +03:00
Paul Fertser
d8917e0c89 NEWS: last pre-release changes
Change-Id: Ibeb9078d19023b8cae5c0371079d5e4e1b5e3c57
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2776
Tested-by: jenkins
2015-05-17 21:53:08 +01:00
Paul Fertser
c3976ac658 jtag/drivers/stlink: fix SRST issue with stlink-v1
Even though the latest firmware version for stlink-v1 supports "v2"
JTAG API, the hardware SRST handling is still broken; amend the check
accordingly.

Change-Id: I62c662cd7aa209d2d6e9fe260f5c0be81d0ce672
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2761
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-05-17 21:52:51 +01:00
Vincent Palatin
45eef3c23d psoc4: add support for Cypress CCG1 family
Add the identifiers to support the flash on the Cypress Type-C Port Controller
chips of the CCG1 family : http://www.cypress.com/ccg1/.

Tested successfully on CYPD1132-16SXI.

Change-Id: I3fe6283379e5bcab964afac31b547ef95535aa2c
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-on: http://openocd.zylin.com/2757
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-05-17 21:18:48 +01:00
Peter A. Bigot
a50f5afd06 nrf51: refine and extend known devices table
The notation Gx0 in the nRF51 Series Compatibility Matrix indicates that
the specified HWID is valid only for build code 0 of each chip, and for
subsequent builds the HWID will be different.  Replace the Gx0 notation
with G0 throughout, and add the missing HWID for nRF51422 QFAC A1
(present on the newer nRF51 developer boards).

See: https://www.nordicsemi.com/eng/nordic/download_resource/41917/5/55913589
See: https://devzone.nordicsemi.com/question/30774/mapping-hwid-to-revision-information/

Change-Id: I79d842137d41342db35904867c48b06fbc6fbc70
Signed-off-by: Peter A. Bigot <pab@pabigot.com>
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2593
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-05-17 21:18:14 +01:00
Karl Palsson
218747dbd3 docs: gdb_target_description defaults enabled
This has been the case since c6216201 in 2013

Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Change-Id: I70232a46e29951f05f02dec00e0695d761697aa5
Reviewed-on: http://openocd.zylin.com/2764
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-05-17 21:17:13 +01:00
Austin Morton
38cb629ddf server: avoid the tcl server crashing when there is no target
Since commit 1d0cf0df37
("server: tcl_notifications command") connecting to the tcl server
would terminate openocd. Fix this.

Change-Id: I36e2a7482f7db3a30ff7e9f969c3b6cda9599382
Signed-off-by: Austin Morton <austinpmorton@gmail.com>
Reviewed-on: http://openocd.zylin.com/2759
Tested-by: jenkins
Reviewed-by: Forest Crossman <cyrozap@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-05-17 21:17:02 +01:00
Paul Fertser
8de17eb65a manual: add missing usb blaster commands
Change-Id: Ie7fbb9f87a811c4add5b7c8f9581d5bbc90fa4f8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2772
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:15:34 +01:00
Paul Fertser
c6ba0a2240 manual: fix usb_blaster_pin command syntax and description
Change-Id: If3fbb2fe4f1842bea3962a6b903fd16aa9e8b545
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2771
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:15:24 +01:00
Paul Fertser
1583379fb9 README.Windows: clarify the kernel drivers installation
HID and composite devices need to be mentioned explicitly due to
windows oddities.

Change-Id: I7cdbaa50c60ceb1950c934e0249986d46c875cff
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2506
Tested-by: jenkins
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:15:13 +01:00
Paul Fertser
805604058b manual: reorder flash driver info
Put all the individual driver descriptions to where they really
belong, fix sectioning etc.

Change-Id: I94dc09e9a296ec57db4475f8dfb0a7d62a754aa4
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2770
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:14:43 +01:00
Paul Fertser
ee5ecb8a29 manual: fix all overfull and underfull hboxes
Change-Id: Id84f16de5a3d1907e196d13007a312593bb6670a
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2769
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:14:11 +01:00
Paul Fertser
98861c54be manual: remove the lists of config files
Directory listings are volatile and serve no purpose in the
manual. Just remove them.

Change-Id: I63d54ba209c29eafb6608cf406b8ce5d8e9ee6c8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2768
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-05-17 21:13:31 +01:00
Paul Fertser
abd7ad027f Restore -dev suffix
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
2015-04-24 18:56:30 +03:00
Paul Fertser
323320487f The openocd-0.9.0-rc1 release candidate
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
2015-04-24 18:12:24 +03:00
Paul Fertser
2e0023569f Add NEWS in preparation for the new release
Change-Id: I629158b59ff38f9b82a560f119a391bb97af43f2
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2701
Tested-by: jenkins
2015-04-24 16:08:30 +01:00
Paul Fertser
1da15d5bff jtag/drivers/ti_icdi: do not segfault when adapter can't be opened
Change-Id: Id3af8dfd18b13947bca4f3c89c2516ccbcef60b6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2742
Tested-by: jenkins
2015-04-24 16:08:18 +01:00
Andreas Färber
5036b0e427 xmc4500-application-kit-general: Drop srst_nogate
Reset stopped working with this setting.

Change-Id: I98e8fafa48e0ab65dce8110870be422edf7b2fdb
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2727
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-24 15:13:03 +01:00
Jiri Kastner
5fa41168dd target/ti_tms570.cfg: added several JTAG IDs for TMS570LS family
from TI datasheets for whole cortex-r4 family added JTAG IDs

TMS570LS1227 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns192
	0x0B95502F

16/32-Bit RISC Flash Microcontroller, TMS5703137-EP (Rev. B)
http://www.ti.com/lit/pdf/spns230
	0x0D8A002F
	0x2D8A002F
	0x3D8A002F

RM48L952 16- and 32-Bit RISC Flash Microcontroller (Rev. B)
http://www.ti.com/lit/pdf/spns177
	0x0D8A002F
	0x2D8A002F
	0x3D8A002F

RM46L852 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns185
	0x0B95502F

RM48Lx30 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns176
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

RM46Lx30 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns182
	0x0B95502F

RM46Lx50 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns184
	0x0B95502F

TMS570LS04x/03x 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns186
	0x0B97102F

RM42L432 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns180
	0x0B97102F

RM46Lx40 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/
	0x0B95502F

TMS570LS12x5 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns191
	0x0B95502F

RM48Lx40 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns175
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

TMS570LS31x4/21x4 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns165
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

TMS570LS20216/20206/10216/10206/10116/10106 16/32-Bit RISC Flash Microcontroller (Rev. F)
http://www.ti.com/lit/pdf/spns141
	0x0B7B302F

TMS570LS31x5/21x5 16- and 32-Bit RISC Flash Microcontroller (Rev. B)
http://www.ti.com/lit/pdf/spns164
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

RM48Lx50 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns174
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

TMS570LS3137 16- and 32-Bit RISC Flash Microcontroller (Rev. B)
http://www.ti.com/lit/pdf/spns162
	0x0B8A002F
	0x2B8A002F
	0x3B8A002F

TMS570LS12x4 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns190
	0x0B95502F

TMS570LS1115 16- and 32-Bit RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns189
	0x0B95502F

TMS570LS11x4 16- and 32-BIT RISC Flash Microcontroller (Rev. A)
http://www.ti.com/lit/pdf/spns188
	0x0B95502F

Change-Id: Idf53a44851e1bb4bde4a74c64b65d4411e56da7c
Signed-off-by: Jiri Kastner <cz172638@gmail.com>
Tested-by: Jiri Kastner <cz172638@gmail.com>
Reviewed-on: http://openocd.zylin.com/2123
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-24 14:55:30 +01:00
Alex Ray
a1719e0048 TI TMS570 USB Kit board config
Split TMS570 target into LS31/LS21 and LS20/LS10 targets.
Board for the TMS570LS20SUSB Kit, which uses the TMS570 Cortex-R4 MCU from TI.
Tested attaching.

Change-Id: I1a69ac1ed800d0d6b7f9860c19cbd149e3e47620
Signed-off-by: Alex Ray <a@machinaut.com>
Reviewed-on: http://openocd.zylin.com/2089
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-24 14:55:16 +01:00
Paul Fertser
528197ba2c rtos/mqx: prevent crash with -rtos auto
Since mqx comes last in the list, with the auto option its
update_threads is called even though it wasn't detected.

This check should be removed from all the rtos helpers and moved to
the generic code, but better do it later all in one go.

Change-Id: If24ab42a58a468d90e9f12028d4c2fb76a9bc2e8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2741
Tested-by: jenkins
2015-04-24 14:49:06 +01:00
Paul Fertser
68101e67ac target/cortex_a: examination should be done every time it's asked for
It was observed on AM437x that after every reset the target's debug
regions are unpowered. To be able to properly communicate with the
target and perform cortex_a init debug access after a reset event the
examination need to be performed every time, not just on OpenOCD
start.

Change-Id: Idf272e127ee88341e806ee00df154eade573451d
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2723
Tested-by: jenkins
Reviewed-by: Felipe Balbi <balbi@ti.com>
2015-04-24 14:47:16 +01:00
Paul Fertser
f7f9a37fa6 target: try to reexamine even when polling fails
After intermittent connection failures or target power failures it
might be necessary to try reexamination even when polling fails. This
should make communication with Cortex-A targets more reliable.

This was runtime tested with stlink attached to an stm32l1 and an FTDI JTAG
adapter attached to an stm32f1 target.

Change-Id: I38c4db8124b7f4bbf53ddda53c13273449f49c15
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2721
Tested-by: jenkins
Reviewed-by: Felipe Balbi <balbi@ti.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Andreas Färber <afaerber@suse.de>
2015-04-24 14:46:59 +01:00
Paul Fertser
0d50dfe318 rtos: fix print format specifiers
Exposed by arm-none-eabi build.

Change-Id: I657c642249aa83403f93132d1e28713aee692c30
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2724
Tested-by: jenkins
2015-04-24 14:46:19 +01:00
Simon Qian
2d4ae3f4c8 configure the SWD frequency when setting adapter speed in SWD mode for versaloon
Change-Id: I99cdc11ba1442e4c9efaa0f1de8e7089ec725e14
Signed-off-by: Simon Qian <openocd@versaloon.com>
Reviewed-on: http://openocd.zylin.com/2608
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-16 20:30:49 +01:00
Andrey Yurovsky
2cf48d2c79 flash: at91samd: add SAML21 support, fix part ID issue
This adds support for the new Atmel SAML21 family of low-power Cortex
M0+ devices.  Their Flash controller is essentially the SAMDxx one so
the change consists of adding the new part IDs.  Unfortunately the
device ID logic had a couple of mistakes in it that did not affect
anything on SAMD2x devices (due to 0 values expected there) but that is
a problem on L21, it's therefore addressed here and things should now
match the datasheets.

Tested on Amtel SAML21 Xplained Pro development kit against the included
SAML21J18A there.  Also tested for regressions on a SAMD20 and SAMD21
using their dev kits.

Change-Id: I768f75e064b8656c15148730dacaa4c3acfc4101
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2690
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-16 20:30:34 +01:00
Uwe Bonnes
4ed3a1efa2 stlink_usb.c: Decode some more errors.
Change-Id: I637cb63bd39120554aa184eaa48fd00a4852359f
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2706
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-16 20:30:16 +01:00
Paul Fertser
03b72c367c flash/nor/mdr: add docs, remove memory leak on probe()
This adds the mandatory Info documentation for the driver as well as
the usage field.

As a clean up, this also includes freeing of the allocated memory
which results in a memory leak if probe is invoked multiple times.

Valgrind-tested.

Reported by Dmitry Shpak.

Change-Id: I2b1d9b9e8b069c6665b11d880b40ce19a1b26ce6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2694
Tested-by: jenkins
Reviewed-by: Дмитрий Шпак <disona@yandex.ru>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-16 20:29:06 +01:00
Marc Schink
14040c7a57 flash: efm32: Add support for EZR32LG and EZR32WG.
This patch was tested with an EZR32WG Starter Kit.

Change-Id: I0f7c619e715fe30e88e6da3bead0806dd3bce819
Signed-off-by: Marc Schink <openocd-dev@marcschink.de>
Reviewed-on: http://openocd.zylin.com/2700
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-16 20:28:56 +01:00
Spencer Oliver
8d86633eb7 docs: update OpenOCD url's to openocd.org domain
Change-Id: I8b55c8d12773a1c36f2fd2afeecf20a74e890064
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2698
Tested-by: jenkins
2015-04-16 20:28:21 +01:00
Spencer Oliver
788bdb49fd cmsis-dap: print vendor and product id on open failure
Change-Id: Iae7ed8d59a722b805536550a8033f5fb7c85c5fc
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2708
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
2015-04-16 20:28:03 +01:00
Mahavir Jain
ebbc9cb86c doc/openocd.texi: fix formatting for mrvlqspi driver documentation
* also included example for flash usage information

Change-Id: Icf9defc25d38bf24567b1708138b83a8de1e0497
Signed-off-by: Mahavir Jain <mjain@marvell.com>
Reviewed-on: http://openocd.zylin.com/2705
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-16 20:26:44 +01:00
Paul Fertser
68921d2316 tcl/target/stm32f3: fix reset init for stlink
Use mmw to manipulate only selected bits of the word. msb and mwb verify the
memory location and may error on PLLRDY set as a result of PLLON written.

Change-Id: I9a4c1e58f002a1e5e99be1bd34aac27ba65d111d
Reported-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2702
Tested-by: jenkins
2015-04-16 20:26:36 +01:00
Paul Fertser
e7e1396578 contrib/itmdump: add a hack to allow direct dumping of specific SWIT, fix timestamp
Currently itmdump is not a production-quality code hence this hack
seems to be appropriate.

More robust handling is possible with libswo-based swodec tool that's
available from http://git.zapb.de/ .

This adds a new command line option -d N where N is a stimulus number
you want to dump (counting from 1).

The idea here is that if you're interested to live-monitor just a
single stimulus port, you can use this utility directly. If one wants
to demultiplex the TPIU stream, the following is proposed:

1. Use https://gitorious.org/multiplex/multiplex utility that can
accept binary data from a file/pipe/stdin and arbitrary number of TCP
connections. It simply mirrors all the incoming data to all the
accepted connections;

2. Use socat to connect itmdump to the proxy mentioned in 1. and then
either dump the results to separate files or share via their dedicated
TCP ports.

Example script (inspired by http://openocd.zylin.com/#/c/1662/ ,
enables and disables specific itm ports on demand):

for i in `seq 0 31`; do
  while true; do
    socat -U TCP-LISTEN:$((8000+$i)),reuseaddr \
             SYSTEM:"echo itm port $i on | nc -q0 localhost 4444 > /dev/null; nc localhost 7777 | stdbuf -oL itmdump -d$((i+1))"
    echo itm port $i off | nc -q0 localhost 4444 > /dev/null
  done < /dev/null >&0 2>&0 &
done

Change-Id: Iaeb102436eaa5b106002083f2ffe758fb7bd83e5
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2537
Tested-by: jenkins
2015-04-16 20:25:30 +01:00
Paul Fertser
5387d616a3 Fix several format specifiers errors exposed by arm-none-eabi
Change-Id: I1fe5c5c0b22cc23deedcf13ad5183c957551a1b7
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2719
Tested-by: jenkins
2015-04-16 20:24:50 +01:00
Felipe Balbi
da7b65a93b board: ti_am43xx_evm: remove xds100v2 interface
GP and EPOS EVMs do not provide xds100v2 on board,
rather they have a pin header which can be used
to attach any debug pod the user might want.

Change-Id: I61678c50900fbe0fab500ea42f85ecde7a490ded
Reported-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2618
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-16 20:24:37 +01:00
Andreas Fritiofson
9dfb58e802 rtos: add instructions and helper code to make FreeRTOS work again
Run-time tested with FreeRTOS V8.1.2 (current version).

For the time being I propose this way of dealing with RTOSes that do
not export necessary information on their own.

I also suggest implementing a similar scheme for ChibiOS, exporting
the necessary struct fields' offsets via an OpenOCD-specific helper.

Change-Id: Iacf8b88004d62206215fe80011fd7592438446a3
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2347
Tested-by: jenkins
2015-04-16 20:23:46 +01:00
Andreas Fritiofson
6b2887e16a FreeRTOS: Make optional symbols optional
xSuspendedTaskList and xTasksWaitingTermination are only available for
some configurations. Missing optional symbols will have their addresses
remaining at zero so the corresponding lists will be skipped when
building the task list.

Change-Id: If330f5038d009298c3a14a4d2756db7105a30bc8
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2425
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-16 20:20:28 +01:00
Tomas Vanek
f3b1405fdd AT91SAM4L: handle reset run/halt in SMAP
This is a remake of http://openocd.zylin.com/1966
originally written by Angus Gratton <gus@projectgus.com>

ATSAM4L has a "System Manager Access Port" (SMAP) that holds the CPU
in reset if TCK is low when srst (RESET_N) is deasserted.
Without this change any use of sysresetreq or srst locks the chip
in reset state until power is cycled.

A new function smap_reset_deassert is called as reset-deassert-post event handler.
It optionally prepares reset vector catch and SMAP reset is released then.

Change-Id: Iad736357b0f551725befa2b9e00f3bc54504f3d8
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/2604
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 15:47:43 +01:00
Paul Fertser
bdfd5bbe04 target/arm_adi_v5, cortex_m: retry ahbap_debugport_init few times in case of an error
Some targets need arbitrary amount of time (usually not too long)
after reset (both sysresetreq and srst) to do initialisation, and
SWD/JTAG is not available during that. According to PSoC4 docs, the
debugger should try connecting until it succeeds.

Also ahbap_debugport_init might be necessary to perform after using
hardware srst too, so add it there (except for the targets that
support srst_nogate since they are very unlikely to need it).

Change-Id: I3598d5ff7b8e0bf3a5566a57dec4b0b2b243d297
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2601
Tested-by: jenkins
2015-04-14 13:19:09 +01:00
Paul Fertser
13ac3d556c target/cortex_a: emit a clear error message when dbgbase can't be detected
In some cases (the most obvious are TI's SoCs) ROM table lacks entries
for the cores, so OpenOCD has no way to determine what debug base to
use. Due to an error fixed in ec9ccaa288 it wasn't handled properly,
and OpenOCD would continue to try using dbgbase = 0, which happened to
work for e.g. AM437x.

This patch adds a clear indication to the user that to access such a
target, dbgbase must be set manually in the config.

Reported by Felipe Balbi on IRC.

Change-Id: Id8533e708f44b76550eb8b659564f5f45717c298
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2603
Tested-by: jenkins
2015-04-14 12:44:55 +01:00
Paul Fertser
eaa6d8f839 flash/nor/lpc2000: free allocated working area when target_write fails
In some circumstances (e.g. inappropriate jtag clock)
target_write_memory in lpc2000_iap_working_area_init might fail. The
allocated working area should be freed inside
lpc2000_iap_working_area_init in this error case.

This was leading to a weird segfault due to stack corruption later
when reset was executed.

Reported by quitte (Jonas Meyer).

Change-Id: Ia2ed42a9970a4d771727fd516a6eea88e9b859e2
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2696
Tested-by: jenkins
2015-04-14 12:41:26 +01:00
Paul Fertser
20a077eadb jtag/adi_v5_jtag: fix infinite recursion in jtagdp_transaction_endcheck()
Calling ahbap_debugport_init() is wrong here because the actions
performed by it might lead to jtagdp_transaction_endcheck errors thus
leading to infinite recursion.

The removed code is not needed now because target polling should lead
to reexamination automatically, and both cortex_a and cortex_m call
ahbap_debugport_init() as part of their target examine handler.

This was reported as a real life issue on IRC by Weaselweb with
Cortex-A target. Quitte reports similar results in some circumstances
(adapter_khz too high) with LPC17xx.

Change-Id: I7148022f76a1272b5262d251f2e807ffb1543547
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2697
Tested-by: jenkins
2015-04-14 12:39:02 +01:00
Paul Fertser
cf77040e1e flash/nor/lpc2000: properly free working area used in get_lpc2000_part_id()
The IAP working area needs to be freed here, just like in all the
other driver functions since an automatic local variable is used to
store a pointer to it.

This was reported by quitte (Jonas Meyer) on IRC as a strange totally
unrelated segfault after doing certain operations (leading to target
reset) from GDB. He has provided me with remote access to the specific
machine and configuration that exposed the issue, and after some
debugging it became apparent that a auto local variable (holding the
gdb connection pointer) gets overwritten somehow. Placing an
appropriate breakpoint just before the event and using a watchpoint
made the cause apparent: reset lead to freeing of all working areas,
and there was one holding a pointer to a variable that was auto local
in get_lpc2000_part_id().

Change-Id: I7e634d890135ca0f3b4b311e09e8385a03982bd6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2695
Tested-by: jenkins
2015-04-14 12:36:57 +01:00
Paul Fertser
e51d591641 jtag/startup.tcl: fix regression with autoselecting JTAG
This regression was introduced with d90b86d8. "transport select" doesn't
throw an error anymore and autoselects the first available transport on
its own.

Reported by moyix on IRC.

Change-Id: I3f303c0372e915931cca4b28af450694abc1a63e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2693
Tested-by: jenkins
2015-04-14 12:35:39 +01:00
Richard Braun
7090edc813 ChibiOS: fix crash on auto detection
The detection framework assumes rtos->symbols is dynamically allocated,
an assumption that the ChibiOS variant breaks by providing a raw statically
allocated symbol list.

Change-Id: I379bcc2af99006912608ddd3f646ff7085606f47
Signed-off-by: Richard Braun <rbraun@sceen.net>
Reviewed-on: http://openocd.zylin.com/2597
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 12:16:50 +01:00
Paul Fertser
19f219f731 Tcl exception codes cleanup, shutdown command amendments
This patch might influence openocd Tcl commands behaviour in subtle
ways, please give it a nice testing.

The idea is that if an OpenOCD Tcl command returns an error, an
exception is raised, and then the return code is propogated all the
way up (or to the "catch" if present). This allows to detect
"shutdown" which is not actually an error but has to raise an
exception to stop execution of the commands that follow it in the
script.

openocd_thread special-cases shutdown because it should then terminate
OpenOCD with a success error code, unless shutdown was called with an
optional "error" argument which means terminate with a non-zero exit
code.

Change-Id: I7b6fa8a2e24c947dc45d8def0008b4b007c478b3
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2600
Tested-by: jenkins
Reviewed-by: Juha Niskanen <juha.niskanen@haltian.com>
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
2015-04-14 12:11:48 +01:00
Juha Niskanen
33bb0fe619 helper: shutdown command should return with 0 exit status
Commit a35712a85c caused a regression where command

openocd -c "echo a1; shutdown; echo a2"

always returned non-zero exit status to operating system,
even when commands before shutdown all succeeded. This patch
attempt to fix this.

Change-Id: I3f478c2c51d100af810ea0171d2fd4c8fcc657f3
Signed-off-by: Juha Niskanen <juha.niskanen@haltian.com>
Reviewed-on: http://openocd.zylin.com/2589
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 12:10:18 +01:00
Paul Fertser
20fcd0729e jtag/tcl: fix incorrect memcpy in jim_newtap_expected_id
Found by clang static checker.

On the very first call of jim_newtap_expected_id() pTap->expected_ids
and expected_len are null, and there's nothing to copy. This patch
changes this cryptic code to use realloc() instead.

Change-Id: Ic0b5140d08257a906f15b55a2ae64db7bc06d5f1
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2562
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Tested-by: jenkins
2015-04-14 12:09:48 +01:00
Uwe Bonnes
2175bb149a turtelizer2-revC: Tested with real hardware.
Also some hints around deprecated tcl/interface/turtelizer2.cfg added.

Change-Id: Ifa57b49febffaeddd5d8ff0a48833d3544927b10
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2584
Tested-by: jenkins
Reviewed-by: Harald Kipp
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 12:07:22 +01:00
Nemui Trinomius
1cd3fdf2f6 lpc2000: Removed cmd51_can_xxxxb variables.
Current flash driver can fail to write across the sector boundary.
This patch fixes "thisrun_bytes" set to "cmd51_dst_boundary" value instead of "cmd51_can_xxxxb"

Referred to SevenW's post and fix,thanks.
http://sourceforge.net/p/openocd/mailman/openocd-devel/thread/fa32e7d6654df22470dc5f4a3dbc984a%40familiebenschop.nl/#msg33594152

Tested on below listed chips.
LPC810,LPC811,LPC812,LPC824,LPC1115,LPC1343,LPC1347,LPC1227,
LPC1769,LPC1788,LPC54102,LPC4088 and LPC2388.

Change-Id: If1c6a1daa58ca27c405bd959a784e599a7a8f4d4
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2607
Tested-by: jenkins
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 12:03:53 +01:00
Andreas Färber
39a7085d36 tcl/board: Add Infineon XMC 2Go config
Tested with "J-Link Lite-XMC4200 Rev.1 compiled Jan 10 2014 20:31:33".

Change-Id: Iefa9185372341d889db2b5f1f93bce126450b535
Cc: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2564
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:53:20 +01:00
Patrick Noffke
282bc28a6e Added Atmel SAM4SA16C chip (chip ID 0x28a70ce0).
Change-Id: I45e8e807a36c39940b910b3edb40698c7d8dabd6
Signed-off-by: Patrick Noffke <patrick@noffke.me>
Reviewed-on: http://openocd.zylin.com/2625
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:53:12 +01:00
Andreas Färber
e8aa3524d2 tcl/board: Add Infineon XMC1100 Boot Kit config
Tested with "J-Link Lite-XMC4200 Rev.1 compiled Jul 18 2014 17:28:26".

Change-Id: Icc03172cefe38f2217bf44a73f94f8a6fb93dfba
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2472
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:52:35 +01:00
Andreas Färber
a5844ace23 tcl/target: Add Infineon XMC1000 family target config
Basic target config, verified against XMC1100 AA/AB, XMC1200 AA/AB,
XMC1300 AA/AB manuals.

The default adapter_khz was tested with the XMC1100 Boot Kit.

Change-Id: Iff6ed52d875ccb83c0d4ff0d555b90e0f28b860c
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2471
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:52:20 +01:00
Andreas Färber
aee1b1d570 tcl/board: Add Spansion SK-FM4-176L-S6E2CC config
Works best after update to firmware v2.3.

Change-Id: Id2d3a0ae28bba014ee5338df9280fe39773c3398
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2570
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:51:32 +01:00
Andreas Färber
fd23fb4c6e tcl/target: Add Spansion FM4 config
Assembled by trial-and-error for an S6E2CC.

Change-Id: I317c12d24c9075ce3de286455fa3ee45731c5c81
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2569
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:50:44 +01:00
Ed Beroset
daf9bcf77f startup: Fixed measure_clk to return kHz instead of MHz.
The original code had iterated 10,000,000 times and taken the elapsed 
time divided by 10,000, to yield kHz which is mathematically correct 
only if we were measuring time in seconds, but we are measuring time in 
 milliseconds, so the correct divisor is actually 10,000,000.  Previous 
code would report 0.500 for actual measured speed of 500 kHz.

Change-Id: Iba4c4961fe3973e7ccfa6dfa11d606a966ceb50c
Signed-off-by: Ed Beroset <beroset@ieee.org>
Reviewed-on: http://openocd.zylin.com/2573
Tested-by: jenkins
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:50:03 +01:00
Ed Beroset
7a7086e644 em357: Corrected EM357 support including errata details
Original submitted code had only been tested with em358, but testing with
actual em357 revealed errors that this patch corrects.

Change-Id: I70cf31210de8ed84e3755a56e76261ad200322bb
Signed-off-by: Ed Beroset <beroset@ieee.org>
Reviewed-on: http://openocd.zylin.com/2581
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:48:50 +01:00
Uwe Kleine-König
e968fd1895 Cortex-A: Don't flush the data/unified cache if MMU is off
When the SCTLR has C set but M unset (i.e. Caching on, but MMU off) the cache
if effectively off. So only flush the cache if MMU is on, otherwise stale
entries might be committed to memory.

Change-Id: Iaff8b6f25b7a41ba838b91d45684c98f99fc0b27
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-on: http://openocd.zylin.com/2429
Tested-by: jenkins
Reviewed-by: Christopher Head <chead@zaber.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Vladimir Svoboda <ze.vlad@gmail.com>
2015-04-14 11:47:48 +01:00
Evan Hunter
0836a0fa21 RTOS: Add logging to FreeRTOS and general RTOS
Change-Id: I43d14f3b59daae7f90c344abdf71eaa8f74ef7ef
Signed-off-by: Evan Hunter <ehunter@broadcom.com>
Reviewed-on: http://openocd.zylin.com/2391
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:42:58 +01:00
Paul Fertser
d06b09595b tcl/interface/parport: default to sane value on non-windows systems
When using ppdev driver 0 is the most appropriate default value as it
corresponds to /dev/parport0. Raw port address is suitable only for
direct access (I think that's parport-giveio on windows).

Reported by danitool on IRC.

Change-Id: I983c22251de6601b433ad31aaf660fb664cee7e9
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2572
Reviewed-by: Andreas Färber <afaerber@suse.de>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:42:32 +01:00
Paul Fertser
ea85ed98be jtag/core: honour SRST timings in SWD mode
Since SWD is currently abusing the JTAG command queue for reset and
sleep handling (and all other operations are performed in a different
way), sleep needs to be forced explicitly to ensure correct timings.

Change-Id: I5b0da6cbb7d0560154e4077b261aa6828cefc892
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2591
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:41:54 +01:00
Jeff Ciesielski
7407046e3d tcl/board: Add Infineon XMC4500 Relax Kit config
Tested with "J-Link Lite-XMC4000 Rev.1 compiled Dec  7 2012 19:23:07"
on XMC4500 Relax Lite Kit V1.

Change-Id: Ib680a444fa4cadbf640afba15d607c0e6bd4ab2c
Signed-off-by: Jeff Ciesielski <jeffciesielski@gmail.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2567
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:38:19 +01:00
Jeff Ciesielski
58aee57883 tcl/board: Add Infineon XMC4200 Application Kit config
Change-Id: I3a946ba3745da651d470cd574222ba5c7147ac9d
Signed-off-by: Jeff Ciesielski <jeffciesielski@gmail.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2566
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:37:40 +01:00
Andreas Färber
df22965783 tcl/board: Add Infineon XMC4500 Application Kit configs
Tested CPU_45A-V2 (General Purpose) with ARM-USB-TINY-H (via SWD) and
with "J-Link Lite-Cortex-M V8 compiled Jul 17 2014 11:40:12" firmware.

Tested CPU_45B-V1-006 (SDRAM) with ARM-USB-TINY-H (via SWD) and
with "J-Link Lite-XMC4200 Rev.1 compiled Jul 18 2014 17:28:26" firmware.

Change-Id: I3451117606551671ec77722f6adf7d7a6a4bd576
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2481
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:36:58 +01:00
Andreas Färber
c048d1f7b1 tcl/target: Add Infineon XMC4000 family config
Base config, verified against XMC4500, XMC4400 and XMC4100/XMC4200 manuals.

Change-Id: I10907bdf307bc6d11dc5454bf5391758de49dc30
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2480
Tested-by: jenkins
Reviewed-by: Jeff Ciesielski <jeffciesielski@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-04-14 11:36:04 +01:00
Felipe Balbi
b1f3e89970 tcl: icepick: add icepick_d_set_coreid
this is just to avoid open coding that in
icepick_d_tapenable. Cleanup only, no functional
changes.

Change-Id: Iabd20291b7bdd95957afa1c74f52171789201227
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2624
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:23:56 +01:00
Felipe Balbi
c32f81f718 target: icepick: call icepick_c_setup
it also works on icepick_d.

Change-Id: I50c0c81286aae673c94ea77e47454ff48eab1668
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2623
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:22:47 +01:00
Felipe Balbi
b6cb48c212 target: icepick: switch over to icepick_c_router
Reusing what's already there to ease maintainability.

Change-Id: I2030581669c644e2d9d9f9968075ab6344445d04
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2622
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:22:07 +01:00
Felipe Balbi
1d8c36e16a tcl: target: am437x: pass coreid
This commit is only for the sake of completeness as
default coreid is zero. In any case, coreids 1-4 are
used for the different PRU cores inside the SoC.

Change-Id: I775f2f444b1a908ffaf7bdbc43bcc966f19668c4
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2621
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:21:05 +01:00
Felipe Balbi
beb61c6999 target: am437x: use more descriptive names
Use more descriptive names for JRC and DAPs
so they more closely match documentation.

For example there's no Cortex A9 DAP, that's
the DebugSS DAP where Cortex A9 target sits. In
that same DAP we have have ETM, STM and both
dual-PRU subsystems.

Change-Id: I0e66ebb6299763f96606fae3e4c62e5785c804f2
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2620
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:19:56 +01:00
Felipe Balbi
0c20f1ff3f target: am437x: fix DebugSS DAP ID
Main DAP (where Cortex A9 sits) ID is actually
0x46b6902f. Fix it.

Change-Id: Ifa3335186bcf60d264d4ecea477bfe2f5ca10ead
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2619
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:18:48 +01:00
Felipe Balbi
c8fe9f6b4c tcl: board: add AM437x IDK support
Add support for Texas Instruments AM437x
Industrial Development Kit support.

Change-Id: I33ed71c7392c3805a86cf2c8adce83c0e8aa323d
Tested-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2617
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:17:16 +01:00
Felipe Balbi
5df0dfb7f4 tcl: am437x: add reset-init event handler
this event handler will configure and lock PLLs
and configure DDR so platform is placed in usable
state.

Change-Id: Idd02f4c9789181d69578f8606ac3576ea1dd8a0b
Tested-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2616
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:15:57 +01:00
Felipe Balbi
d85a0a6a0c tcl: am437x: disable watchdog on reset-end
sometimes, watchdog might be left running and
it could expire in the middle of a debug session,
to prevent that, just make sure to disable watchdog
on reset-end if current state is 'halted'.

Change-Id: Ib4f2a2321cba17cd8c56ca3ae63114a563a6de90
Tested-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2615
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:11:52 +01:00
Felipe Balbi
92a01329c9 tcl: am437x: define registers to be used later
a later commit will implement a proper reset-init
handler to lock pll and configure ddr as we should.

Change-Id: I432cf28a5a944bfa83c20aed7298dbd29df30e38
Tested-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2614
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:09:41 +01:00
Felipe Balbi
f0d10751fa tcl: board: ti_am43xx_evm: follow xds100v2 requirements
xds100v2 asks us to call these three commands to
guarantee proper behavior, so do it.

Change-Id: Iecf9c148ce7c2082ef915b46eeb511ceea395cc3
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2613
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:07:21 +01:00
Felipe Balbi
03a661a52d tcl: board: ti_am437x_evm: select jtag transport
default already is jtag, but this silences a
warning during startup.

Change-Id: I94478327bbb259649500ef74a5b5c10d51e2a517
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2612
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 11:00:45 +01:00
Felipe Balbi
0baecf9943 tcl: target: am437x: use entire SRAM area
According to AM4379 TRM [1], table 2-1 L3 Memory Map,
we have a total of 256KiB and there's no reason not to
use it all.

[1] http://www.ti.com/lit/ug/spruhl7b/spruhl7b.pdf

Change-Id: I117f2afe721bc4e3f0df304d3542e1a91aa69d12
Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-on: http://openocd.zylin.com/2611
Tested-by: jenkins
Reviewed-by: Tom Rini <trini@konsulko.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-04-14 10:59:47 +01:00
Felipe Balbi
589affe35b tcl: target: am437x.cfg: pass correct dbgbase
Since commit ec9ccaa288 (arm_adi_v5: make dap_lookup_cs_component()
traverse subtables and handle multicore) AM437x devices can't be used
with OpenOCD anymore. The reason is that dbgbase used to be set to zero
before that commit and that just happens to work with AM437x devices.

A more robust solution is to pass correct dbgbase when creating the
target, which this commit does.

Signed-off-by: Felipe Balbi <balbi@ti.com>
Change-Id: Iaf2617804324de8094b25137943e08b84f14c75f
Reviewed-on: http://openocd.zylin.com/2602
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
2015-04-14 10:59:08 +01:00
DmitryShpak
d3c2679bcb target/target.c: fixed rp check bug in asynchronous flash write algorithm.
Bug in read pointer check within flash write algorithm made incorrect check
if block size is more than 4 bytes (bug was detected with 16 bytes block size).

Change-Id: I5b8e7ebca619a0a85ae6e9e496ff792248134d81
Signed-off-by: DmitryShpak <disona@yandex.ru>
Reviewed-on: http://openocd.zylin.com/2657
Tested-by: jenkins
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-04-02 00:18:25 +01:00
Mateusz Manowiecki
09ca5af4d0 jtag/drivers/ftdi.c: removed memory leak
swd_cmd_queue buffer memory leak removed

Change-Id: Iafcdf034d32a37d577b58b6256c8fd9b064ce228
Signed-off-by: Mateusz Manowiecki <segmentation@fault.pl>
Reviewed-on: http://openocd.zylin.com/2563
Tested-by: jenkins
Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:52:09 +00:00
Marian Cingel
06707fe159 doc: update RTOS section, add 'mqx' info
Change-Id: I20b93d49d275e6daaf5e39c49b4508c70c6fc56f
Signed-off-by: Marian Cingel <cingel.marian@gmail.com>
Reviewed-on: http://openocd.zylin.com/2592
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:47:16 +00:00
Uwe Bonnes
2af366259f Add configuration for EFM32 Gecko boards with Segger J-Link.
Tested with Tiny Gecko.

Change-Id: Iddb87170b6aaaf7f15d3c4517c8661dd6394be8f
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2585
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:40:57 +00:00
Mahavir Jain
f618725e1a flash/nor: mrvlqspi: fix printf formatting issues
Change-Id: I74cfce7bb8dbc13fbc3005b5a96213417f93a9f2
Signed-off-by: Mahavir Jain <mjain@marvell.com>
Reviewed-on: http://openocd.zylin.com/2577
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-03-25 21:39:48 +00:00
Angus Gratton
d90b86d8e3 transport: make 'transport select' auto-select the first available transport if not set
This should allow most of the existing configurations for older
versions to remain compatible without forcing the user to change his
or her config to explicitly select transport.

Also in some circumstances can remove the need to chain a "-c transport
select X" when building custom configs on the command line, which seems
like a common new user pitfall.

Change-Id: Ic87a38c0b9b88e88fb6d106385efce2f39381d3d
Suggested-by: Petteri Aimonen <jpa@git.mail.kapsi.fi>
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2551
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:32:49 +00:00
Paul Fertser
492bab62ab target/adi_v5_swd, cortex_m: properly handle more cases requiring reconnect
This brings SWD reconnection procedure in line with the ARM
documentation and changes cortex_m reset procedure to make use of it.

The motivation behind this patch is to make SAM4L "reset" and "reset
halt" properly without SRST. The complication here is that EDBG issues
an additional read of DP_RDBUFF automatically right after writing
SYSRESETREQ, that leads to a FAULT which needs to be dealt with
properly. With this patch the very first ahbap_debugport_init DAP
access will make SWD layer properly reinitialise the link before
continuing.

Runtime tested with mbed CMIS-DAP + KL25 only.

Change-Id: Ic506f9db30931dfa60860036b83f73b897975909
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2596
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:32:06 +00:00
Paul Fertser
ef02b69b14 drivers/cmsis-dap: port to common SWD framework
Valgrind-tested.

Comparison of flashing performance on an FRDM-KL25Z board running mbed
CMSIS-DAP variant, 5MHz clock, old driver:

wrote 28096 bytes from file demo.elf in 26.833590s (1.023 KiB/s)
verified 27264 bytes in 1.754972s (15.171 KiB/s)

this implementation:

wrote 28096 bytes from file demo.elf in 3.691939s (7.432 KiB/s)
verified 27264 bytes in 0.598987s (44.450 KiB/s)

Also tested "Keil ULINK-ME CMSIS-DAP" with an STM32F100 target, 5MHz
clock, results reading from flash, old driver:

dumped 131072 bytes in 98.445305s (1.300 KiB/s)

this implementation:

dumped 131072 bytes in 8.242686s (15.529 KiB/s)

Change-Id: Ic64d3124b1d6cd9dd1016445bb627c71e189ae95
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2356
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 21:31:09 +00:00
Paul Fertser
1bc6a81138 tcl/board/twr-k60f120m: remove useless flash bank 0 definition
Since the very first flash bank is already defined in target/kx.cfg,
there's no sense in repeating it.

Reported and tested by Richard Braun.

Change-Id: I417b7072b5e6675ddbf824446e7581b8b7da8f4b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2595
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 20:48:11 +00:00
Paul Fertser
082170292b flash/nor/kinetis: do not attempt mass-erase in place of a bank erase
Many kinetis parts come in multi-bank configuration, so this
optimisation here can't be performed safely.

Investigated and fixed by Richard Braun.

Change-Id: I2b56614b47951595c403a1a8edd3afe11b85679b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2594
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-25 20:47:46 +00:00
Paul Fertser
6819468a78 armv7m_trace, stlink: provide APIs to capture trace with an adapter
Change-Id: I9d193dd5af382912e4fe838bd4f612cffd11b295
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2540
Tested-by: jenkins
2015-03-25 20:46:59 +00:00
Paul Fertser
a09a75653d armv7m: add generic trace support (TPIU, ITM, etc.)
This provides support for various trace-related subsystems in a
generic and expandable way.

Change-Id: I3a27fa7b8cfb111753088bb8c3d760dd12d1395f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2538
Tested-by: jenkins
2015-03-25 20:46:43 +00:00
Uwe Bonnes
3e1dfdcb85 stm32l1.cfg: Add missing dash to fix f7394049d3 commit.
Change-Id: Ifeb2d4fc2b43813edbc6fe2cf08bfd4c55cd1e86
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2590
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-03-10 07:35:37 +00:00
Andreas Fritiofson
8d80a25410 tcl: Add default hooks for STM32F3x
Keep clocks running in low power modes. Stop watchdogs from interfering
with the debug session. Set up PLL and increase clock at reset init.

Change-Id: I984d2018f7d47a1042f1e12894563154fa7b566c
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2196
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 09:20:09 +00:00
Paul Fertser
571db89aa1 flash/nor/stellaris: allow to recover a locked device that can't be examined
Change-Id: I28536184053e2d1ba906620e728f7fad6ba39f0a
Reported-by: Ed Beroset <beroset@mindspring.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2552
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Ed Beroset <beroset@ieee.org>
2015-03-09 08:58:16 +00:00
Andreas Färber
5aa08f7851 jlink: Add variant "J-Link Lite-XMC4000"
Avoids "J-Link hw type unknown 0x10" on the Infineon Relax Lite Kit.

Change-Id: I3091623ead2e84b67ac20d9866307ccbb3f26f66
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2568
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 08:46:50 +00:00
Andreas Färber
353695582f jlink: Add variant "J-Link Lite-XMC4200"
Avoids "J-Link hw type unknown 0x11" on various Infineon boards.

Change-Id: If20b9e21110d2acc02be57f5faf28c5e6a39e2c9
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2565
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 08:46:26 +00:00
Paul Fertser
2d998c0944 server, target, cortex_m: add deinit_target to the API to free resources
This should facilitate dynamic target creation and removal.

Currently it helps with getting 0 bytes lost report from Valgrind on
exit (after talking to a nucleo board). However, 1,223,886 bytes in
5,268 blocks are still reachable which means the app holds pointers to
that data on exit. The majority comes from the jtag command queue,
there're also many blocks from TCL command registration.

Change-Id: I7523234bb90fffd26f7d29cdd7648ddd221d46ab
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2544
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-03-09 08:34:46 +00:00
Paul Fertser
ebe9b7a661 target/target: call event handlers around examine when polling resumes
The target might be using Tcl examine-start and examine-end handlers,
they need to be called when the target gets reexamined after polling
succeeds again.

Change-Id: I371380c6f3c427ec7a0206d73426f6589f18a9bd
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2536
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-03-09 06:41:58 +00:00
Paul Fertser
889b246d93 hla/hla_interface: call HLA layout API close() on quit
This bug was exposed by Valgrind.

Change-Id: I2e2bc036b49ca3ff22f78f765ee4537763350096
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2543
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:40:50 +00:00
Paul Fertser
11b6ab90fb target/cortex_m: do not leak memory on reexamination
This bug was exposed by Valgrind.

Change-Id: If50878664d928c0a44e309ca1452089c1ac71466
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2542
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:40:21 +00:00
Paul Fertser
b71ae9b1a7 target: fix timer callbacks processing
Warning, behaviour change: before this patch if a timer callback
returned an error, the other handlers in the list were not called.

This patch fixes two different issues with the way timer callbacks are
called:

1. The function is not designed to be reentrant but a nested call is
possible via: target_handle timer event -> poll -> target events
before/after reexaminantion -> script_command_run ->
target_call_timer_callbacks_now . This patch makes function a no-op
when called recursively;

2. The current code can deal with the case when calling a handler
leads to its removal but not when it leads to removal of the next
callback in the list. This patch defers actual removal to consolidate
it with the calling loop.

These bugs were exposed by Valgrind.

Change-Id: Ia628a744634f5d2911eb329747e826cb9772e789
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2541
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:40:04 +00:00
Paul Fertser
ca0e237d39 arm11: initialise DPM and register cache before reading DSCR for the first time
When target was already halted during the initial examination,
arm11_check_init() was trying to read, store and interpret DSCR
contents before the DPM structure is initialised. This caused
a segfault like described on
http://sourceforge.net/apps/trac/openocd/ticket/65 .

This is a totally untested attempt to fix this issue.

Change-Id: I2fff115679a3f0023e7a88c749ccb5f045d6cf01
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2043
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:39:28 +00:00
Paul Fertser
d019080dfa stlink: avoid null pointer dereference in stlink_usb_close()
Otherwise it happens if stlink can not be opened on start.

Change-Id: I7088f10e61508dae230eccfe576a51498c92f5b8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2550
Tested-by: jenkins
Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-03-09 06:38:52 +00:00
Franck Jullien
b4b1976e4e openrisc: add profiling function
Change-Id: Ifee89b289069590e6086a4713b165989578e29ec
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/2494
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:38:15 +00:00
Paul Fertser
217403ce09 armv7m: do not access FPU registers when not present
This is runtime and valgrind tested with l0, l1 and f3 hla boards.

Change-Id: I49b0b042253d5f3bf216997f0203583db319fe23
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2516
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:36:49 +00:00
Paul Fertser
dccbf7d88d armv7m: add FPU registers support
This patch adds the fpv4-sp-d16 registers to the armv7m register set.

The work is inspired by Mathias K but takes a different approach:
instead of having both double and single presicion registers in the
cache this patch works only with the doubles and counts on GDB to
split the data in halves whenever needed.

Tested with HLA only (on an STM32F334 disco board).

Currently this patch makes all ARMv7-M targets report an FPU-enabled
target description to GDB. It shouldn't harm if the user is not trying
to access non-existing FPU. However, the plan is to make this depend
on actual FPU presence later.

Change-Id: Ifcc72c80ef745230c42e4dc3995f792753fc4e7a
Signed-off-by: Mathias K <kesmtp@freenet.de>
[fercerpav@gmail.com: rework to fit target description framework]
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/514
Tested-by: jenkins
Reviewed-by: Peter Stuge <peter@stuge.se>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:36:30 +00:00
Paul Fertser
ecf97f7c96 jimtcl: update to 0.76 release version
It makes sense to use the latest released version to ensure
compatibility.

Change-Id: I0957f927d825fa6fb6a1594ca17bcca46ee6c1a6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2522
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:35:33 +00:00
pierre Kuo
5e005f4129 target/arm_disassembler: add exception related disassembly
Add ERET/HVC/SMC disassebly decoding flow, below is testing result

> mdw 0x5c 4
0x0000005c: e160006e e1400072 e1600073 ee110f10
> arm disassemble 0x5c 4
0x0000005c	0xe160006e	ERET
0x00000060	0xe1400072	HVC 0x0002
0x00000064	0xe1600073	SMC 0x0003
0x00000068	0xee110f10	MRC p15, 0x00, r0, c1, c0, 0x00
>

Change-Id: I1beccff885b5b37747edd0b2e9fb2297ce466a00
Signed-off-by: pierre Kuo <vichy.kuo@gmail.com>
Reviewed-on: http://openocd.zylin.com/2548
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:35:21 +00:00
Paul Fertser
e00a56bede target/cortex_a: remove dead assignment
Found by clang static checker.

Change-Id: I77b0dc18188328fdb28d07b9e5c52e06182d9e2b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2561
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:34:01 +00:00
Paul Fertser
77d2cad9fc flash/nor/stellaris: remove dead assignment
Found by clang static checker.

Change-Id: Ifa58ba383092341c7343916e5cc8ec3c72ab2f60
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2560
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:33:53 +00:00
Paul Fertser
cc50a42882 flash/nor/sim3x: remove dead assignment
Found by clang static code checker.

Change-Id: Ic1370f8d7a48f08da6514afec5aacde38af7dfb6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2559
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:33:43 +00:00
Paul Fertser
01b42b2e7c contrib/itmdump: fix UB in show_swit, and few compile warnings
Change-Id: I1c5c99f190f7b4d405dc6fa06533e7ff37a652ec
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2533
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:32:17 +00:00
Karl Palsson
552c8c5971 contrib: itmdump: fix incorrect format printf
Change-Id: I29100e4b284e031613586a66daa74987d86ac9e1
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2449
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:32:03 +00:00
Austin Morton
1d0cf0df37 server: tcl_notifications command
Implements async target notifications to the tcl server

Change-Id: I4d83e9fa209e95426c440030597f99e9f0c3b260
Signed-off-by: Austin Morton <austinpmorton@gmail.com>
Reviewed-on: http://openocd.zylin.com/2336
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:30:30 +00:00
Marian Cingel
c50047bb41 rtos: Freescale MQX rtos support
ARMv7E-M (CortexM4) architecture

- fix position offset of r2,r3 registers on exception stack
- switch 'calloc' arguments
- remove prototypes of internal function and typedefs
- add NULL check for alloc functions
- remove last line of license "Franklin Street, Fifth Floor"
  because of 'checkpatch' validation
- environment: jlink + twrk60n512

Change-Id: I70840ded15b17dd945ca190ce31e2775078da2d9
Signed-off-by: Marian Cingel <cingel.marian@gmail.com>
Reviewed-on: http://openocd.zylin.com/2353
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-03-09 06:29:17 +00:00
Matthijs van Duin
dab4adb5ec tcl/interface/ftdi/xdsv2: fix and clarify EMU* signals
The signal names are changed for consistency with TI's docs and
sources.

Change-Id: Ic5c5314daa20f6f610be8a848399f951d47aa137
Signed-off-by: Matthijs van Duin <matthijs@rinnic-vaude.nl>
Reviewed-on: http://openocd.zylin.com/2231
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:27:45 +00:00
Uwe Bonnes
f7394049d3 stm32l1.cfg: Add ID Code of Cat.2 devices.
Change-Id: I4eb5020858c1896e294d633213f3df3fa45b6250
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2517
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
2015-03-09 06:26:45 +00:00
Uwe Bonnes
a20db2d205 stm32f3x.cfg: Remove duplicate item.
Change-Id: I812c36688add73fab2e74fc112c733c5d3c201a6
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2554
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:26:28 +00:00
Nemui Trinomius
199acf668e lpc2000: Add LPC407x/8x flash size auto detection
This patch adds auto flash size detection for LPC407x/8x series.

Tested on below listed chips.
LPC4088
LPC1788(regression test)

Change-Id: I82f62678a04eac9b84658bd6d1cfdf45be64c931
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2555
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Jens Bauer <jens@gpio.dk>
2015-03-09 06:26:06 +00:00
Olivier Esver
17bcbdaef1 atmega: add support for the at90usb128 flash
Add support for the at90usb128 flash (tested on the RZUSBstick)

Change-Id: Ic042d7c403b20a5cc533da00c30ae6e2139bbd10
Signed-off-by: Olivier Esver <olg.esver@gmail.com>
Reviewed-on: http://openocd.zylin.com/2557
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:25:52 +00:00
Mateusz Manowiecki
5087a95548 Added system signal handling to Linux version
(with http://www.cons.org/cracauer/sigint.html in mind)

Change-Id: I15f559bc1122a408c3fb9338ba55c16fab3187e1
Signed-off-by: Mateusz Manowiecki <segmentation@fault.pl>
Reviewed-on: http://openocd.zylin.com/2443
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:25:45 +00:00
Mateusz Manowiecki
ef0fa97a71 jtag/drivers/buspirate: add JTAG_STABLECLOCKS cmd
Solution found on the internet

Change-Id: Ied6f7d9b28131a7ac83b203e4c64d4e9ffec0595
Signed-off-by: Mateusz Manowiecki <segmentation@fault.pl>
Reviewed-on: http://openocd.zylin.com/2496
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:25:21 +00:00
Arne Wichmann
e3b43b77e9 target & board: AT91SAM7A2 and Olimex SAM7-LA2
Initial Support for AT91SAM7A2 on Olimex SAM7-LA2 board.
The board seems not to be able to reset into halted mode, as srst is
connected to NRESET of the cpu (configured srst_pulls_trst).
JTAG RCLK is connected to CLK.
Tested with interface/ftdi/olimex-arm-usb-ocd-h.cfg.

Change-Id: I2bdd67e3683e45f1119c5850bad294aa107891d8
Signed-off-by: Arne Wichmann <arne.wichmann@gmail.com>
Reviewed-on: http://openocd.zylin.com/2318
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-03-09 06:25:03 +00:00
Tomas Vanek
90ae846fc4 psoc4 flash driver: cleaned printf PRI... formats
Failed build on Mac OS X 10.10.2 was reported in OpenOCD-devel.
Cleaning types and printf formats. uint32_t prefered for flash/sector sizes.
2 minor changes in comments.
Removed redundant bracket.

Change-Id: Ia06b77af59c2c0ffd10869a4b263a760ca8b0a7a
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/2558
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
2015-02-28 05:47:57 +00:00
Theodore A. Roth
db8029bc26 nrf51: Update known devices table.
Added new entries to the nrf51_known_devices_table array. New entries
are documented in the "nRF51 Series Compatability Matrix V1.0" found on
the Nordic Semi web site. Reordered entries to match the order found in
the document.

Also added an entry for an undocumented hwid discovered while flashing
the PCA10031 and PCA10028 dev boards.

Change-Id: Icca7da103d437dc28e651f27ab937fe953b9aac9
Signed-off-by: Theodore A. Roth <troth@openavr.org>
Reviewed-on: http://openocd.zylin.com/2514
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-24 15:23:17 +00:00
dmitry pervushin
73867c260a flash/nor/spi: add GigaDevice SPI flash
Signed-off-by: dmitry pervushin <dpervushin@gmail.com>
Change-Id: I5a239dc67754ef4be1d9ec36186f434b09aa1e25
Reviewed-on: http://openocd.zylin.com/2530
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-24 14:48:37 +00:00
Paul Fertser
40d6e88268 cfg: add board and target configs for TI SimpleLink Wi-Fi CC3200 LaunchPad
Change-Id: I4396ee737c1dad380aa23894bbd1faf75f26d072
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2465
Tested-by: jenkins
2015-02-22 19:00:34 +00:00
Uwe Bonnes
be97da76ab Provide genuine F3 nucleo config and source it for STM32F334 Discovery board.
The F334 disco board has a stlink V.2-1 as F3 nucleo boards. Normal F3 disco
boards use stlink v2 and can't ne used.

Change-Id: I77ebef93b184592f25ff18bb2da776d636f60ff0
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2434
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 17:59:55 +00:00
Oleksij Rempel
2b0beed4b1 tcl/target|board: add configs for Alphascale asm9260t
This adds configs for Alphascale asm9260t ARM based SoC and
Evaluation Kit based on this chip.

Change-Id: Id8d3a1ef204e3ae84540c2693e3d62650ba82f73
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/2515
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 17:57:02 +00:00
Robert P. J. Day
41124ea992 Remove long-deprecated "target count" and "target number" commands.
Given that the manual states that these two subcommands are
deprecated and were scheduled to be removed back in 2010,
remove them and the corresponding documentation from the
manual.

Change-Id: Iaac633349d7fcb8b7f964109c7d26dd0cc5fc233
Signed-off-by: Robert P. J. Day <rpjday@crashcourse.ca>
Reviewed-on: http://openocd.zylin.com/1860
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 17:56:16 +00:00
Andreas Fritiofson
10331d2007 cfg: Fix Kinetis kwikstik/kx config
The flash definition belongs in the target cfg. Add some working area
and suitable reset_config.

Make kx.cfg more similar to klx.cfg.

Disable rclk as it is dead slow and a fixed 1MHz clock seems to work.

Change-Id: I8328f179c3a33be64403da93616abb48651bdfe6
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2227
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 16:23:48 +00:00
Jean-Christian de Rivaz
e290cb76c8 Add SWD protocol support to sysfsgpio
Based on the initial work on bcm2835gpio.c by Paul Fertser with many
additions. Modifications to the GPIO handling was minimal in this
patch. A more big modification is required before cleanup the
interface between bitbang and sysfsgpio.

Change-Id: I54bf2a2aa2ca059368b0e0e105dff6084b73d624
Signed-off-by: Jean-Christian de Rivaz <jc@eclis.ch>
Reviewed-on: http://openocd.zylin.com/2438
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 16:21:15 +00:00
Jean-Christian de Rivaz
e971c7f423 Add SWD protocol support to bitbang
This is based on the initial work by Paul Fertser with addition of the
switch sequences and new ACK handling.  In case of WAIT response, the
sticky bits are cleared and the last operation is repeated. The ACK
handling is based on the interpretation of the 8 February 2006 ARM
Debug Interface v5 Architecture Specification

Change-Id: Id50855b1ffff310177ccf9883dc9eb0d1b4458c8
Signed-off-by: Jean-Christian de Rivaz <jc@eclis.ch>
Reviewed-on: http://openocd.zylin.com/2437
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-22 16:17:49 +00:00
Matej Kupljen
750f8cd0c5 gdb_server: ignore stray + in ACK mode
I couldn't make OpenOCD to work with GDB. I was always getting this in GDB:
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Malformed response to offset query, timeout
(gdb)
While debugging gdb remote protocol, I have seen that gdb responds with:
w ++$?#3f
And those two '+' seems to confuse the OpenOCD parser, if it sees another
'+' sign it emits the DEBUG output and sets the noack_mode to 2. The
problem is that we weren't even IN noack mode, this was set to 0 and then
it explicitly sets it to 2 and thus turning the noack mode on.

Change-Id: If267c9226e57fa83121ded09cf69829f8f0b4b93
Signed-off-by: Matej Kupljen <matej.kupljen@gmail.com>
Reviewed-on: http://openocd.zylin.com/2545
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-22 16:16:06 +00:00
Uwe Bonnes
db83fb307b cortex_m: Add Cortex-M0 identification to ROM-table display.
Change-Id: Id7715a83ba9793844475629aaffd10a81ce586b6
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2549
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Stian Skjelstad <stian@nixia.no>
2015-02-22 16:14:36 +00:00
Christopher Head
0228f8e827 Cortex A: fix extra memory read and non-word sizes
Without this patch, to perform a memory read, OpenOCD first issues an
LDC instruction into DBGITR in Stall mode (thus executing the
instruction), then switches to Fast mode and reads from DBGDTRTX once
for each word to transfer.

At the very end of the transfer, the final Fast mode read of DBGDTRTX
has, as always, the side effect of re-issuing the LDC instruction. This
causes two problems:

(1) If the word immediately beyond the end of the requested region is
inaccessible, this spurious LDC will cause a fault. On a fast CPU, the
LDC will finish executing by the time the poll of DSCR takes place,
failing the entire memory read. On a slow CPU, the LDC might finish
executing later, leaving an unexpected and confusing sticky fault lying
around for the next operation to see.

(2) If the LDC succeeds, it will leave the loaded word in DBGDTRTX, thus
setting DBGDSCR.TXFULL=1. The cortex_a_read_apb_ab_memory routine
completes without consuming that last word, thus confusing the next
routine that tries to use DBGDTRTX (this may not have any visible effect
on some implementations, because writing to DBGDTRTXint when TXFULL=1 is
defined as Unpredictable, but I believe it caused a visible problem for
me).

With this patch, the bulk mem_ap_sel_read_buf_noincr is modified to omit
the last word of the block. The second-to-last read of DBGDTRTX by that
function will cause the issue of the LDC for the last word. After
switching back to Normal mode and waiting for that instruction to
finish, do a final read of DBGDTRTX to extract the last word into the
buffer, leaving TXFULL=0.

Without this patch, memory accesses are always expanded such that they
are aligned to the access size. With this patch, accesses are issued
exactly as ordered by the caller. The caller is expected to handle
fragments at the beginning and end of the transfer if the address is
unaligned and an unaligned access is not desired.

Without this patch, the DFAR and DFSR registers, which report the
location and status of data faults, are ignored while performing memory
accesses, which could cause problems debugging an OS page fault handler.
With this patch, DFAR and DFSR are preserved across memory accesses, and
DFSR is decoded in the event of a synchronous fault to provide the
caller with more information about the reason for failure.

Thanks to Boris Brezillon for the original patch whose ideas led to the
non-word access mechanism implemented here and to various code reviewers
for their comments.

Change-Id: I11ae7104fbe69a522efadefc705c9a217a7eef41
Signed-off-by: Christopher Head <chead@zaber.com>
Reviewed-on: http://openocd.zylin.com/2381
Tested-by: jenkins
Reviewed-by: Olivier Schonken <olivier.schonken@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-22 16:13:59 +00:00
Paul Fertser
986102f3f1 doc: stellaris driver supports Tiva C too
Change-Id: I3b77bf0617c0bbba85cfd678adece57aa7d03e32
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2509
Tested-by: jenkins
2015-02-12 12:57:13 +00:00
Paul Fertser
e899dcbfcf flash/nor/stm32lx: add all the IDs and revisions from current RM
RM0038 Rev.12 lists these new parts and introduces the category naming
scheme.

RM0367 Rev.2 (STM32L0x3 RM) doesn't add any new codes.

Change-Id: Id95dd48dda64d5f108dac57d265d29a7db3a1bd1
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2495
Tested-by: jenkins
2015-02-12 12:56:46 +00:00
Paul Fertser
c4113b5f3d README, doc: add mrvlqspi flash driver information
Change-Id: I7a270cdaf3d9119aa75285a8d1e063c2fe2a31b7
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2510
Tested-by: jenkins
2015-02-12 12:52:19 +00:00
Paul Fertser
70c8328750 doc, README: mention all the variants supported by lpc2000 driver
Change-Id: I66f9a201426a68fc1314ab7f02b27e36dcab33ba
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2508
Tested-by: jenkins
2015-02-12 12:51:46 +00:00
Andrej Kazmin
7c59257834 flash/nor/at91samd: add small delay before checking nvm status
OpenOCD's SWD subsystem doesn't currently have a consistent WAIT
handling (i.e. it doesn't ever retry, just returns an error), so right
after a row write a small delay is needed as AHB access is stalled
during the flashing operation.

The issue was exposed with a samd20 using ftdi SWD transport.

Change-Id: I07d99d3a96845cc689c3904a41f4d41344f200aa
Signed-off-by: Andrej Kazmin <funnyfish@funnyfish.botik.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2268
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-11 23:22:40 +00:00
Paul Fertser
30f802493d flash/startup: extend "program" command to accept "exit"
This optional argument tells OpenOCD to exit after finishing (either
succesfully, or with an error) the programming sequence. Without it
OpenOCD stays running.

Change-Id: I6ecaf33ff985eea9a9cd02ff644a74403ae3e1e5
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2492
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-11 22:19:37 +00:00
Paul Fertser
a35712a85c server: shutdown command should lead to exit without evaluating the rest
Currently

openocd -c "echo a1; shutdown; echo a2"

outputs both "a1" and "a2" and only then shuts down. This patch fixes
it by making shutdown command throw an exception, so unless it's
caught the shutdown will behave as expected.

Change-Id: I764268b3a9046ff3e9717d04095ea0673f1d755a
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2511
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-11 22:18:33 +00:00
Andreas Fritiofson
25e7a69e26 target/profiling: Use the correct method to access registers
Change-Id: I6b8590dc9d07886b885013b1b767fe2f0739cd6a
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2479
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 22:17:21 +00:00
Andreas Fritiofson
18c86b1c45 xscale: Use the correct method to access registers
Change-Id: I900a0787812cb24d1f74ca50eb6bb4f85375a353
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2478
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 22:17:11 +00:00
Andreas Fritiofson
89ba6ffec6 hla_target: Use the correct method to access registers
Change-Id: I853fc5117bdf07ecbc4584ff59d324367b2cb3e3
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2477
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 22:17:04 +00:00
Andreas Fritiofson
24e99ac6d9 cortex_m: Use the correct method to access registers
Convert the DWT register store to use a byte array and fix the byte order
bug uncovered by that. Also fix an incorrect access of the PC value.

Change-Id: Idb5acab71bdf5a96895c358324b05c335e4d32ca
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2476
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 22:16:57 +00:00
Andreas Fritiofson
0ecb0396d4 nds32: Use the correct method to access registers
The registers are represented as bit arrays intended to be accessed using
the buf_set_* and buf_get_* functions. Storing the register values in
integers enables accessing them directly, which gives different results
depending on host byte order.

Convert the register store to use a byte array instead and fix all the
byte order bugs uncovered by that.

Also merge the 32 and 64 bit register fields. Only one of them is used at
a time and after the change to byte arrays their types are also the same.

Change-Id: I456869a1737f4b4f5e8ecbfc1c63c49a75d21619
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2475
Tested-by: jenkins
Reviewed-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 22:16:51 +00:00
Antony Pavlov
fd43be0726 mips32: add gdb target description support
This commit is inspired by

    commit 1255b18fc6
    Author: Spencer Oliver <spen@spen-soft.co.uk>
    Date:   Fri Sep 13 09:44:36 2013 +0100

        armv7m: add gdb target description support

Change-Id: I75c3971fd0599d34ed49fb73975378b57f2a4af0
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
CC: Spencer Oliver <spen@spen-soft.co.uk>
CC: Oleksij Rempel <linux@rempel-privat.de>
CC: Paul Fertser <fercerpav@gmail.com>
CC: Gregory Fong <gregory.0xf0@gmail.com>
Reviewed-on: http://openocd.zylin.com/1972
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
2015-02-11 22:11:19 +00:00
Antony Pavlov
3f447bb8dd mips32: use 'unsigned int' for CPU register indices
Change-Id: I77e94b2fe0943a87e1d18d88ebf2a0133aaad728
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2216
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-11 22:09:27 +00:00
Anton Kuzmin
abdd5680cd tcl/interface/ftdi: correct LED config for BusBlaster KT-Link
Configure the LED to be off by default, blink on activity.

Change-Id: I8515ee66c49bddf866268b85811be15c2dbc086c
Signed-off-by: Anton Kuzmin <anton.kuzmin@cs.fau.de>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2539
Tested-by: jenkins
2015-02-11 22:05:39 +00:00
Andreas Bomholtz
bdbe78f131 sim3x: new flash driver for Silabs SiM3 microcontroller family
This is a new driver for Silicon Laboratories SiM3 microcontroller
family, based on the work of Ladislav Bábel. The driver will try to
detect the type of MCU from the device id register, and if this
fails it will use the flash size from the flash bank command.
Driver added to the documentation and to the README.
TCL script added.

Tests:
* Hardware: SiM3C166 (pre-production) and SiM3U167
* Binary: 4kb, 197kb, 256kb
* Flash protect not tested

Change-Id: I701e0cf505ca8ad99be7f83543fe5055b2f65dcc
Signed-off-by: Andreas Bomholtz <andreas@seluxit.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2078
Tested-by: jenkins
2015-02-11 22:05:22 +00:00
Angus Gratton
233f8859c0 nrf51 - Add async loader. Performance on nrf51822QAA/stlink-v2 from ~3.5KiB/s to ~19.5KiB/s.
Change-Id: Ib0bf41a0cec85f0bd5728551f8ad7f6255e4ea04
Signed-off-by: Angus Gratton <gus@projectgus.com>
[spamjunkeater@gmail.com: Cleanup buffer allocation, detect -1 for unknown pages]
Signed-off-by: Erdem U. Altunyurt <spamjunkeater@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2204
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-11 22:00:46 +00:00
Daniel Glöckner
b2dc1af59a armv7a: fix interpretation of MMU table
On armv7 there no longer are 1kB pages. Instead the bit that in
older architectures distinguished 1kB pages from 4kB pages is on
armv7 used for as execute-never marker. There may now also be 16MB
supersections with 40 bit physical address.

Change-Id: I959bdb8012782a9d07d968907a21f50e3d9b356a
Signed-off-by: Daniel Glöckner <daniel-gl@gmx.net>
Reviewed-on: http://openocd.zylin.com/2386
Tested-by: jenkins
Reviewed-by: Vladimir Svoboda <ze.vlad@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 16:18:50 +00:00
Joerg Fischer
fb9277191b J-Link serial number config option
Add serial option to jlink config commands, handy when there is more than one
adapter connected.

To select adapter 0123456 for OpenOCD, use

jlink serial 0123456

Change-Id: Ib29ce3f0c4975e1169211721a4531bf4db61f1ee
Signed-off-by: Joerg Fischer <turboj@gmx.de>
Reviewed-on: http://openocd.zylin.com/2521
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 16:18:25 +00:00
Olivier Schonken
6e32887f91 cortex_a: Add Cortex-A5 identification
Add Cortex-A5 identification to ROM-table display, and also
to cortex_a_init_debug_access. This change is mostly cosmetic.

Change-Id: I7b1dd8755d70d45eb5f315aa1918d44a813b3cdf
Signed-off-by: Olivier Schonken <olivier.schonken@gmail.com>
Reviewed-on: http://openocd.zylin.com/2483
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 16:17:58 +00:00
Paul Fertser
3f9f7de7b0 README: mention "transport select" in quickstart section
Change-Id: I027635c3c8632efcf58cf979b9cb2f99e9e7f046
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2512
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-11 15:34:21 +00:00
Paul Fertser
c8d351b1bf target/image: fix undefined behaviour when loading with GDB
The image struct is malloc'd and hence base_address_set doesn't have a
defined value.

Caught by Valgrind.

Change-Id: Ice15b2299fc768e44e8034eeb93e035076eacd03
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2524
Tested-by: jenkins
Reviewed-by: Stian Skjelstad <stian@nixia.no>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-11 15:34:11 +00:00
Paul Fertser
7f000f824b doc: document the OCL (on chip flash loader) driver
Change-Id: I8afe870c7a16b04473f4822c2df9a7607f0480e7
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2529
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-11 15:33:50 +00:00
Oleksij Rempel
bcfb604618 tcl: add TP-LINK TL-MR3020 to the firmware recovery script
This adds the board to the list of supported devices for the easy
recovery procedure. Only ram_boot is supported for this target.

Change-Id: I144e1836f8b6257e96a42c98c2668da74ce243f6
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/2520
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Reviewed-by: Andreas Färber <afaerber@suse.de>
2015-02-11 15:30:28 +00:00
Oleksij Rempel
f59d2d9ecf tcl/target|board: add config Atheros ar9331
Add configs for Atheros ar9331 MIPS based WiSoC and
board based on this chip: TP-LINK TL-MR3020

Change-Id: I9e99719bce4bbb28311f6e9cddb32288db6e7b91
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/2519
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:30:01 +00:00
Jose de Sousa
5bc0dc0c9d target: write gmon.out according to target endianness
After profiling gmon.out was being written in little endian format only
which would cause gprof to issue and error and exit on big endian targets.

Change-Id: I526a40adae0f9a439fc5b77cef30fda228198b48
Signed-off-by: Jose de Sousa <jose.t.de.sousa@gmail.com>
Reviewed-on: http://openocd.zylin.com/2168
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:27:18 +00:00
Pawel Si
b01952d78c mini51: support for Nuvoton NuMicro M051 series flash memory
adds flash support for Nuvoton M052, M054, M058, M0516 microcontrollers
into the mini51 driver, patch also adds support for programing LDROM,
flash data and flash config.

I've tested it on a M0516LBN microcontroller using an ST-LINK/V2:
1. removing security lock:
   openocd -f interface/stlink-v2.cfg  -f target/m051.cfg -c "init ; halt ; mini51 chip_erase; exit"
2. flashing:
   openocd -f interface/stlink-v2.cfg  -f target/m051.cfg -c "program file.hex"

Change-Id: I918bfbb42461279c216fb9c22272d77501a2f202
Signed-off-by: Pawel Si <stawel+openocd@gmail.com>
Reviewed-on: http://openocd.zylin.com/2426
Tested-by: jenkins
Reviewed-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:23:09 +00:00
Jacob Palsson
45a86f8e2a tcl/target: add CC2538 and CC26xx target files (with cJTAG procedure)
Added support for the Cortex-M3 based TI low power RF SoC CC2538 and
the CC26xx family.

These chips need a start sequence for switching from cJTAG to JTAG
before being used with OpenOCD, this is done in the tcl proc
ti_cjtag_to_4pin_jtag in the ti-cjtag.cfg config.

The configs for CC2538 and CC26xx run the start sequence on post-reset
event and set the ICEPick IDCODE in the data register for OpenOCD to
read, this is done so that every time OpenOCD resets the device, it
will enable JTAG.

Change-Id: I7db620211c0e7e03fad59d24fe31d23a9cdcfedc
Signed-off-by: Jacob Palsson <jaaacke@gmail.com>
Reviewed-on: http://openocd.zylin.com/2232
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-11 15:22:40 +00:00
Ed Beroset
18d6c0b02b em357: added target files for em357 and em358
This patch adds support for Silicon Labs (formerly Ember) EM357
and EM358 chips and derivatives.

Change-Id: Ie63aed95a2f4ef1a6b955e301a51b4de1b3a5462
Signed-off-by: Ed Beroset <beroset@ieee.org>
Reviewed-on: http://openocd.zylin.com/2470
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:11:19 +00:00
Nemui Trinomius
d66f48d1f6 jlink: Added hardware version number for JLink firmware on LPC-Link2
JLink firmware on LPC-Link2 has unique hardware version number(0x12).

Change-Id: I76b6e27c47d236da75c61dd6b83d6a823615968d
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2298
Tested-by: jenkins
Reviewed-by: Anders Oleson <anders@openpuma.org>
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:10:53 +00:00
Heinz Schweiger
d7792a684e cfg: TI Tiva C dk-tm4c129x Evaluation Kits
New Texas Instruments Tiva C Series Boards
http://www.ti.com/tool/dk-tm4c129x

Change-Id: I44f96982e91786b977b3d29e0f4c7053d584a703
Signed-off-by: Heinz Schweiger <openocd@htl-steyr.ac.at>
Reviewed-on: http://openocd.zylin.com/1867
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:09:49 +00:00
Michael Brown
34f3e84d69 lpc2000: add chip IDs for LPC11U6x/LPC11E6x
Change-Id: I53568674951ec8a5db5e191c7b50c60b5a84d0b6
Signed-off-by: Michael Brown <fractalmbrown@gmail.com>
Reviewed-on: http://openocd.zylin.com/2463
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 15:08:47 +00:00
Tomas Vanek
1d7176f50b psoc4: support for Cypress PSoC 41xx/42xx family
New NOR flash driver was derived from stm32lx.
Procedure ocd_process_reset_inner is overriden in psoc4.cfg
to handle reset halt and system ROM peculiarities.

Change-Id: Ib835324412d106ad749e1351a8e18e6be34ca500
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/2282
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-02-11 14:59:55 +00:00
Jussi Kivilinna
a9c90a0f8f stm32lx: do not attempt mass-erase in-place of first bank erase
Commit 832f0a5bfb 'stm32: add mass erase support for STM32L' added
use of mass-erase in-place of bank-erase. This is triggered if first
bank is requested to be fully erased.

This erroneous action completely fails on STM32L162VEY (has 512 KiB
flash in two 256 KiB banks) and also unintently destroying contents of
EEPROM and second flash bank.

Change-Id: I0f13f7b0346747a09c755d72b5b95775ceff5a6f
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@haltian.com>
Reviewed-on: http://openocd.zylin.com/2441
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
2015-02-04 22:02:59 +00:00
Paul Fertser
873774992d flash/nor/stm32lx: use 0 base to autodetect second bank location
Change-Id: I3c296b3e276fcd4d92e4180fc0d2133eebfcc240
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2503
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 22:02:45 +00:00
Paul Fertser
97c96ac13f doc: add stm32lx mass_erase description
Change-Id: Ibe26f40a105dfabcf336ae12fcdc72f4e87513b6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2502
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 22:02:36 +00:00
Paul Fertser
f34098953a flash/nor/stm32l: unify waiting for busy flag functions
Change-Id: I5e6daff8232bb4807dd13a1951fbf335529661d4
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2491
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 22:02:28 +00:00
Paul Fertser
cd72808889 flash/nor/stm32l: fix mass erase
Topaz reports on http://sourceforge.net/p/openocd/tickets/87/ that
protection level constants are mixed up. This leads to device ending
up in protection level 1 after mass erase.

Additional work is required to actually put the device in RDP Level 1
and then back to Level 0, as Option bootloader launch is a special
kind of full target reset.

To be able to flash properly after mass_erase a "reset init" is needed
(it's anyway recommended to always perform it before any flash
operation).

Change-Id: I9a838909458039bb0114d3019723bf134fa4d7c9
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2490
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 22:00:52 +00:00
Paul Fertser
c9639ae2ac configure: define WIN32_LEAN_AND_MEAN early to make it effective
This macro makes windows builds faster and helps with the old "#define
interface struct" issue as the word "interface" is part of libusb-0.1
API. However, defining it in replacements.h is too late, as windows.h
gets included by that time from somewhere else.

This solution is provided by Ray Donnelly from the MSYS2 team.

Change-Id: I376a5fb3d106786515d7e1ba44dbd751e4dcdb1b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2486
Tested-by: jenkins
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 21:56:55 +00:00
Paul Fertser
d0db4bfcec Makefile.am: link libusb-1.0 after libusb-0.1 to fix dependencies
Since libusb-0.1 might be provided by libusb-compat, it will depend on
libusb-1.0, so needs to be mentioned before it in the link command
line, this is relevant for static linking.

Thanks go to mingwandroid for spotting it during MSYS2 build.

Change-Id: I15cf0b8f084c351b4f93e75686bd0f843477352b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2485
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 21:56:45 +00:00
Paul Fertser
35de943d35 flash/nor/stm32f2x: add new revisions of STM32F4x parts
Change-Id: I7585ccbe12fe079e960ce9e33d9a143672a6a08c
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2493
Tested-by: jenkins
Reviewed-by: Rémi PRUD'HOMME <prudhomme.remi@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 21:56:23 +00:00
Rémi PRUD’HOMME
fb1b388dea Subject: [PATCH] update src/flash/nor/stm32f2x.c
Add the new STM32F446 mcu with 512 Ko
Tested with a eval board

Change-Id: I0c16ce7d32d249c7634d697815207c20e7f778c4
Signed-off-by: prudhomme.remi@gmail.com
Reviewed-on: http://openocd.zylin.com/2484
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-02-04 21:56:13 +00:00
Uwe Bonnes
5ffe5b9b2c Add more STM32F3 IDs in target/stm32f3.cfg.
Change-Id: I4c4462aa025639c4d20e6fa23c8845a69e60afc5
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2435
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-02-02 10:29:01 +00:00
Paul Fertser
d537cfa124 drivers/stlink: clarify "init mode failed" message
The message as it was didn't let the user know that something was wrong
with the target or wiring.

Change-Id: Ib609c2d31959e77413e61c348d0e31d7269d5c58
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2365
Tested-by: jenkins
Reviewed-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-by: Jens Bauer <jens@gpio.dk>
2015-01-30 09:44:24 +00:00
Paul Fertser
5b6c29a457 tcl/target: add lpc8xx.cfg
This adds a trivial config for LPC8xx chips based on the already
existing infrastructure in lpc1xxx.cfg.

Change-Id: I7384df1f3c2e3e8ab767319728db5c4f8149480f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2464
Tested-by: jenkins
Reviewed-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
2015-01-30 09:40:55 +00:00
Paul Fertser
4f441486e5 jtag/drivers: remove useless checks causing build failure with clang 3.5.0
Change-Id: Icafab6ac1e3e79c6da1bc163c30744eee4bde8d3
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2482
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
2015-01-30 09:02:20 +00:00
Andreas Fritiofson
f2c85452cf armv4_5: Continue the change from uint32_t to uint8_t[4] for regs
Also remove an unrelated no-op cast.

Change-Id: Ibeb6c72e5b0b0347abb568947a05a179661faf2d
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2473
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
2015-01-30 08:57:55 +00:00
Paul Fertser
355f4cadbb Use (uint8_t *) for buf_(set|get)_u(32|64) instead of (void *)
This helps to uncover incorrect usage when a pointer to uint32_t is
passed to those functions which leads to subtle bugs on BE systems.

The reason is that it's normally assumed that any uint32_t variable
holds its value in host byte order, but using but_set_u32 on it
silently does implicit pointer conversion to (void *) and the
assumption ends up broken without any indication.

Change-Id: I48ffd190583d8aa32ec1fef8f1cdc0b4184e4546
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2467
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-30 08:56:54 +00:00
Jens Bauer
9d745a0690 stm32f2x: Fix byte order bug.
Do not use buf_set_u32 on integers; they're not buffers.
If using buf_set_u32 on integers, bytes will be exchanged on Big Endian targets.
In this particular case, FLASH_OPTCR was incorrectly written, causing it to often
contain one of these values: 0x00aaaae1, 0x00aaffef, 0x00ffabe1 or 0x00abffe1.
This write-protected the device before flash-programming, causing this command...
flash write_image erase unlock myfile.elf
... to fail, complaining about write-protection.
Repeating the above command would change the OPTCR register each time.
After applying this patch, the OPTCR remains "unchanged".

Change-Id: I73d510fcc2e81a01973ad5c6e1aa22715ebd2743
Signed-off-by: Jens Bauer <jens@gpio.dk>
Reviewed-on: http://openocd.zylin.com/2466
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-30 08:55:23 +00:00
Paul Fertser
08da1b4258 flash/nor/kinetis: pull SRST low during mass erase
Mass erase operation might be impacted by different factors,
apparently the most reliable way is to do it while asserting the chip
reset line.

Change-Id: Id6ab57eaec86e402ffdf4f5c8843e7735640f03e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2424
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-30 08:54:25 +00:00
Andreas Fritiofson
1fa4c728aa jtag: Rewrite TAP verification/auto-probe logic
Enable auto-creating additional discovered TAPs even if some TAPs are
predefined, avoiding initialization failure when it's not necessary.

Also, drop the arbitrary limit on the number of predefined TAPs. Still,
don't auto-create any if there are more than 20 TAPs already, to stop
a noisy connection from creating unlimited TAPs.

Create auto-probed TAPs with less noise.

Reduce code duplication between verification and auto-probing.

Change-Id: I82a504d92dbcc0060206e71f10c5158256b5f561
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2236
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-01-28 08:01:43 +00:00
Uwe Kleine-König
24fb042a73 ARMv7-A: remove useless switch construct
The default label does just return the same error code as the case for
zero, so this can be handled by a simple if statement.

Change-Id: I61a8cb51b5e261f21eca386af7d8cbf17ffa2d44
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-on: http://openocd.zylin.com/2430
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-28 06:57:57 +00:00
Jaakko Kukkohovi
fe04314c2a jtag/drivers/cmsis-dap-usb: fix cmsis_dap_serial
Previously the serial wasn't actually used in hid_open() call,
which meant that the first device with matching vid:pid was opened
irrespective of the actual serial number.

Change-Id: I45216ae5d9e0798e97be693c30e2f03c89b9a02b
Signed-off-by: Jaakko Kukkohovi <jkukkohovi@gmail.com>
Reviewed-on: http://openocd.zylin.com/2487
Tested-by: jenkins
Reviewed-by: Jörg Wunsch <openocd@uriah.heep.sax.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 21:16:42 +00:00
Paul Fertser
101124c69a tcl/board: frdm kinetis boards have SRST connected
Change-Id: I1a56b5e9d1ac6466bba11cc694ee3eaa2c9b504f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2462
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:58:06 +00:00
Paul Fertser
064dc5daac tcl/target/stellaris: Snowflake supports SYSRESETREQ too
Change-Id: If4bf472ab8867c54a976bdb5803f7e4f79f350a8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2461
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Ed Beroset <beroset@ieee.org>
2015-01-26 20:57:56 +00:00
Paul Fertser
38107ff966 tcl/target: consolidate Kinetis configs
Change-Id: I75fe6b239ff435f700459e7d7040616503fa458e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2460
Reviewed-by: Andreas Färber <afaerber@suse.de>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:57:41 +00:00
Paul Fertser
d940a3224b jtag/drivers/stlink: demote the output of available speeds to DEBUG
Change-Id: If0afb6fb1cb2f39619e4e614573065c145255c3e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2469
Reviewed-by: Jens Bauer <jens@gpio.dk>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:56:25 +00:00
Paul Fertser
9a160c6334 jtag/hla_interface: avoid segfault with adapters that do not have configurable speed
Change-Id: I0386cbfc85ba8b28d3819530f9950b31545d6821
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2468
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:56:18 +00:00
Uwe Bonnes
d61795c625 stm32f07/9: Both devices have 256 kByte Flash Maximum.
See RM0091, Rev.7. page 56.

Change-Id: I9a98094d49739686f93e26a5112eb0a2a8a7c883
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2458
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:55:31 +00:00
Uwe Bonnes
5b38f862f8 stm32f0x: Remove duplicate code for revision string.
As of RM0091, Rev. 7, all F0 have the same revisioning scheme.

Change-Id: I0b344a1d3ca3f61f48fa151e83c549ca5333ae47
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2457
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:55:23 +00:00
Uwe Bonnes
5420ff3638 stm32f09x: Print info in get_stm32x_info.
Change-Id: I5f9b765fe04906e124e2c95ff6bf7193be9d4ce2
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2456
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:55:17 +00:00
Thomas Eichinger
0d9ecc42d1 tcl/board: Add ST NUCLEO L152RE configuration
Added support for the ST nucleo l152re board with a stm32l152ret6 MCU,
analog to st_nucleo_f* configurations.

Change-Id: Id2c61dc7a7cb2e1cc64442191b367bab4247bdeb
Signed-off-by: Thomas Eichinger <eicht@lepus.uberspace.de>
Reviewed-on: http://openocd.zylin.com/2489
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:55:03 +00:00
Paul Fertser
a1bbf4b75b cfg: add srst_nogate to the supported targets, remove from board configs
It depends on the particular target whether it can work with SRST
asserted or not, so this belongs to the target config rather than the
board config.

Also, this allows for simple

openocd -f myboard.cfg -c "reset_config connect_assert_srst"

command to be used whenever a user feels a need to connect to an
unresponsive target.

Change-Id: I3d8da9ae47088fc0c75a20bfdd20074be1014de0
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2459
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:54:51 +00:00
Uwe Bonnes
7dd50909e3 stm32f4/nucleo: Use only one configuration for all stm32f4 nucleo boards.
Change-Id: Ic3d0b47b19dae9cb09c11d24f16fea85a1b90c0b
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2397
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:54:30 +00:00
Uwe Bonnes
ded2b293f4 stm32f0/nucleo: Use only one configuration for all stm32f0 nucleo boards.
Change-Id: Ib2ddcd7a92c0d7ad503ef8e953f2bc304241a9f0
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2396
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:54:21 +00:00
Uwe Bonnes
43aadbf5dc flash/nor/stm32f1: Add handling of stm32f09, nearly same as stm32f07.
Change-Id: I9cb2aa75decca0e8a065fe7f5353de44d6877274
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2394
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-26 20:54:10 +00:00
Karl Palsson
1663a17d9d target/stm32xx: Endian is not configurable.
So remove it from all the configs, it's misleading, and leads to cargo
culting of config files.

Change-Id: I2b77e60d5e96f9759c7c9fc91b20e73be2e95d9a
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2446
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:26:18 +00:00
Jörg Wunsch
03b1905223 flash: add AT91SAM4SD16C device
Change-Id: I12f740a1a2d10637b0e5b1e8d054dd912576d190
Signed-off-by: Jörg Wunsch <openocd@uriah.heep.sax.de>
Reviewed-on: http://openocd.zylin.com/2455
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-01-15 23:25:05 +00:00
Karl Palsson
9e38365258 contrib: itmdump: fix multi byte decoding
Incorrect byte manipulations.

Change-Id: Id8c3f457b39f4b2b75613076d403359c4972a69d
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2448
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:23:28 +00:00
Paul Fertser
97012f080c tcl/interface/ftdi: add config for the IoT-LAB adapter
This is an integrated adapter used on the IoT-LAB boards.

Schematics are available from
https://github.com/iot-lab/iot-lab/wiki/Docs/openm3-schematics.pdf

Change-Id: I1c80e72653c3f319bb04d01e3dfddb1c2447c398
Tested-by: Quentin Lampin <quentin.lampin@orange.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2415
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:22:31 +00:00
Andreas Färber
7ca77b090b tcl/board: Add TI TMDX570LS20SUSB board config
It is derived from ti_tmdx570ls31usb.cfg, using a different TAP ID.

Change-Id: I2d911995c76ea4f75a780cc230d61f4959825809
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-on: http://openocd.zylin.com/2440
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:21:41 +00:00
Spencer Oliver
145f8ed817 stlink: add reconfigurable speed support
The ability to change the speed has been added to firmware versions J22 and
above. Any attempt to change on earlier versions will be ignored without error,
as the existing code does.

For supported firmware versions the driver will attempt to get as close as
possible to supported speeds (never higher).

The default stlink speed on power up is 1.8MHz.
The driver will now also print supported clocl speeds during init.

Change-Id: Iee9bd018bb8b6f94672a12538912d41c23d48a7e
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2335
Tested-by: jenkins
2015-01-15 23:21:18 +00:00
Spencer Oliver
ab0432176c hla: add ability to change adapter speed (if supported)
As a note we need to cache the requested speed setting, as the
hla interface may not be ready when the first adapter_khz is called.

Change-Id: I2fa6807d5f0bd3f0365cf178bd10a230c39415a7
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2334
Tested-by: jenkins
2015-01-15 23:21:01 +00:00
Karl Palsson
0ea9a66239 cfg: stm32l1: Use specific chipname
This should have been corrected earlier with the split of l1/l0 code
apart.

Change-Id: I87b94a310ae7e76318554a9cd2705348a942d58b
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2447
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:20:44 +00:00
Paul Fertser
1f8518fef4 jtag/hla: output possible idcode candidates in case of mismatch
Output a similar message to what we have on low-level JTAG adapters to
avoid confusing users. Reported on IRC by chickensk.

Change-Id: I96d58410ef715b966e32d79c0aacf38596c5eb3f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2451
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:17:29 +00:00
Evan Hunter
d25b43b163 jtag: Avoid extra SRSTn resets when connecting
Previously the jtag_add_reset(1, 0) caused the processor to be released,
and if SRSTn existed then it would then be reset again two lines later.

Change-Id: I58b7a12607f46f83caa7ed3b3cebc4195eb51ef6
Signed-off-by: Evan Hunter <ehunter@broadcom.com>
Reviewed-on: http://openocd.zylin.com/2398
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-15 23:16:06 +00:00
Spencer Oliver
d12fa18bd9 docs: update bug tracker URL
Change-Id: I6a362020a29ccb9222f7909b5b34e5c35a02ed4b
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2454
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-01-15 23:14:14 +00:00
Nemui Trinomius
a39d1ced36 lpc2000: Improve lpc2000 flash driver.
This patch adds flash programming support for LPC5410x and LPC82x.
And adds auto flash size detection for LPC800 series.
Tested on below listed boards/chips.
LPC54102(LPCLPC54102Xpresso)
LPC824(LPCXpresso824-MAX)
LPC812(LPC812MAX)
LPC811,LPC810

Change-Id: Ie68b6d425b17ccfa83814607ee61056e99800c1c
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2442
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-01-15 23:13:49 +00:00
Alexander Stein
1567caea2c cortex_a: Add support for A7 MPCore
A7 MPCore needs unlocking the debug registers same as with A15 MPCore.
Found out by hacking on the code.

Change-Id: I613cb4fb35007b85b4a9a401577b47768bc1a08b
Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Reviewed-on: http://openocd.zylin.com/2344
Tested-by: jenkins
Reviewed-by: Kamal Dasu <kamal.dasu@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-10 00:57:09 +00:00
Kamal Dasu
e519099ab7 cortex_a: Add support for A15 MPCore
Added Cortex-A15 support for DAP AHB-AP init code as per ADI V5 spec.
Also added changes to make the APB MEM-AP to work with A15.
Made the the cortex_a target code  generic to work with A8, A9
and A15 single core or multicore implementation. Added armv7a code
for os_border calculation to work for known A8, A9 and A15
platforms based on the ARM DDI 0344H, ARM DDI 0407F, ARM DDI 0406C
ARMV7A architecture docs.

Change-Id: Ib2803ab62588bf40f1ae4b9192b619af31525a1a
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Reviewed-on: http://openocd.zylin.com/1601
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-10 00:56:45 +00:00
Tomas Vanek
806872a34a ChibiOS: struct ChibiOS_params_list[] should not be const
Procedure ChibiOS_update_memory_signature() sets struct member signature.

Change-Id: I45adbd14fa7cda99413fd0b516d45b3fb55e322d
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/2427
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-09 08:56:10 +00:00
Karl Palsson
881d08ddbd transport: clarify error message when transport is not selected
When no transport is selected, the error message dumps the available
transports, but not how to actually select one.

Change-Id: I63da2a4b59e3f6cc8d30bd631e41a82636a056ef
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2406
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-09 08:48:18 +00:00
Spencer Oliver
513436a17a flash: fix kinetis driver typos
Change-Id: I0a4557f08507c61cb8ab33b38d2b6b069c344c09
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2385
Tested-by: jenkins
2015-01-09 08:47:39 +00:00
Spencer Oliver
d1a67c80e4 cfg: fix lpc17xx regression
commit b5a6ba46 broke the following board files, update to new cfg.

Change-Id: Ic3b776bd32eb72eae6ad1e130e329268ce9ba71a
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2384
Tested-by: jenkins
2015-01-09 08:47:20 +00:00
Salvador Arroyo
1d37b37dc7 avoid segfaulting when attempting to set an unavailable type of breackpoint
For example "bp 0x20000000 8 2" makes openocd segfaulting on a
stm32f4x Discovery board.

Change-Id: I1ddd46b1fa9ade78db2234ed975ccefb72539331
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/2342
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-09 08:46:45 +00:00
Jens Bauer
2eacb8fdfb Mac/PPC: Fix build.
GCC-4.2 on Mac/PPC complains about size_t is expected for %zx and the build stops.
In order to avoid other problems, I've chosen simply to typecast.

Change-Id: I99b569c4d1100e729712e31d24d6539f8b5971b6
Signed-off-by: Jens Bauer <jens@gpio.dk>
Reviewed-on: http://openocd.zylin.com/2360
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2015-01-09 08:42:15 +00:00
Paul Fertser
9f6d4d1302 swd: handle various failure conditions
When communication with target fails for whatever reason, it makes
sense to do JTAG-to-SWD (in case the target got power-cycled or the
DAP method was reset anyhow), SWD line reset sequence (part of
JTAG-to-SWD already) and the mandatory IDCODE read. Schedule that to
be performed on the next poll.

Fix the return values for ftdi and jlink drivers to be consistent with
OpenOCD error codes and remove ad-hoc calls to perform DAP method
switching (as it's now done from the upper layer automatically).

Change-Id: Ie18797d4ce7ac43d8249f8f81f1064a2424e02be
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2371
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Mateusz Manowiecki <segmentation@fault.pl>
2015-01-09 08:36:52 +00:00
Paul Fertser
c120fb6d89 target: improve robustness of polling and reexamination
When a target was present on OpenOCD start but later disappeared for
whatever reason (typically unstable connection or target going to
sleep) and reappeared only for a brief period of time, reexamination
would fail, and poll would no longer run. This patch fixes it.

Change-Id: I61f9b5a3f366a761320e233f4e1689f926b5556d
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2370
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2015-01-09 08:36:06 +00:00
Spencer Oliver
420bd49b5b rtos: free gdb packet allocated memory
compile tested only.

Change-Id: I3bc06c212967a3ce44a875f802b554c178537d1d
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2382
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-09 00:19:11 +00:00
Paul Fertser
a9a5c17cf5 checkpatch: fix check for the FSF address
Commit 4525c0a4c4 cherry-picked check
for the FSF address presence from upstream. However, it has a typo
resulting in this obscure error when triggered:

Use of uninitialized value in concatenation (.) or string at /home/jenkins/.jenkins/jobs/openocd-gerrit/workspace/tools/scripts/checkpatch.pl line 1258.
ERROR:

This patch fixes it.

Change-Id: Ia417ef4782d21c8b3f1d39de88c4ab850a5a6630
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2414
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2015-01-08 23:05:24 +00:00
Andreas Fritiofson
1e23496f6e jtag: Remove unnecessary global variable
Change-Id: I96e5f13b12da2970eafc5fca24b7952d427eeca9
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2235
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2015-01-07 23:23:14 +00:00
Andreas Fritiofson
9330147fae jtag: Fix memory leaks in jtag_tap_free()
Change-Id: I953fbb346fbf168fb50b349d245f2aa64dbfdcb3
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2234
Tested-by: jenkins
2015-01-07 23:23:01 +00:00
Karl Palsson
c3ec1940b5 stm32l: split l0/l1 support no jtag, different HSI settings
L0 is cortex m0+, so different id codes, SWD only, different addresses
for the clock speedup.  It has no endian options, no boundary scan.

Removed all L0 specific portions from L1 files, and renamed files to clarify
their purpose.  The deprecated stm32lx_stlink.cfg is kept as is, as it is only
around for backwards compatibility with prior releases.

Tested on STM32L053 Discovery and STM32L151 Discovery.

Has _not_ been tested with jtag on L1.

Change-Id: I8eea890d2f92a302d9e9c8a8832d218ee1b6bcfc
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2405
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Juha Niskanen <juha.niskanen@haltian.com>
2014-12-03 09:10:21 +00:00
Juha Niskanen
12b41a3409 stm32: Fix L0/1xx CPUTAPID setting and add new L1xx BSTAPIDs
Fix script parse error, when using JTAG, introduced in
commit 0187ced9ed

Add several BS TAPIDs with comments about ST documentation.

Change-Id: I8d0370b244ccaf7ea0dbe1919bfad1915f7317d4
Signed-off-by: Juha Niskanen <juha.niskanen@haltian.com>
Reviewed-on: http://openocd.zylin.com/2376
Tested-by: jenkins
Reviewed-by: Rémi PRUD'HOMME <prudhomme.remi@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-12-03 09:07:54 +00:00
Uwe Bonnes
9c4d294654 tcl/target/stm32f4: ramp up JTAG speed, HSI is 16MHz there
Since all F4 parts have an internal HSI providing 16MHz, it's safe to
use 2MHz JTAG frequency by default.

Change-Id: I2702d5a1d642d4acd4af2db54c028949132c6900
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2383
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:28:10 +00:00
Uwe Bonnes
41a968ec05 tcl/target/stm32f4x: add F401 and F411 IDs
Change-Id: I12079586dafb8a7614bdf4cc0b13cd5030301742
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2379
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:27:52 +00:00
Grigori Goronzy
c4b52f8fd7 lpc2000: ignore status of part ID IAP command
The IAP firmware won't return a proper status with some versions. This
happens on my CCC r0ket board and others have seen it as well [1]. So
just ignore the status code and do a (weak) consistency check instead.

[1] http://www.lpcware.com/content/forum/lpc1343-iap-read-part-identification-command

Change-Id: I0daa779d520a540629677c56857bbc20d6db422d
Signed-off-by: Grigori Goronzy <greg@chown.ath.cx>
Reviewed-on: http://openocd.zylin.com/2364
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-11-24 22:27:02 +00:00
Antony Pavlov
4525c0a4c4 checkpatch.pl: check for the FSF mailing address
This check code is imported from Linux v3.17 checkpatch.pl.

Change-Id: If39d834ee9b6131bccc92de38fd7c108650bd2f1
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2341
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Tested-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:23:38 +00:00
Antony Pavlov
9777284ae0 or1k: remove address of the Free Software Foundation
The FSF address has changed; The FSF site says that
address is

  Free Software Foundation
  51 Franklin Street, Fifth Floor
  Boston, MA 02110-1301
  USA

(see http://www.fsf.org/about/contact/)

Instead of updating it each time the address changes,
just drop it completely treewide.

Change-Id: I27199f7625901f677d8105d1e8876cff00147b71
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2340
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:23:28 +00:00
Antony Pavlov
c5d8988316 checkpatch.pl: check for openocd tree, not for kernel tree
checkpatch.pl looks for linux kernel specific paths and files
to check source tree. As openocd misses kernel files it ends
with this error message:

    Must be run from the top-level dir. of a kernel tree

This patch also renames 'kernel' -> 'openocd'
in source tree-related messages.

Due to checkpatch checking modifications on itself, lift the
restriction on having no spaces at the start of a line for Perl
scripts. This can be readded back later.

Change-Id: I89b7ca976bef5e13785bd3a43e597c9feb4c2df4
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2339
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:23:14 +00:00
Antony Pavlov
f16b7a6d7e mips32: fix typos
Change-Id: Ibb98fe3da68bf670a5bb83600bb49647db8a4163
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2338
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:22:53 +00:00
Alexei Colin
fd25b3bcd1 doc: flash: write_image writes only loadable sections
The code that takes only sections marked PT_LOAD is in
image_elf_read_headers in src/target/image.c

(Just trying to save some time for the next person with same question.)

Change-Id: I493c102c908fca2b7238276ddbbecbe8c7cd9a0a
Signed-off-by: Alexei Colin <ac@alexeicolin.com>
Reviewed-on: http://openocd.zylin.com/2348
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:22:25 +00:00
Christian Gudrian
f83e1dc13f Added FPU support for ChibiOS/RT
When an enabled FPU is detected we now use an appropriate stacking.

Change-Id: I1b0f43ec22e1c55c4f10e2ffa97d4aaa77bca5ee
Signed-off-by: Christian Gudrian <christian.gudrian@gmx.de>
Reviewed-on: http://openocd.zylin.com/2354
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:22:11 +00:00
Christian Gudrian
8b99681346 rtos: add support for ChibiOS/RT 3.0
In ChibiOS/RT 3.0 the ready list pointer "rlist" is now part of the system
data structure. Since the ready list is the first element in that
structure it can be accessed via the structure's symbol "ch".

Change-Id: Idc7eaa87cb7bbad0afa0ff1dafd54283bf429766
Signed-off-by: Christian Gudrian <christian.gudrian@gmx.de>
Reviewed-on: http://openocd.zylin.com/2352
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:21:47 +00:00
Paul Fertser
6d562283b5 rtos: allow symbols to be optional for a particular RTOS
Default to non-optional.

Change-Id: Ifc9ddb1ab701a19c3760f95da47da6f7d412ff2e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2355
Tested-by: jenkins
Reviewed-by: Christian Gudrian <christian.gudrian@gmx.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:21:37 +00:00
Andrey Yurovsky
08607aefc0 flash: at91samd: fix use of is_erased in check
is_erased can be one of -1, 0, or 1 so it must not be checked like a
boolean value.  In this case we want to erase a page unless we know it's
already erased so we just check for is_erased != 1.

Thanks to Jim Paris for pointing this out on another driver.

Change-Id: I4591186228153b64e5a9608a2aac18745e578d4a
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2368
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:18:59 +00:00
Paul Fertser
921eb4213a jtag/drivers/jlink: implement register command to fix SWD
Some J-Link fw versions require registration to be performed before
SWD operation is possible. It doesn't harm anyway, vendor's utilities
do it unconditionally.

Thanks go to Segger for providing the necessary information.

Change-Id: Iabd76c743eca86e2c817a97cb93c969fec3f7ac6
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2331
Tested-by: jenkins
2014-11-24 22:18:30 +00:00
Thomas Schmid
61de77ef88 at91sam4: Adding support for the AT91SAM4S4A.
Added the chip definition for the Atmel AT91SAM4S4A. This chip is a 48-pin
package with 256k flash and 64k ram.

Change-Id: I8ada7d5735e31e0ce086f96f5906c7358464245c
Signed-off-by: Thomas Schmid <thomas@rfranging.com>
Reviewed-on: http://openocd.zylin.com/2254
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:15:36 +00:00
Anders
1662c854e2 flash/nor/lpcspifi.c: fix bug that prevented clean reset after flash write
After SPI flash was written by the assembly language stub,
the last SPI command was not terminated by raising CS.
This left the SPI device in a hung state that prevented the
flash from being read by the M4 SPIFI controller, even after
the M4 was fully reset. To access the flash via SPIFI, it was
necessary to completely power cycle the board.

This fix adds the missing instructions to raise CS and
terminate the SPI command after the last byte. This allows
the M4 to be resumed or reset cleanly after flashing. The
SPIFI memory is now immediately accessable at address
0x1400 0000 after flashing is complete.

Change-Id: I4d5e03bded0fa00c430c2991f182dc18611d5f48
Signed-off-by: Anders <anders@openpuma.org>
Reviewed-on: http://openocd.zylin.com/2359
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:14:38 +00:00
Uwe Bonnes
2162ca72ef Hacking: Some note how to review.
Change-Id: Ied682884abdba27da265f1ce3632417f54a80fe2
Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
Reviewed-on: http://openocd.zylin.com/2380
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 22:14:03 +00:00
Nemui Trinomius
78cad16187 lpc2000: Added LPC1500 series flash programming support.
This patch adds flash programming support for LPC1547/8/9 and LPC1517/8/9.
Tested on LPC1549(LPC1549 LPCXpresso Board with CMSIS-DAP firmware).

Change-Id: Ic95b4d62055bb9fdc2ca484696a38ccaf49ad951
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2304
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Grigori G <greg@chown.ath.cx>
2014-11-24 22:01:12 +00:00
Jim Paris
a59e8058e7 nrf51: fix checks for is_erased
is_erased can take the value 0 (no), 1 (yes), or -1 (unknown).
Checks like (!is_erased) don't do the right thing if it's -1.

Change-Id: I10ba32c99494ca803e0a7a1ba56fdd78184b96bb
Signed-off-by: Jim Paris <jim@jtan.com>
Reviewed-on: http://openocd.zylin.com/2366
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 21:54:11 +00:00
Jim Paris
56802d794e nrf51: verify that UICR needs erasing before triggering an error about it
If the UICR is already empty, there's no reason to return an error
just because it can't be erased again.  This happens, for example,
when flashing UICR from GDB after a "monitor nrf51 mass_erase".

Change-Id: Ia6d28c43189205fb5a7120b1c7312e45eb32edb7
Signed-off-by: Jim Paris <jim@jtan.com>
Reviewed-on: http://openocd.zylin.com/2363
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 21:54:02 +00:00
Jim Paris
f30bb58644 nrf51: fix UICR erase
nrf51_erase_page() checks for (sector->offset == NRF51_UICR_BASE) to
determine if the UICR should be erased.  However, sector->offset for
the UICR bank is set to 0 in nrf51_probe, so this code is never hit.
Attempting to erase UICR ends up erasing the first flash sector.

Use bank->base instead to determine if UICR is being erased.

Change-Id: Ie5df0f9732f23662085ae2b713d64968cd801472
Signed-off-by: Jim Paris <jim@jtan.com>
Reviewed-on: http://openocd.zylin.com/2362
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-11-24 21:53:38 +00:00
Jim Paris
6412b0656b nrf51: fix UICR region size
The UICR region is actually 0x100 bytes in size.  Besides making the
full region accessible, having the right value is important because
GDB rounds flash addresses to the nearest multiple of the block size
when determing which flash blocks to erase.

Change-Id: I416c391cbfc7be41a03a9b9c6e42326c87391f38
Signed-off-by: Jim Paris <jim@jtan.com>
Reviewed-on: http://openocd.zylin.com/2361
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2014-11-24 21:53:24 +00:00
Peter Lawrence
30203b3d8b arm_adi_v5: added two CoreSight peripheral IDs
added "Single Wire Output" and "Trace Memory Controller" peripheral 
IDs to dap_rom_display(), which is invoked by the "dap info" command

Change-Id: Iea3201007bb98e6376fbb50be40a4a2e031b0a03
Signed-off-by: Peter Lawrence <majbthrd@gmail.com>
Reviewed-on: http://openocd.zylin.com/2369
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-11-03 19:30:59 +00:00
Paul Fertser
cbb797bdcc tcl/interface/ftdi/swd-resistor-hack: clarify and add schematic diagram
Change-Id: I8600ee983de85e4225430ae508a50cd938122d89
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2357
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-11-02 18:04:14 +00:00
Spencer Oliver
885f438814 cmsis-dap: add serial number support
Change-Id: I66926d1013e2b3a43ce0d18d3599771428706b6a
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2329
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-10-16 12:30:50 +00:00
Spencer Oliver
ef02315de3 cmsis-dap: refactor HID PID/VID check loop
In preparation for adding serial number support.

Change-Id: I3c9fb411b79d54a4d2de067039255436ba6708c7
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2328
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-10-16 12:30:45 +00:00
Spencer Oliver
c7de02d619 build: make makeinfo optional
This means the user does not have to install texinfo to build OpenOCD.

Change-Id: Id9f42da798d3c2b79e95214c9e2559cf32802251
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2325
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-10-16 12:30:26 +00:00
Spencer Oliver
1ea25b85bb cfg: remove incorrect execute permissions
Change-Id: I0ba9dfdf876bc99df4e2d1f1f3bc0c9ccc6c98c2
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2333
2014-10-06 18:56:14 +00:00
Rémi PRUD'HOMME
832f0a5bfb stm32: add mass erase support for STM32L
The mass erase for STM32L was lack because the procedure is more complex
than the procedure for the STM32F4xx.

The reference manual RM0038 (L100 subfamily) page 79 is more accurate
than the reference manual for the STM32L0xx. On the L0, the mass-erase
erase also the EEPROM. This is a limit to mass erase on L0.

The mass erase procedure is a command of telnet interface.

Tested on Discovery L053 and Discovery L100.

Change-Id: I6a1d7a3669789aea89c59a006ab2d883f3d827ca
Signed-off-by: Rémi PRUD'HOMME <prudhomme.remi@gmail.com>
Reviewed-on: http://openocd.zylin.com/2319
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 18:41:30 +00:00
Rémi PRUD'HOMME
b55ca1ad27 stm32: Add config file for a new board STM32L052 dsicovery
this board use STLink-V2-1, the STM32L1xx use the STLink-V2.

Change-Id: Ie58f45affcb1e9a6fed711b48c3c03b5035ab2b2
Signed-off-by: Rémi PRUD'HOMME <prudhomme.remi@gmail.com>
Reviewed-on: http://openocd.zylin.com/2317
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 18:41:24 +00:00
Rémi PRUD'HOMME
0187ced9ed stm32: add L0xx CPUTAPID
Add CPUTAPID for stm32 L0xx mcu devices. Using -expected-id to
add the new id with the id for L1xx devices. This for reduce the
duplicated code.

Change-Id: I48bd230884ecf38fa200c620b547bdf3b5f59132
Signed-off-by: Rémi PRUD'HOMME <prudhomme.remi@gmail.com>
Reviewed-on: http://openocd.zylin.com/2315
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 18:41:20 +00:00
Paul Fertser
cdcae765de flash/nor/stellaris: implement protection statuses and procedures
This should make protection work as expected on all stellaris
families, including the latest Tiva C Snowflake.

Run-time tested on TM4C123x (Blizzard).

Change-Id: Ia017edb119bec32382b08fc037b5bbc02dd9000c
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2267
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 18:40:46 +00:00
Paul Fertser
487c57d9a2 libusb: introduce jtag_libusb_choose_interface() and use it for JLink
This introduces a new common function that allows auto-discovery of a
suitable USB interface based on class, subclass and protocol
matching. It claims the interface and returns the corresponding
endpoints number to the caller.

The need for this arised due to nRF51822 USB dongle which comes with
an "on-board Segger J-link debugger" having 3 interfaces, so the
current code can't work at all with it (in this particular case the
last interface needs to be choosen). This also removes special
handling of JLink-OB endpoint numbers as it's now possible to
autodetect them as well as the standard JLink endpoints.

Change-Id: I4d990a7a3b373efdd2949a394b32d855a168e138
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2327
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 18:40:39 +00:00
Paul Fertser
b631e78b25 flash/nor/stellaris: actually enable protection and unprotection with ICDI
This is still limited to pre-Snowflake parts and the first 64K of
flash.

Change-Id: I9ca872ada3d1a87dba6261464b2a72a15eda5ecf
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2264
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 12:03:36 +00:00
Paul Fertser
1f6a66ab7f hla: add a way to pass arbitrary commands from user to layout and use for ICDI
TI's ICDI adapter supports some additional commands which a user might
want to run for debugging or other purposes, the most useful of them
being "debug unlock" that fully mass-erases the device and unprotects
the flash.

Change-Id: I26990e736094367f92106fa891e9bb8fb0382efb
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2263
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 12:03:30 +00:00
Paul Fertser
44394c2a77 interface/ftdi/olimex-arm-usb-ocd-h: fix nTRST control definition
According to my inspection of an Olimex ARM-USB-OCD-H adapter ACBUS0
is connected directly to an SN74LVC2T45 buffer input B2, and the
corresponding output A2 is connected directly to the JTAG
connector. It seems the information in the Olimex flyer is incorrect
for the -H version and TRST can't be tri-stated, ACBUS2 is unused.

The older ARM-USB-OCD device has SN74AC244 for an output buffer and
ACBUS2 controls its !2OE, ACBUS0 connected to 2A1 (2Y1 is nTRST), in
accordance with the information flyer.

Change-Id: I22828b7b959b6f62c3f51367feb8fab9705641e5
Reported-by: Tim Sander <tim@krieglstein.org>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2286
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Tim Sander <tim@krieglstein.org>
2014-10-06 11:59:48 +00:00
Anders
61d8b2cabf jtag/drivers/jlink.c: fix for LPC Link-2 running JLink firmware on Linux
Change 2288 fixed the extraneous reset caused by set_configuration that
crashed the LPC Link-2 running JLink firmware and works on windows platforms.
On Linux however, conditional code was still calling USB reset and caused
the adapter to crash on any non-windows platforms.

Change-Id: Ibf2a02d0dcdd91ccb71d86231cd8311dcadfee1e
Signed-off-by: anders@openpuma.org
Reviewed-on: http://openocd.zylin.com/2297
Tested-by: jenkins
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 11:58:57 +00:00
Anders
ca8f8e7e77 jtag/drivers/libusb1_common: avoid device reset when reselecting configuration
According to [1], we shouldn't reselect an already active configuration to avoid needless device reset. This is known to cause issues with e.g. LPC Link2 with JLink firmware.

[1] http://libusb.sourceforge.net/api-1.0/caveats.html#configsel

Change-Id: I3568ada77780a521548c450090db7173f8d0b2dd
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Signed-off-by: Anders Oleson <anders@openpuma.org>
Reviewed-on: http://openocd.zylin.com/2288
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 11:58:32 +00:00
Spencer Oliver
48a681c741 helper: constify log_strings
Change-Id: I5bdd8958e79b754d56bb7aee2892856e557eed76
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2296
Tested-by: jenkins
2014-10-06 11:57:44 +00:00
Spencer Oliver
3160c66408 target: constify structures
Change-Id: I875cfab8dec4ade72ed9c9cd7d52baaca182a1ef
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2295
Tested-by: jenkins
2014-10-06 11:57:40 +00:00
Spencer Oliver
b675edcc95 jtag: constify driver arrays
Change-Id: I81574fa8ca3cc748526dc61b75a2c75d6335ef04
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2294
Tested-by: jenkins
2014-10-06 11:57:36 +00:00
Spencer Oliver
36bc83b174 flash: constify driver data structures
Change-Id: Ia5c3de48119f036e1d7a41be62a672a6fb37e59b
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2293
Tested-by: jenkins
2014-10-06 11:57:32 +00:00
Spencer Oliver
03410e92da rtos: constify symbol names and lists
Change-Id: I72f3cd50fc6a33a178e72e169c9660e707751524
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2292
Tested-by: jenkins
2014-10-06 11:57:29 +00:00
Spencer Oliver
40815bd39a nuc1x: fix typos
Change-Id: Ia67b55ccb2bea71a99daa176def82960f487ca9f
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2291
Tested-by: jenkins
2014-10-06 11:57:26 +00:00
Andrey Yurovsky
db4b2c2536 at91samd: fix protect, add EEPROM and boot commands
There were two problems with the _protect() feature:
1. The address written was off by a factor of two because the address
register takes 16-bit rather than 8-bit addresses.  As a result the
wrong sectors were (un)protected with the protect command.  This has
been fixed.
2. The protection settings issued via the lock or unlock region commands
don't persist after reset.  Making them persist requires modifying the
LOCK bits in the User Row using the infrastructure described below.

The Atmel SAMD2x MCUs provide a User Row (the size of which is one
page).  This contains a few settings that users may wish to modify from
the debugger, especially during production.  This change adds commands
to inspect and set:
- EEPROM size, the size in bytes of the emulated EEPROM region of the
  Flash.
- Bootloader size, the size in bytes of the protected "boot" section of
  the Flash.

This is done by a careful read-modify-write of the special User Row
page, avoiding erasing when possible and disallowing the changing of
documented reserved bits.  The Atmel SAMD20 datasheet was used for bit
positions and descriptions, size tables, etc. and testing was done on a
SAMD20 Xplained Pro board.

It's technically possible to store arbitrary user data (ex: serial
numbers, MAC addresses, etc) in the remaining portion of the User Row
page (that is, beyond the first 64 bits of it).  The infrastructure used
by the eeprom and bootloader commands can be used to access this as
well, and this seems safer than exposing the User Row as a normal Flash
sector that openocd understands due to the delicate nature of some of
the data stored there.

Change-Id: I29ca1bdbdc7884bc0ba0ad18af1b6bab78c7ad38
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2326
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 11:56:40 +00:00
Andrey Yurovsky
592d0d514d at91samd: add erase/secure commands, minor fix
Reference code for the SAMD2x disables caching in the NVM controller when
issuing NVM commands.  Let's do this as well to be consistent and safer.

Add a "chip-erase" for the Atmel SAMD targets that issues a complete Chip Erase
via the Device Service Unit (DSU).  This can be used to "unlock" or otherwise
unbrick a chip that can't be halted or inspected, allowing the user to reflash
with new firmware.

Add a "set-security" command which issues an SSB.  Once that's done and the
device is power-cycled, the flash cannot be written to until a "chip-erase" is
issued.  The chip-erase cannot be issued by openocd at this time because
the device will not respond to a request for the DAP IDCODE.

Change-Id: I80122f0bbf7e3aedffe052c1e77d69dc2dba25ed
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2239
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 11:56:27 +00:00
Paul Fertser
ec9ccaa288 arm_adi_v5: make dap_lookup_cs_component() traverse subtables and handle multicore
When looking for a debug base address of a core, one should search
through all the ROM tables, not just the top-level one.

This code also assumes that the first found entry (in a depth-first
search) will correspond to core 0, the second to core 1 etc.

The patch is supposed to be an alternative implementation of
http://openocd.zylin.com/#/c/1313/.

Change-Id: Ifc88971a02fe3d9c00d9bf72a822ade5804d4e09
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/1920
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-10-06 11:54:54 +00:00
Paul Fertser
9c47dc9e8e doc/openocd.texi: add SWD to the transports supported by jlink
Since 6733253219 jlink adapter driver
supports SWD in addition to JTAG.

Change-Id: I9376aa02d9281f3e2734d8f127cd42162633d95b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2324
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-29 20:12:30 +00:00
Jon Burgess
1601c1a40b gdb_server: Include current RTOS thread in signal packets
This allows GDB to automatically switch to the thread that has
been interrupted and show you where it has stopped.

Change-Id: Icb9500dc42a61eb977e9fac55ce9503c9926bf5d
Signed-off-by: Jon Burgess <jburgess777@gmail.com>
Reviewed-on: http://openocd.zylin.com/2303
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-29 20:11:59 +00:00
Jon Burgess
0a5e03c12a cortex_m.c: Use two byte breakpoint for 32bit Thumb-2 request
When GDB requests a breakpoint on a 32bit Thumb-2 instruction it
sends a length of 3 which the current code rejects. Using the
existing two byte breakpoint for this case appears to work fine.

The use of length==3 for this case is mentioned in a few places:
https://sourceware.org/gdb/onlinedocs/gdb/ARM-Breakpoint-Kinds.html
http://sourceforge.net/p/openocd/mailman/message/30012280/

Change-Id: I59cd69ba4d1bc9a37b86569738c6bb2a67c3eb7a
Signed-off-by: Jon Burgess <jburgess777@gmail.com>
Reviewed-on: http://openocd.zylin.com/2312
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-29 20:06:41 +00:00
Simon Qian
b4f6338738 vsllink: improve the performance when using swd
Versaloon firmware has been updated for reporting
errors if fail on swd transactions.

Change-Id: I49ac0ad034cc9ad83cc4e43953579811d1243063
Signed-off-by: Simon Qian <openocd@versaloon.com>
Reviewed-on: http://openocd.zylin.com/2302
Reviewed-by: Fatih Aşıcı <fatih.asici@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-29 20:06:20 +00:00
Karl Palsson
54ff07808f tcl/board: add TI Tiva C ek-tm4c1294xl config
Change-Id: Iab070fe4c0f03ecc0db035b16dfb64105b0841be
Signed-off-by: Karl Palsson <karlp@tweak.net.au>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2063
Tested-by: jenkins
2014-09-29 20:04:30 +00:00
Andreas Fritiofson
c0b8e605f7 command: Fix confusing syntax error message
If the user executes a command with an invalid subcommand, the error
message is extremely unhelpful:

> flash write test.elf
flash write test.elf: command requires more arguments

This is because any command line that starts with a valid command group is
classified as a group, triggering ocd_bouncer to print the confusing
message.

Fix by requiring that to be a command group, the command line must not
contain any unknown tokens after the last valid (sub-)command group. That
is OK because command groups don't have handlers defined and thus can't
take any parameters.

Also fix the error message for "unknown" type to be similar to the error
message that is printed (by Jim) for non-existent primary commands.

Change-Id: I26950349f0909fd3961c4f9ab9b198c221cea9fc
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2285
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:40:38 +00:00
Andreas Fritiofson
1c021ed0af target: Remove "-variant" argument
Remove this underutilized feature. Despite the fact that a lot of configs
specifies a arbitrary "variant", only the xscale target actually defines
any.

In the case of xscale, the use of -variant is dubious since

1) it's used as a redundant irlen specifier,
2) it carries a comment that it doesn't really need it and
3) only two xscale configs even specify it.

If there's a future target that needs a variant set, a target specific
option could be added when needed.

Change-Id: I1ba25a946f0d80872cbd96ddcc48f92695c4ae20
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2283
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:39:24 +00:00
Joakim Gebart
b2973be9cc mpsse: Display libusb error names instead of numbers
Added calls to libusb_error_name() where applicable in order to easier
understand the error messages.

Change-Id: I3fe3d4b5624ae0de37c36e54a371eba5535ccaa1
Signed-off-by: Joakim Gebart <joakim.gebart@eistec.se>
Reviewed-on: http://openocd.zylin.com/2289
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:39:09 +00:00
Andrey Smirnov
9a42454c2b flash/nor/tcl.c: Do not double probe banks
Previous to this version the code of handle_flash_probe_command would
probe a bank twice: first time by auto-probe through a call to
flash_command_get_bank and second time by calling the probe function
directly. This change adds a flash_command_get_bank_maybe_probe wich
is a more generic version of the flash_command_get_bank, that would
allow commands to decide whether auto-probing should be performed or
not.

Change-Id: If150ca9c169ffe05e8c7eba36338d333360811e3
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2093
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:38:37 +00:00
Paul Fertser
e77b7447f7 target/arm_dpm: prevent endless loop in arm_dpm_full_context()
The code treats registers that are shadowed in FIQ mode in a special
way: to read them out the target is first switches to USR mode. But
since USR != ANY the current implementation later skips register read,
and the loop becomes endless in case any !valid ARM_MODE_ANY is
present at the moment arm_dpm_full_context() is called. This was
reported in https://sourceforge.net/p/openocd/tickets/76/. The issue
surfaced because 2efb1f14f6 added two
ARM_MODE_ANY registers ("sp" and "lr") which were not normally read,
so at the time a user was calling "arm reg" they were not valid.

Fix this by changing the mode appropriately while keeping the "mode"
variable state intact so it would later match register's mode.

Compile-tested only.

Change-Id: I01840e8fa20ec392220138a3f1497ac25deb080a
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2278
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:38:01 +00:00
Mahavir Jain
447fb25324 flash/nor: add mrvlqspi flash controller driver
This patch adds support for QSPI flash controller driver for
Marvell's Wireless Microcontroller platform.
For more information please refer,
https://origin-www.marvell.com/microcontrollers/wi-fi-microcontroller-platform/

Following things have been tested on 88MC200 (Winbond W25Q80BV flash chip):
1. Flash sector level erase
2. Flash chip erase
3. Flash write in normal SPI mode
4. Flash fill (write and verify) in normal SPI mode

Change-Id: If4414ae3f77ff170b84e426a35b66c44590c5e06
Signed-off-by: Mahavir Jain <mjain@marvell.com>
Reviewed-on: http://openocd.zylin.com/2280
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:37:09 +00:00
Mahavir Jain
e921c69e0e flash/nor/spi: Add Winbond w25q32fv flash support
Change-Id: I2919d462e04b489cc793b82ec347838a08cb8c48
Signed-off-by: Mahavir Jain <mjain@marvell.com>
Reviewed-on: http://openocd.zylin.com/2273
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:36:59 +00:00
Austin Phillips
7568a91c8e Support hla_serial command for ST-LINK adapters.
The hla_serial command allows for a programming device serial number to be
specified in addition to USB VID/PID.  This allows for multiple ST-LINK/V2
programmers to be attached to a single machine and operated using openocd.

Change-Id: I350654bf676eb26ba3a90450acfa55d2a5d2d791
Signed-off-by: Austin Phillips <austin_phillips@hotmail.com>
Reviewed-on: http://openocd.zylin.com/2198
Tested-by: jenkins
Reviewed-by: Martin Glunz <mg@wunderkis.de>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-22 19:36:05 +00:00
Andrey Skvortsov
3a4ec66b24 jtag: drivers: stlink: remove unnecessary '\n' in LOG_* entries
Change-Id: Ia2dc3efc27b53334af4d85f9807abba0463c291b
Signed-off-by: Andrey Skvortsov <andrej.skvortzov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2220
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-15 08:39:16 +00:00
Anders
dd93e0662e flash: added new Spansion S25FL116K, S25FL132K, and S25FL164K devices
The new FL1-K family is replacing the FL-K family. The data from all
three was based on the datasheet. In addition the 8MB S25FL164K was
tested successfully with OpenOCD on a custom board.

Change-Id: Idafeed86da12a481c0db92cc0de7ba28f50c2252
Signed-off-by: Anders <anders@openpuma.org>
Reviewed-on: http://openocd.zylin.com/2281
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-15 08:23:44 +00:00
Andrey Yurovsky
4efb3ebb76 stm32lx: don't allow part_info to be uninitialized
It's possible for us to fail to read the part ID code so make sure that
part_info is initialized to NULL before attempting to do so, otherwise
we could proceed and use it uninitialized and then segfault.

Change-Id: I0a3f3d3947690b66f0981b5046340449521e0b33
Signed-off-by: Jack Peel <jack.peel@synapse.com>
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2276
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-15 08:23:12 +00:00
Andreas Fritiofson
45f01e0a12 cortex_m: Check return value from cortex_m_dcc_read.
Caught by clang.

Change-Id: I26d2b845aca431612862ef432b217ca397d9b893
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2279
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-15 08:22:56 +00:00
Nemui Trinomius
910972fcec cfg: Added Nucleo-F411RE board config.
It supports STLink/V2-1 debug adapter.

Change-Id: Ifbc610cd68ec929608369e69d0b1395fe04956cd
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2259
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-09-15 08:21:05 +00:00
Paul Fertser
1f4b0190e8 tcl/board/sheevaplug: add adapter_khz setting
This combination is known to work properly with 2MHz JTAG clock.

Change-Id: Ie5ec3d3b415efbb13faee7d34e0c7f862b78350c
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2266
Tested-by: jenkins
2014-09-15 08:20:05 +00:00
Paul Fertser
eab9af185e tcl/interface/ftdi/sheevaplug: fix device description
Without this SheevaPlug debugging interface can't be matched.

Change-Id: Ifca149130d03c1aa165ed1123e8540e49485f023
Reported-by: Andreas Schneider <schneider.andi@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2265
Tested-by: jenkins
2014-09-11 21:35:00 +00:00
Vanya Sergeev
b5a6ba46aa cfg: refactor lpc1xxx targets onto one base config
Since now auto-detection for flash size works nicely, there's no
reason to keep numerous configs around.

Change-Id: If0cbc37985abf17ef7c1f7d0688e76500fac228f
Signed-off-by: Vanya Sergeev <vsergeev@gmail.com>
Reviewed-on: http://openocd.zylin.com/1960
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-09-08 23:05:08 +00:00
Бурага Александр
1e439e2a9a tcl/target: add config for К1879ХБ1Я, a hybrid ARM11/DSP SoC by RC Module
This adds config to allow JTAG debugging of an ARM core of a modern
hybrid SoC by Research Centre "Module"
(http://www.module.ru/en/company/). К1879ХБ1Я is targetted at set-top
boxes and other multimedia equipment, the official SDK is Linux-based.

Change-Id: Ib2ae5784d25699f952682e66b025a3f677a76d5d
Signed-off-by: Бурага Александр <dtp-avb@yandex.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2272
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 22:26:35 +00:00
Nemui Trinomius
de16280e02 stm32f2x: added STM32F411xx series support.
Added STM32F411xx series to flash driver.

Tested on NUCLEO-F411RE board(STM32F411RET6).

Change-Id: Id7d1f2858c09815a013e0590e65ad193fb039157
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2258
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 21:34:25 +00:00
Paul Fertser
28b0019803 tcl/interface/ftdi: fix TRST for Olimex TINY adapters
According to the research by Eldar, TINY-H adapter has nTRST connected
to ACBUS0 directly via a 100 Ohms series resistor. I think it's safe
to assume the older TINY adapter does the same.

See high-res photos at [1].

This patch should fix issues with JTAG for the case when nTRST is
actually connected but is missing from the config.

[1] https://wikidevi.com/wiki/Olimex_ARM-USB-TINY-H

Change-Id: Iaaee7be30536ebb502802d38b82cd9573408f854
Reported-by: Хайруллин Эльдар <eldar.khayrullin@mail.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2247
Tested-by: jenkins
Reviewed-by: demokmail <demokmail@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 21:15:33 +00:00
Paul Fertser
5774894a64 flash/nor/stellaris: add all Tiva C parts IDs
Luckily, TI's website has predictable URLs for the datasheets, so it
was trivial to download all the pdfs corresponding to the currently
available 71 TivaC devices. Then they were processed with pdftotext
and parsed by this script:

BEGIN { capture = -1 }
/^Device Identification 0 \(DID0\)$/ { state = "waitingclass0" }
/^Device Identification 1 \(DID1\)$/ { state = "waitingpartno0" }
/^CLASS$/ { if (state == "waitingclass0") state = "waitingclass"
    else if (state == "waitingclass") capture = 4 }
/^PARTNO$/ { if (state == "waitingpartno0") state = "waitingpartno"
    else if (state == "waitingpartno") capture = 4 }
(FNR == 3) { family = $2 }

{
    if (capture >= 0) {
	if (capture == 0) {
	    if (state == "waitingclass")
		class = $0
	    else if (state == "waitingpartno")
		partno = $0
	}
	capture--
    }
}

END { print "{" class ", " partno ", \"" family "\"}," }

Change-Id: I6820c409fe535f08394c203276b5af4406fe8b92
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2262
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 20:31:55 +00:00
Paul Fertser
76cabfc311 flash/nor/stellaris: improve support for Tiva C (Blizzard and Snowflake)
This should make current Tiva C parts usable apart from the protection.

Runtime tested on TM4C123GXL (Blizzard) and TM4C1294XL (Snowflake).

Change-Id: Ia64e9d39fbd2b7049578bbfade72435e5203ddf5
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2257
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 20:29:29 +00:00
Paul Fertser
804aee7702 tcl/interface/ftdi: add kt-link config (with SWD) for DP BusBlaster
Change-Id: Icbeca8c0c3845c0b777fb2e4c81b17e7b7cc5ff8
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2269
Tested-by: jenkins
Reviewed-by: Ben Gamari <bgamari@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 20:27:16 +00:00
Paul Fertser
96549bf012 jtag/drivers/libusb0_common: fix FTBFS (libusb_device_descriptor error)
This struct and libusb_get_device_descriptor() method are not present
in libusb-0.1 API, so when libusb-1.0 is unavailable, this code breaks
the build. Fix by using the appropriate struct (which is apparently
filled automatically on device initialisation).

While at it, change return values for consistency with the callers.

Change-Id: I7d85ab9a70401a155a65122397008ae4d81382fe
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2252
Tested-by: jenkins
Reviewed-by: Austin Phillips <austin_phillips@hotmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 20:23:15 +00:00
Paul Fertser
b171c7ab16 tcl/target/imx6: add yet another SJC tapid
This is for mx6q TO1.1.

Change-Id: Id6af2ed232fc19be9bf49eb6d2df0004c6668698
Reported-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2253
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-09-08 20:21:37 +00:00
Paul Fertser
f8318d1b0d target/adi_v5_swd: fix segfault when calling jtag_to_swd
When SWD mode is not supported by the target adapter, the call should
return an error instead of segfaulting.

Change-Id: I1626097deb93ecfbe78a6e82d812c7a673dbbde5
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2256
Tested-by: jenkins
2014-09-08 20:18:51 +00:00
Paul Fertser
bd0409aa93 jtag: always configure enabled tap parameter appropriately
Commit f701c0cb seems to have introduced a regression for non-JTAG
transports as the newly created "tap" (DAP actually) ended up being
disabled, thus resulting in total lack of functionality.

This was exposed by a debug log demonstrating ftdi SWD transport
connection to mdr32f9q2i, the target wasn't examined on init and
couldn't be reset.

Change-Id: If53cbe800d4adc177aa3ac3219860e7fa15b3e49
Reported-by: Хайруллин Эльдар <eldar.khayrullin@mail.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2261
Tested-by: jenkins
Reviewed-by: Angus Gratton <gus@projectgus.com>
Reviewed-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-22 07:38:42 +00:00
Angus Gratton
f0dfa136ad target async loader: add offset to debug lines
This was very helpful when debugging programs during async loading.

Change-Id: Ia2eacc3e105403f70f51b1242b675e2ffe86e8ca
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2203
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-19 20:32:45 +00:00
Andrey Yurovsky
3751214b9c stm32lx: refactor and add support for STM32L0xx
This adds initial support for the STM32L0 family, specifically the ID
code 417 variant.  The 'L0 has 128B rather than 256B pages as well as a
different number of pages per sector.  It also has several key registers
and register sets in different locations from the STM32L1xx parts.

This change therefore takes the opportunity to reorganize part information into
a const table (it was previously determined by a set of control statements) and
abstracts away some of the low-level details to make them generic for L1 and
L0 parts.

We also include the first bank's size (for dual bank parts) in the new
device information table (and correct that size for the 0x437 variant
which is 256 rather than 192KB).

The 'L0 parts will not use the built-in loader/helper for Flash writing.

Tested on STM32L053 (dicovery board and Nucleo board) and STM32L152
(discovery board).

Change-Id: I57f7a8ab02caee266de71b31ae82a50d85728a0b
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2200
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-19 20:32:07 +00:00
Angus Gratton
d50cc1bfea jtag/drivers/ftdi: Use adapter_khz value for initial clock speed (was default 1kHz)
nrf51822 doesn't like a 1kHz initial clock rate, puts the DAP into a bad state.

Mailing list discussion thread: http://sourceforge.net/p/openocd/mailman/openocd-devel/thread/20140718081528.GA5554%40ex2.lan/#msg32621853

Change-Id: I71aa75505cc1b41ee80c7b9db415f6ac738c2916
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2223
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-19 20:26:26 +00:00
Andrey Yurovsky
32e0fa6bcb flash: samd: add missing ID for SAMD20E18A
This was somehow missed in the chip ID table and of course that's
exactly the one on my board (as such, tested on hardware).

Change-Id: I212d7c729d979e0357f1d4635f40935e25fe6ff3
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2260
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:24:02 +00:00
Spencer Oliver
47eceaa229 jlink: Constantify string arrays
Change-Id: Ib63f4c32e6d5a7dad21567521d938142ea40b308
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2245
Tested-by: jenkins
2014-08-19 20:23:18 +00:00
Spencer Oliver
83265a4c70 jlink: add variant "J-Link Lite-ADI"
Fitted to various Analog Devices ADuCM36x dev boards.

Change-Id: Ib3691704c0ecd2f8cba1abba284aee695d6bc135
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2244
Tested-by: jenkins
2014-08-19 20:23:15 +00:00
Spencer Oliver
c1c613bdbb jlink: fix typo
Change-Id: If495b819c0532a97447ec7208c13d8a66a3ad47d
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2243
Tested-by: jenkins
2014-08-19 20:23:12 +00:00
Paul Fertser
0c4e991b76 flash/nor/stm32f1x: add STM32F302x6/8 IDs, clarify STM32F302xB/C
Change-Id: I22afbe30f32b0ea9b59c3de8d15ce14bdc4763cc
Reported-by: Luis Rodrigues <lfrodrigues@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2249
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:21:34 +00:00
Robert Jarzmik
73123ccc57 jtag: usb_blaster: fix initialization regression
As Daniel pointed out, since the rewrite of the USB Blaster driver, the
initialization behaviour has change. The initial flush of the FIFOs is
not longer done with a specific USB setup packet, but with a write
filling up the blaster queues.

The problem is, quoting Daniel :

    When the CPLD is in bit banging mode (as is usually the case), the
    first 0x00 byte sets all pins to low and disables the output
    driver. Disabling the output drivers is a few nanoseconds slower
    than changing a pin from high to low, so I see a spike towards GND
    on my reset line when that byte is sent over USB. The spike is too
    short to have an effect on the board.

    When the 4096 0x00 bytes are processed and the TMS=1 is to be
    generated, all I see is several microseconds of low level on all
    pins, resetting my board.

This patch changes the way the initialization is done :
 - at driver init, nothing is sent towards the usb-blaster
   This gives time for init script to setup PIN6 and PIN8 (resets)
 - at the very first driver command, the initialization is done :
   - the output is in bit bigbang mode
   - the PIN6 and PIN8 are computed according to init script
   - the 4096 computed output is sent

Change-Id: If7ceee957f6b59bcb27c8f912f1cfdd0f94f75ed
Reported-by: Daniel Glöckner <daniel-gl@gmx.net>
Cc: Franck Jullien <franck.jullien@gmail.com>
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Reviewed-on: http://openocd.zylin.com/2229
Tested-by: jenkins
Reviewed-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-by: Daniel Glöckner <daniel-gl@gmx.net>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:21:02 +00:00
Paul Fertser
80ea805332 transport: emit a warning when a user tries to reselect a transport
Even though changing transport is impossible, reselecting it should be
harmless.

Change-Id: I6c1c2786134e826f47f848b590e6d712b6fd2206
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2251
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:19:58 +00:00
Paul Fertser
8390f71428 tcl/interface/ftdi: auto-select SWD from converters' configs
When you source a JTAG-SWD converter config, any other transport
doesn't make any sense, so just autoselect it right there.

Change-Id: I6c098740905a0d4007473fc19cc07e11cbcc9369
Suggested-by: Хайруллин Эльдар <eldar.khayrullin@mail.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2248
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Eldar Khayrullin <eldar.khayrullin@mail.ru>
2014-08-19 20:19:40 +00:00
Eldar Khayrullin
877b8434cd tcl/board/stm32ldiscovery: fix breakage
Change-Id: I450ea82c27009be6bad6a7814969d81964ff44d8
Signed-off-by: Eldar Khayrullin <eldar.khayrullin@mail.ru>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2255
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:18:54 +00:00
Oleksij Rempel
9402f8dc4e mips_m4k.c: EJTAGBOOT and NORMALBOOT are not supported on EJTAG 2.0
Change-Id: I8157c19e9d8aed5c2376a2c54c32c1ddac1ad5af
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1934
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:18:16 +00:00
Oleksij Rempel
ecb6f8c23e mips_m4k.c: D or I breaks only if they supported.
For example Realtek RTL8186 (Lexra LX5280 core) don't
support break- and watchpoints.

Change-Id: Ie00102da4bf13a8c42a9ad05910c66884f297cfd
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1933
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:18:09 +00:00
Oleksij Rempel
02ac60b000 mips32.c: cache debug caps and support EJTAG 2.0 specific changes
EJTAG v2.0 indicated some debug caps in IMP register.
V2.6 moved them to DCR register. To make it more universal,
convert this values and store them for later use.

Change-Id: Id6b9f47c9c2ea94d37281ebfcae5acf357261ddf
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1932
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:18:02 +00:00
Oleksij Rempel
c13ca4de40 mips32.c: fix IB and DB bits check for EJTAG v2.0
Change-Id: I4e28dddc1d5d9c2b923ae17beacdd7f73591b1d0
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1931
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:17:55 +00:00
Oleksij Rempel
91bfd9dbf2 mips_ejtag.c: do not set v2.6 ECR bits on v2.0 devices
Change-Id: I894abbb923282d5f84daf8e0bca69190c07567de
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1930
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:17:43 +00:00
Oleksij Rempel
ed085f379e mips_ejtag.c|h: use version specific IMPs
and make version specific debug log

Change-Id: I17f7ff757cfa1264a1dadbfe20c5e21de62ef87a
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1929
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-08-19 20:17:30 +00:00
Cristian Maglie
1fa24ebe39 Removed limit on lenght of command line options.
In particular -f and -s options may contains paths that can easily
exceed the (old) 128 bytes buffer.

Change-Id: Ifc198536549f50663e8e588519bb9ef75dcd172c
Signed-off-by: Cristian Maglie <c.maglie@bug.st>
Reviewed-on: http://openocd.zylin.com/2241
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-12 21:04:27 +00:00
Andrey Smirnov
5587013ad6 tcl/board: Add board configuration for nRF51822-mKIT
Add board configuration for Nordic's nRF51822-mKIT devkit, available
here:
http://mbed.org/platforms/Nordic-nRF51822/

Change-Id: Ib9329307147b1e7be061a5060b4eec8256fe2bd4
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
[gus@projectgus.com: Minor tweaks, model number]
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2116
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 22:37:11 +00:00
Angus Gratton
9fce8a21ca stlink_usb: Fix swallowed error on read/write operations, add retries on SWD WAIT, clean up error debug output.
- stlink_usb_get_rw_status() had a bug where FAULT or WAIT responses
  in read/write operations were ignored, leading to incomplete data.

- Added wrapper stlink_cmd_allow_retry to handle
  SWD_AP_WAIT/SWD_DP_WAIT statuses in most commands. These statuses
  appear if an SWD read or write received a WAIT ACK response from the
  target more than 4 times in a row. The driver retries the operation
  (with exponential backoff) before failing outright (in testing 1
  retry was always enough.)

- As part of the implementation of stlink_cmd_allow_retry a large
  number of lines of boilerplate were refactored.

- Fleshed out stlink_usb_error_check and added it to some more code
  paths so WAIT or FAULT responses are logged to debug. WAIT responses
  will be logged even if they are subsequently retried, which should
  help in case the retries have subtle side effects (none
  anticipated.)

Tested with two targets: STLINK F0 Discovery, Nordic NRF51822. Only
tested with STLINK V2 programmers.

Change-Id: I9af24e8f0121b035356dbb9978d6bbf4feb2e4d3
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2201
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 22:34:52 +00:00
Angus Gratton
6d26e3e768 nRF51822: Add workaround for PAN-16 where not all RAM blocks reliably enabled on reset
According to Nordic Semiconductor Product Anomaly Notice (document
NRF51822-PAN), item 16, some revisions of nRF51822 sometimes reset
without all RAM blocks enabled. This was noted on NRF51822-QFAA rev
CA/C0, only 8KiB of memory was accessible.

This patch turns on all RAM following a debugger induced reset
(matches specified behaviour.)

Change-Id: I4f8be4ec3d1271da7fe5bc9a084fdcb2968535bb
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2202
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 22:26:44 +00:00
Andrey Skvortsov
4949757473 tcl/target: added support for TI OMAP/AM 3505 and 3517
added TAPID for OMAP/AM 3505 and 3517. Tested on TAM3517 Twister board
with AM3517 SoC.

Change-Id: I78a3268a4adb18092c694a556538c99c9032f648
Signed-off-by: Andrey Skvortsov <andrej.skvortzov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2127
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 21:27:21 +00:00
Paul Fertser
c7384117c6 Allow transports to override the selected target (hla configs unification)
This should allow to share common configs for both regular access and
high-level adapters.

Use the newly-added functionality in stlink and icdi drivers, amend
the configs accordingly.

Runtime-tested with a TI tm4c123g board.

Change-Id: Ibb88266a4ca25f06f6c073e916c963f017447bad
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
[gus@projectgus.com: context-specific deprecation warnings]
Signed-off-by: Angus Gratton <gus@projectgus.com>
[andrew.smirnov@gmail.com: additional nrf51.cfg mods]
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Tested-by: Andrey Skvortsov <andrej.skvortzov@gmail.com>
Reviewed-on: http://openocd.zylin.com/1664
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 21:25:56 +00:00
Angus Gratton
f701c0cbeb newdap: Ignore -irlen/-irmask/etc newdap params on SWD or CMSIS-DAP
Previously the -irlen parameter was required even though it is not
a part of the SWD or CMSIS-DAP transports.

This may eventually need to be changed for CMSIS-DAP once that
supports JTAG as well.

Change-Id: Ia02b67840c19c7cf1c7a75063648c0174176a311
Signed-off-by: Angus Gratton <gus@projectgus.com>
Reviewed-on: http://openocd.zylin.com/2226
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-11 20:49:05 +00:00
Andreas Fritiofson
e1bc7f4545 interface/ftdi: Mark flyswatter.cfg as tested
- Flyswatter + Proxmark3 (Atmel AT91SAM7S256) - works
- Flyswatter + Tiva Launchpad (EK-TM4C123GXL) - works

Change-Id: I615e0ff9262be6ae1064fb2de8e6e810775e7db4
Tested-by: Ondrej Mikle <ondrej.mikle@nic.cz>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2237
Tested-by: jenkins
2014-08-04 11:09:48 +00:00
Andreas Fritiofson
f75345b915 drivers/jlink: Revert old workaround
This workaround broke usage with at least the I.MX6Q.

The comment implies that talking to the J-Link dongle itself should
fail if the target isn't reset, which sounds really strange. I'm
guessing it just triggered another bug in OpenOCD or Segger FW which
might have been fixed since. Revert and wait and see if there are any
failure reports.

Tested with Kwikstik (J-Link + Kinetis K40), not with the mentioned
adapter.

Change-Id: I97f555efe079bd99c098bf483491d9509b2363ad
Signed-off-by: Roy Spliet <rspliet@mpi-sws.org>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2147
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-08-02 13:54:39 +00:00
Paul Fertser
66e20117e8 drivers/jlink: fix SWD speed config, and set it before sending anything
During the initialisation a driver might need to communicate with the
target (e.g. sending jtag2swd sequence), so when doing so it should
honour the user-specified speed.

Change-Id: If84fea6057fda9edcf2c0a653edfbab2500e3cdd
[andrew.smirnov@gmail.com: fix khz/hz confusion]
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2224
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-02 13:53:59 +00:00
Paul Fertser
6733253219 drivers/jtag/jlink: support SWD mode
Quick attempt at SWD support, closely modelled after ftdi.

Change-Id: I25140d80c5be7b2f8f0e2ef722a4ba4df0da4cf3
Signed-off-by: Brian Campbell <Brian.Campbell@ed.ac.uk>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2141
Tested-by: jenkins
Reviewed-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-02 13:53:33 +00:00
Paul Fertser
e2b1f06f93 tcl/board: fix all the remaining boards that were sourcing ft2232 configs
This was reported in
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=751372 .

Change-Id: I258f3d40593ff2966ce3ca61c13a23699d1b162f
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2230
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-02 09:04:19 +00:00
Andreas Fritiofson
91e47f3ab8 Fix some problems with the bin2char utility
Don't hardcode the type for the array, just output the array initializer
so the includer can choose the type and storage class, zero-terminate at
will and so on.

Change-Id: I6d5e0710eaaba0a218b3eb32f6569177356f4462
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2176
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-08-02 09:01:32 +00:00
Paul Fertser
f1b04a20dc Provide od+sed replacement for the bin2char helper
Using custom build-time tools is always more problematic, especially
for cross-compiling.

This alternative implementation assumes "od" (IEEE Std 1003.1-2001)
and sed are available which should be the case for any reasonably
modern system.

Change-Id: I0208f475648c78e7dca127ff4bab60d314b2bf53
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2139
Tested-by: jenkins
Reviewed-by: Fatih Aşıcı <fatih.asici@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-08-02 09:00:28 +00:00
Fredrik Hederstierna
e03eb89cfb tcl/board: add STM32429I-EVAL and STM32439I-EVAL dev boards from ST.
Change-Id: I304b6e7bae832391f11d53003299d68e31b0e4ef
Signed-off-by: Fredrik Hederstierna <fredrik@hederstierna.com>
Reviewed-on: http://openocd.zylin.com/2171
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-07-10 21:19:35 +00:00
Paul Fertser
333df54fb7 tcl/target/stm32l: restore slow clock on reset
Change-Id: I63eafaa38b188fe50c13ab966be44a3eaa2006b0
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2188
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-10 21:18:45 +00:00
Thomas Schmid
48d2431968 Adding support for the Atmel SAMR21.
The Atmel SAMR21 is a Atmel SAMD21 with an Atmel RF233 in one package (two
dies). Tested with the SAMR21 Xplained Pro eval kit.

Change-Id: I1d79ea05834b925d7ec810527206fe86854e684b
Signed-off-by: Thomas Schmid <thomas@rfranging.com>
Reviewed-on: http://openocd.zylin.com/2194
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-10 21:18:30 +00:00
Masaki Muranaka
11274d2283 drivers/cmsis_dap_usb: Return with ERROR_FAIL if no CMSIS-DAP device is found.
Even if it does not return, the initialization will be failed.
But it is better to show why the error is caused.

Change-Id: I399c7c94a7156be22723a9715e594061bb414a7e
Signed-off-by: Masaki Muranaka <monaka@monami-ya.com>
Reviewed-on: http://openocd.zylin.com/2189
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-10 21:18:08 +00:00
Oleksij Rempel
915e06b3f0 mips_m4k.c: make sure fast_data_area is safe
If load_image address overlap with fast_data_area,
it will caouse different mysterius issues. This patch
should prevent it.

Change-Id: Ibc95e5aa3ac002a59755029496b6a72616e9287f
Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-on: http://openocd.zylin.com/1854
Tested-by: jenkins
Reviewed-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-10 20:00:22 +00:00
Andreas Fritiofson
518ce9e19e cfg: Rename leftover cortex_a8 -> cortex_a
Change-Id: Id11d89ae2fb78854da4284afb7f14d8a892a2e49
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2197
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-08 19:33:18 +00:00
Nemui Trinomius
287d6e033a kinetis : Added Kinetis-K Series MDM-AP ID.
Kinetis-K series has ID:0x001C0000 on MDM-AP IDR register.
Other Kinetis(L/M/V/E) series have ID:0x001C0020.

Change-Id: Iada37038cd239f7331ba80a3673b36bf7e18c555
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2195
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-07-04 10:06:01 +00:00
Kamal Dasu
59c2239bfd cortex_a: target implementation renames cortex_a8 to cortex_a
A previous commit changes the target name used by tcl scripts.
commit d9ba56c295
target: rename cortex_a8 to cortex_a

The current change renames target functions and definitions in the
implementation from cortex_a8 to cortex_a.
This prepares the implementation to support Cortex-A8, A9, A15-MPCore
in one place.

Change-Id: I73b5a38a92c12ba5bd3b806fbbb664817575a6d7
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Reviewed-on: http://openocd.zylin.com/1599
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-07-03 21:45:04 +00:00
Fatih Aşıcı
84281d711e vsllink: Port to libusb-1.0 API
Change-Id: I8a9a4dace8e7e8152947094b27b86f9a0d90fa61
Signed-off-by: Fatih Aşıcı <fatih.asici@gmail.com>
Reviewed-on: http://openocd.zylin.com/1952
Tested-by: jenkins
Reviewed-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-07-03 19:43:16 +00:00
Fatih Aşıcı
5f9c59409b vsllink: Add SWD support
Tested with stm32f1x, stm32f4x and kl25 targets using SWD transport.

Change-Id: I118d07371b53f402ea9ac73f874460a309c05100
Signed-off-by: Fatih Aşıcı <fatih.asici@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1947
Tested-by: jenkins
2014-07-03 19:43:01 +00:00
Paul Fertser
d48b47e432 jtag/drivers/opendous: remove ftime() calls
ftime() is deprecated by POSIX.1-2008 and causes a warning on
FreeBSD.

The generic OpenOCD LOG_DEBUG implementation already outputs time of
an event with a millisecond precision.

Change-Id: Ic8e4ea27c268f07554ba519768b9bdfc4343f3e9
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2187
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-03 18:41:39 +00:00
Paul Fertser
3039f01aaf drivers/cmsis_dap_usb: restructure init sequence a bit
This fixes the issue of improper initialisation sequence and in
particular makes "cmsis_dap_vid_pid" config specification functional.

Not really elegant but it's in line with the ftdi driver and so can be
reworked in a uniform way later when the internal API is changed.

Change-Id: Ief9fc64ad0ac24e1c66727153f383e4f30a830c7
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2192
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-03 18:40:59 +00:00
Paul Fertser
aa79f7b7e0 jtag/drivers/cmsis_dap: fix check for hardcoded vids/pids
This is intended to fix cmsis_dap_vid_pid command but it doesn't
because cmsis-dap has only one transport and it's auto-selected from
"interface" command handler (before any other commands are run) and as
the result cmsis_dap_usb_open() is called too early.

Change-Id: Idaade73797d8df67a6439d096f6abc9736495599
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2191
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-07-03 18:40:49 +00:00
Kamal Dasu
a74b5687a7 Openocd: svf: Add ability to ignore svf_check_tdo errors
Added Openocd commandline argument to ignore_error when the
read back TDO does not match to expected value specified with
TDO after masking with what is specified in MASK. This allows
to continue to play entire SVF file ignoring errors.
Error logs clearly show the failure reason and prints
read back TDO value.

Change-Id: I324f476fc16a003b35e6f2c5b63976431f49d54a
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Reviewed-on: http://openocd.zylin.com/2129
Tested-by: jenkins
Reviewed-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-07-03 18:08:48 +00:00
Mathias K
7c101b9e31 Add error handling and remove double readout.
Remove double readout of DCB_DHCSR in target poll. The return value
of the endreset event is handled and not ignored in target poll.

Change-Id: I8fe026418dadcf0b0dcbb09acee871ad950937a2
Signed-off-by: Mathias K <kesmtp@freenet.de>
Reviewed-on: http://openocd.zylin.com/1181
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-06-28 18:50:53 +00:00
Paul Fertser
52b80fbd82 jtag/drivers/ftdi: do not touch unavailable reset signals
If the current reset_config doesn't specify availability of nTRST or
nSRST, just leave them alone, do not try to deassert them ever
(asserting would be prevented by the upper layer).

Change-Id: I90123c666e05a1c26f1e164625e82d766a3e3744
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2186
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 16:52:08 +00:00
Spencer Oliver
eeff8eec6c cfg: add SWD configs for stellaris ftdi based adapters
Tested on hardware.

Change-Id: Ib0191e97988dc79e9a62da74bd7fe25f548ff5a2
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2185
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
2014-06-28 09:37:14 +00:00
Paul Fertser
e2a7990aac tcl/interface/ftdi: add SWD configs for kt-link, olimex, rowley and resistor hack
Resistor hack is runtime-tested, other configs are based on
schematics.

Change-Id: I8daffa0434cd41d142fbec7c230a302284f7aa31
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2184
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-06-28 09:37:05 +00:00
Paul Fertser
bf96df255e jtag/drivers/ftdi: require defining SWD_EN signal for SWD mode
Use a special signal instead of a dedicated swd mask. Amend
jtag-lock-pick_tiny_2 config accordingly.

Change-Id: Ifb007a0b5434b590c52f936efd5f5458e913e2e4
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2183
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2014-06-28 09:36:53 +00:00
Paul Fertser
64d02ccf82 jtag/drivers/ftdi: declare standard JTAG signals on SWD init
Unfortunately, this means they're available for config files only
after selecting swd transport.

Change-Id: Ia2afc1f3bfdba8d81efbb8ab964b174c0f7e2811
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2182
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 09:36:17 +00:00
Paul Fertser
a87e699edf jtag/drivers/ftdi: add option to declare signal aliases
This adds -alias|-nalias options to ftdi_layout_signal command that
allow to declare a new signal based on an already defined one.

Change-Id: I552578ebcd12ae21957a1c0d3b7e878adeff6df0
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2181
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 09:36:02 +00:00
Paul Fertser
335bafbb25 Auto-select JTAG transport when appropriate
I looked through all the target configs after stripping comments and
such from them with sed to see what jtag-specific commands can appear
first, and it looks like all the meaningful combinations should be
covered.

Change-Id: I8d543407b7f4ac8aca7354ecd50e841c8a04d5f3
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2179
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 09:35:38 +00:00
Andreas Fritiofson
12e9f6292b Relax polling check if not in JTAG mode
Polling was disabled based on global variables jtag_trst and jtag_srst
which were never touched in non-JTAG mode. Modify the check and remove
the ugly workaround to avoid calls to a possibly uninitialized JTAG
subsystem.

Change-Id: I3b18c81e0fba7aaf35afe6f08c3fe8fa6f8443fd
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2143
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:34:55 +00:00
Andreas Fritiofson
baf998b9f8 cfg: Add SWD support to JTAG-lock-pick Tiny 2
Change-Id: I61eac507fa6861b7daf603ebca58e8bf3cc699c1
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2136
Tested-by: jenkins
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:34:39 +00:00
Andreas Fritiofson
cdd8928a56 Add FTDI SWD driver
This is usable on most or all FTDI adapters using a small hardware tweak.

TCK goes to SWCLK as expected. TDO should be wired to SWDIO. For TDI there
are two options:

Either add a 74HC126 or similar tri-state buffer between TDI and SWDIO,
with OE controlled by a signal named SWDIO_OE. Or simply connect TDI and
SWDIO together via a suitable resistor (220-470 ohms or so depending on
the drive capability of the target and adapter).

nSRST (and of course Vcc, GND) may be connected too but all other signals
should be NC.

Change-Id: Id36cf4577439be96bd4e5955c3026236e1cabced
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1958
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:34:26 +00:00
Andreas Fritiofson
cc99e57b0e transport: Constify the transports vector
Change-Id: I0c874b5d4c97cf781d83bd381d701f770e069f72
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2135
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:33:31 +00:00
Andreas Fritiofson
ae3bcd05f8 swd: Add frequency setting and special/switching sequences to the API
Change-Id: I6f3950374f2525a18bbcb9cbd340c447c20fb704
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2134
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:33:12 +00:00
Andreas Fritiofson
003f8a1d04 adi_v5: Make sure all bit masks are unsigned and wide enough.
Also align them with spaces instead of tabs.

Change-Id: I1c01412a3ea77b29e8e133f5c92d05ed79d7c0f3
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2133
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:32:41 +00:00
Andreas Fritiofson
5a7eae940b swd: Remove support for turnaround periods other than 1
ARM deprecated other trn periods in ADIv5.1 and one cycle is the only
setting that is guaranteed to be implemented, as well as being the reset
value in ADIv5.0.

Thus it makes no sense supporting anything else.

Change-Id: Iffa16bb0ce74788bca88fd3ace8a026148013d00
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2132
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:32:21 +00:00
Andreas Fritiofson
bc91cdad3c swd: Fix park bit polarity according to ADIv5.1 Supplement
Change-Id: I27293defd3f3c3bf37c9662f88689e85ba593d86
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2131
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:31:55 +00:00
Andreas Fritiofson
d2bb14e36a swd: Convert API to asynchronous
Change-Id: I859568dbb2ad4e92411980751c3f747bd70638b8
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1959
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:31:38 +00:00
Andrey Smirnov
2268b77142 adi_v5_cmsis_dap.c: Simplify debugging output
Name of the function is already a part of the LOG_DEBUG macro, so
there's no need to include it in the string itself.

Change-Id: I18c3d5b746e9106d55104e490ccf5bc5e85cc380
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2138
Tested-by: jenkins
2014-06-28 09:31:10 +00:00
Andrey Smirnov
ccf4d6d648 cortex_m: Do additional initialization during reset
SAM4L requires additional steps to be taken right after SYSRESETREQ is
issued in order to function robustly:

       - CMSIS-DAP DAP driver needs to explicitly check for sticky bit
         errors since it is possible for adapter to perform successful
         write opration, report no errors and then, under the hood, do
         some other things that will result in sticky bit being set.

       - Debugger needs to wait for security system to finish
         intialization and assert CDBGPWRUPACK before proceeding

This change is related to commit http://openocd.zylin.com/#/c/1995/

Change-Id: I741c95a809bfd60d930cec9482239e4796a62326
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2088
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
2014-06-28 09:30:09 +00:00
Andrey Smirnov
d6fd5d0f9b adi_v5_cmisis_dap: Separate ABORT from clearing sticky errors
We don't need to do full blown AP ABORT in case of CMSIS-DAP errors,
and the code that was in place was not doing that(issuing AP ABORT)
anyway.

Change-Id: Ide83b1f8875d725da6cb0d53aae8229f8c6316b3
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/2112
Tested-by: jenkins
Reviewed-by: Andrey Yurovsky <yurovsky@gmail.com>
2014-06-28 09:29:36 +00:00
Paul Fertser
6db70bc89b drivers/cmsis_dap_usb: remove jtag reset hacks
This should no longer be needed after tcl scripts are fixed to avoid
calling jtag subcommands when jtag is not used.

Barely tested with an frdm board.

Change-Id: I75f02b088e6134562ae634417d97c48e377df6e9
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2130
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 09:28:36 +00:00
Paul Fertser
f8a6a07149 tcl: introduce using_(jtag|swd|hla) helpers and use them in reset handler
Barely tested with plain SWD transport.

Change-Id: I48b59136bf4294ffed737dba01f1b30ef83aa86b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2003
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-28 09:28:12 +00:00
Andreas Fritiofson
36772a7ed0 swd: Improve parity calculation and move it to types.h
It could be reused by SWD drivers and in other places.

Change-Id: Ieed0cf70c111a73d3a42ed59f46a0cdd177a73d5
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1957
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:27:19 +00:00
Andreas Fritiofson
0e95ec4070 adi_v5_swd: Separate sticky error clearing from AP abort
Swd_queue_ap_abort should set DAPABORT, not only clear sticky errors.
However, DAPABORT should not be set as soon as there is a single
FAULT/WAIT response. It's an "emergency only" operations for use only when
the AP have stalled the transfer for a long time. So these need to be
separate functions.

Change-Id: I37618447884faad54d846c2b07fa668ad505919d
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1956
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:26:54 +00:00
Andreas Fritiofson
677b02b475 adi_v5: Remove unused features of the DAP and SWD interfaces
These features are not currently used so remove or disable them before
something starts to. Not having them around simplifies redesign of the
APIs.

Change-Id: Iad25cc71c48b68a1fa71558141bf14d5ab20d659
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1955
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:26:36 +00:00
Andreas Fritiofson
fd909a5e3d adi_v5_swd: Read RDBUFF once after a sequence of AP reads
Increases performance by a factor of two for long reads.

Change-Id: I81a7a83835058560c6a53a43c3cc991100f01766
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1954
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:26:12 +00:00
Andreas Fritiofson
9ec211de1c adi_v5: Remove strange IDCODE check from dap info handler
Otherwise it breaks SWD targets. The check seems really weird anyway since
it loops through *all* TAPs after the ADIv5 target but doesn't do anything
at all with the result, other than not setting the return values despite
returning ERROR_OK.

Remove a bogus initialization that was needed because of the odd
behaviour of this routine when an IDCODE wasn't found.

Change-Id: Ic086352f6af868b3406b00420291a0a671e3acac
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1953
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-28 09:25:48 +00:00
Fatih Aşıcı
31138437c3 adi_v5_swd: Improve SWD support
Fix bug in parity calculation macro.

Cache and update the selected DP bank when necessary.

Add aborts when the Ack code signals a failure (we should really only
clear the sticky bits, but this will do for now).

Change-Id: I38a4da136ba1d9e989b33c1875a80c0b1b2be874
Signed-off-by: Fatih Aşıcı <fatih.asici@gmail.com>
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1950
Tested-by: jenkins
2014-06-28 09:25:06 +00:00
Paul Fertser
e3be699f51 configure: fix formatting when "echo -n" is not supported
The -n option is non-standard and is unavailable on some systems
(e.g. OS X's shell builtin).

Change-Id: Ia2fed186dee5fa6da543944873d67ebee1d9354e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2172
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-22 09:25:45 +00:00
Paul Fertser
8ae66d0d6f jtag/drivers/jlink: better diagnostics for RCLK problems
The JLink protocol description doesn't really specify it for
JTAG-level commands but the real life evidence is that 0x01 error code
means "Adaptive clocking timeout" as it does for e.g. WRITE_MEM_ARM79.

Change-Id: I4e3b568742814271919f92d202713968c8fcccfb
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2169
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 09:25:15 +00:00
Andrey Yurovsky
eea49ce509 flash: samd: add SAMD10 and SAMD11 part IDs
Add part IDs for the new SAMD10 and SAMD11 parts within the Atmel SAMD
family, they have the same Flash controller as the other samd parts and
should be supported by the at91samd driver.  Compile-tested only.

Change-Id: I493ae96a7d7e8d19e607fd9a4b6544a982be42b3
Signed-off-by: Andrey Yurovsky <yurovsky@gmail.com>
Reviewed-on: http://openocd.zylin.com/2170
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:47:49 +00:00
Paul Fertser
8878673aa9 tcl/target/fm3.cfg: use a CHIPNAME known by the flash driver
fm3 flash driver needs to know which chip variant is used.

This fixes "unknown fm3 variant: mb9bf500.cpu" error if the config is
used as is.

Change-Id: I500fcfb413f23ee246678cec5bd19d14139a28e2
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2160
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:45:51 +00:00
Jiri Kastner
98443c6a4c target: arm_adi_v5: added types and subtypes based on latest coresight documentation
while investigating coresight components, i've found some new partnumbers and devtypes.

Change-Id: Ie68032b0b21d542c2084f80db38b06f5cd4c7591
Signed-off-by: Jiri Kastner <cz172638@gmail.com>
Reviewed-on: http://openocd.zylin.com/2166
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:40:50 +00:00
Franck Jullien
712165f483 openrisc: add support for JTAG Serial Port
Change-Id: I623a8c74bcca2edb5f996b69c02d73a6f67b7d34
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/2162
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:39:08 +00:00
Franck Jullien
fd9f27bfac openrisc: restore current JTAG module while polling the CPU
Change-Id: I93827afaa164d23a93bdddbfa864624b18473f45
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/2163
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:38:04 +00:00
Paul Fertser
667bf9c80f flash/nor/tcl.c: fix formatting in "rejected" error message
The error message (with the usage field unpopulated) looks like this,
obviously missing at least a space before Usage:

Error: 'fm3' driver rejected flash bank at 0x00000000Usage (null)

Change-Id: I2a625676e784d02942823f972a201f7f4f810c68
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2161
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:35:41 +00:00
Joshua Wise
dd4e3a2406 svf: Only read TDO back from the device if we actually need to look at the bits.
This results in a 90% speedup on USB-Blaster, which serializes repeated
TDI input against TDO readback; program time on an 5CGXFC5C6F27 part was
dropped from 2m30s to 9s.

Signed-off-by: Joshua Wise <joshua@joshuawise.com>
Change-Id: I92d5a8b800492283d619328549235b610528c338
Reviewed-on: http://openocd.zylin.com/2145
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:32:13 +00:00
Tom Rini
f9e82f3ffb tcl/target/am335x.cfg: Drop gdb-attach stanza
This isn't needed nor a recommended practice now, was a simple
copy/paste from amdm37x.cfg anyhow.

Change-Id: I064226dc859d7563cfad945b577279fc37448645
Signed-off-by: Tom Rini <trini@ti.com>
Reviewed-on: http://openocd.zylin.com/2068
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-22 08:30:39 +00:00
Nemui Trinomius
889aa89c81 efm32 : Added ZeroGecko family support.
Added Cortex-M0plus "ZeroGecko" Family to flash driver.
Tested on EFM32ZG222F32.

Change-Id: I1660b34ef6ee04837e97581504fff0faf84d1c6d
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/1994
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:29:27 +00:00
Seth LaForge
7b6158db4e cortex_a: fix lockup when writing to high address
On a processor with caches, when you write data to memory OpenOCD invalidates
the cache lines affected. If you write to an address within 64 bytes of
UINT32_MAX, then the for loop control variable wrapped around resulting in an
infinite loop. Change control variable to be an offset from the address
involved. We should never be asked to write 2^32 bytes, so wraparound should
not be a problem.

Change-Id: Ibfe654113eff71684862ff651e7a1cd05ccc6760
Signed-off-by: Seth LaForge <sethml@google.com>
Reviewed-on: http://openocd.zylin.com/2126
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-22 08:23:53 +00:00
Nemui Trinomius
a0e37fe2c0 cfg: Added Nucleo-F334R8 board config.
It supports STLink/V2-1.

Change-Id: I0a8c01247a7a0165321818ca222479e3ae67ce5c
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2175
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-19 21:59:30 +00:00
Nemui Trinomius
76ea15cce7 stm32f1x: add STM32F33x support.
Added STM32F33x series to flash driver.
Tested on NUCLEO-F334R8 board(STM32F334R8T6).

Change-Id: I2fe70d40eb7613a7a3cfa63d25fa83f7bc055fb4
Signed-off-by: Nemui Trinomius <nemuisan_kawausogasuki@live.jp>
Reviewed-on: http://openocd.zylin.com/2174
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-19 21:59:07 +00:00
Paul Fertser
3aee451f27 flash/nor/kinetis: prevent segfaulting with an HLA
HLAs do not provide direct DAP access, so the best we can do about it
is skipping it.

Change-Id: I877ef8fd2d86e40e7442a637cdba182cfd60e05a
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2173
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-18 20:32:06 +00:00
Marco Cruz
bbc2f13f33 tcl/board: add Atmel SAM4E-EK
Change-Id: I07d7e0528ed4e88b070ba4e7598a193ec8e9e37d
Signed-off-by: Marco Cruz <marco.caratuva@gmail.com>
Reviewed-on: http://openocd.zylin.com/2158
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-18 20:27:10 +00:00
Marco Cruz
02f5abddb9 flash/nor/at91sam4: add SAM4E16 support
Change-Id: I7ab4750073c9d34812b690996eef76fccf70c627
Signed-off-by: Marco Cruz <marco.caratuva@gmail.com>
Reviewed-on: http://openocd.zylin.com/2157
Reviewed-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-18 20:25:15 +00:00
Paul Fertser
35c066e23d README.OSX: mention Gentoo Prefix and clarify other options
Change-Id: I431bfb9acf7dd6ad61b9e8f5c20568be22e9f39d
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2146
Tested-by: jenkins
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-18 07:05:39 +00:00
Franck Jullien
ae3baa9d5a target: or1k: remove wrong endian swap from or1k generic code
We don't need to swap the endianness in the target generic code.
This swap is necessary because of the adv_debug_if debug unit.
This patch moves this specific piece of code from or1k.c to
or1k_du_adv.c.

Change-Id: I3acea092fe6edfa79b4a87861b5f01204f071bf0
Signed-off-by: Franck Jullien <franck.jullien@gmail.com>
Reviewed-on: http://openocd.zylin.com/1663
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-05 19:21:46 +00:00
Paul Fertser
c8c10f77dc tcl/target/kl25.cfg: add maximum speed specification
Maximum frequency wasn't tested on hardware but the docs seem to be
quite explicit and do not mention any restrictions for that.

Change-Id: Idcf58df5358d06525e683f07c76eedad8f0b292d
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2120
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-01 18:31:42 +00:00
Paul Fertser
76a765adbc tcl: add ASUS RT-N66U config
CFI flashing verified with real hardware. RAM configuration wasn't
attempted.

Change-Id: I9185ab71430d799793befef708a15f62edba1663
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2153
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-01 18:27:09 +00:00
Paul Fertser
5375a9e1d8 jtag/drivers/osbdm: downgrade init message severity, fix wording
Change-Id: Iacf874b0fe9fbf840e82e6b63f1c97031f4720de
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2156
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-01 18:23:14 +00:00
Cosmin Gorgovan
5fccaa2c8b Flash/LPC2000: Add support for auto-probing flash size
Adds support for auto-probing on devices which support the IAP
Read Part ID command. Includes IDs for all LPC17XX, LPC13XX,
LPC11XX and LPC11XXX devices with publicly available user
manuals.

To use auto-probing, select the 'auto' lpc2000 variant.

Change-Id: Ic617c32925c9ebe0e9d9192ed8ddbfa08e9f0aaa
Signed-off-by: Cosmin Gorgovan <cosmin@linux-geek.org>
Reviewed-on: http://openocd.zylin.com/2075
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-01 18:10:01 +00:00
Cosmin Gorgovan
99d440cbba Flash/LPC2000: Add support for LPC11(x)xx, LPC13xx
LPC11(x)xx and LPC13xx devices are mostly compatible with the lpc1700
variant of the LPC2000 driver, but use a fixed flash sector size of 4KB.

Change-Id: I033515f4ff6bc61d3b9babd27096f78c99cea927
Signed-off-by: Cosmin Gorgovan <cosmin@linux-geek.org>
Reviewed-on: http://openocd.zylin.com/2071
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-06-01 18:07:23 +00:00
Elliott Partridge
7bcf1d838d STM32F2x: Don't clear FLASH_OPTCR bits when locking register
stm32x_write_options is locking the FLASH_OPTCR register by
writing 0x00000001 to it, which clears the other bits. This
causes problems with subsequent flash operations; the hardware
is probably seeing the write protection bits in the register
set to '0' (protect), causing a WRPERR.
This patch ORs the value of the register with 0x00000001, so that
the only change is the lock bit itself.

Change-Id: I0e3ca9aa6563ce1b57a01fc0faf7563b6b85f620
Signed-off-by: Elliott Partridge <elliott.partridge@gmail.com>
Reviewed-on: http://openocd.zylin.com/2155
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-01 17:38:42 +00:00
Alex Ray
248b85a6e7 Disable multiprocessor-id read on ARMv7-R cores
ARMv7-R cores are largely uniprocessor-configured, and when they are
multiprocessor-configured the format of the MPIDR register isn't
compatible with ARMv7-A cores.

Change-Id: I024ec514496fbab5075c6fb34b6acd870e68e1fc
Signed-off-by: Alex Ray <a@machinaut.com>
Reviewed-on: http://openocd.zylin.com/2096
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-01 17:37:56 +00:00
Paul Fertser
9744a2fa20 src/target: select the last created target as current
Configuration commands assume the last created target is the one they
should be applied to. An example of this is sourcing an stm32f1.cfg
several times to access several microcontrollers on the same JTAG chain
where cortex_m reset_config should apply to the target that was just
created, not to the first one.

This fixes http://sourceforge.net/p/openocd/tickets/71/ .

Change-Id: I1ca41cc05fe5f36c4bc62dde4614da1405754fd8
Reported-by: Michael Eischer <mieischer@users.sf.net>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2142
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-01 17:36:41 +00:00
Paul Fertser
fb5e099af8 jtag/drivers/stlink: allow to reconnect seamlessly after polling failure
If the communication with the target was failing (either because of an
intermittent connection or the target was rebooted), this is needed to
reestablish operational state.

Reported-by: Tim Sander <tim@krieglstein.org>
Tested-by: Tim Sander <tim@krieglstein.org>
Change-Id: I91ea2e2b2b5ef8eb27dfe9bae95ef2a919f67e4e
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2152
Tested-by: jenkins
Reviewed-by: Tim Sander <tim@krieglstein.org>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-01 17:28:49 +00:00
Paul Fertser
cd74dd2891 target: reexamine after polling succeeds again
If polling was failing, it likely meant that either the target was
disconnected or rebooted. In the latter case it needs to be reexamined
to be properly configured for the debug session, so do it just in
case.

Reported-by: Tim Sander <tim@krieglstein.org>
Tested-by: Tim Sander <tim@krieglstein.org>
Change-Id: I5b067c18d9276d4e86cc59739f196ae7d0931622
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2151
Tested-by: jenkins
Reviewed-by: Tim Sander <tim@krieglstein.org>
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-06-01 17:28:18 +00:00
Andrey Smirnov
8f9cea457d adi_v5_cmsis_dap: Fix logging order of appearance
Move logging for cmsis_dap_queue_ap_read/write to happen after a call
to cmsis_dap_ap_q_bankselect so that that SWD operation would appear
in the log in the same sequence they happen on the bus.

Change-Id: Ic046bc753e661da7924b019c9100d6932fb686bf
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2087
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2014-06-01 17:01:46 +00:00
Andrey Smirnov
d80123f20b arm_adi_v5: Do not ignore register polling timeout
Previous to this commit 'ahbap_debugport_init' would ignore if timeout
happened or not when waiting for CDBGPWRUPACK and CSYSPWRUPACK and would
continue initialization regardless. It also would not reset the
timeout counter after finishing polling for CDBGPWRUPACK and starting
for CSYSPWRUPACK which could potentially cause some problems.

Also refactor code of both snippets into a more generic function to
avoid duplication.

Change-Id: I16e4f50e6819e08c4126e71ef8cec7db559d608e
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2086
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2014-06-01 17:01:37 +00:00
Andrey Smirnov
d007764fe8 arm_adi_v5: Add convenience "atomic"" function for DP reads
Add convenience "atomic"" function dap_dp_read_atomic_u32()

Change-Id: Ic9ebb58959d2f14bbf03be42a26b0fe58ecfeddb
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2085
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-06-01 17:01:14 +00:00
Paul Fertser
930e41a292 configure.ac: correct test for USB_BLASTER_DRIVER AM symbol
Blaster II should depend on the corresponding symbol, not on libusb-1
presence.

Change-Id: I3d27a1005a78fe81042cb7b515618604612c3ece
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2159
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-05-31 12:07:44 +00:00
Paul Fertser
f97678f3a6 flash/nor/stm32f1x: add support for F04x parts
Ref. RM0091 Rev.6.

Change-Id: I13bcdb1741edc59712e4fa1849fff38d17709fa7
Reported-by: efuentes@irc.freenode.net
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2150
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-05-31 12:05:25 +00:00
Paul Fertser
558279c1bb server: fix confusing wording for incoming tcp connections
Change-Id: I40d5de322f3fc38097e04ce538b0fc2b136e0d6a
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/1937
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-05-31 12:04:31 +00:00
Paul Fertser
ba21fec2aa target/mips32_pracc: fix C99 format specifiers
Warnings exposed by arm-none-eabi build.

Change-Id: Icdaf168d7aaa1a62bdfd41a64e43ef94816d3721
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2140
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-05-31 12:02:28 +00:00
Ivan De Cesaris
74889cf468 quark_x10xx: cleanup of LOG format specifiers
Fix for LOG format specifiers, this is a superset of those
exposed by the arm-none-eabi build.

Add 0x prefix for all values printed in hex.

Add LOG messages for error cases when enabling or disabling
paging.

Change-Id: I070c556e0ad31204231a2b572e7b93af22a9bc61
Signed-off-by: Ivan De Cesaris <ivan.de.cesaris@intel.com>
Reviewed-on: http://openocd.zylin.com/2149
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
2014-05-31 12:01:31 +00:00
Aurelien Jacobs
970a12aef4 lpcspifi: setup a valid stack pointer before calling ROM code using stack
The spifi_init_code blob is calling the spifi_init() function from the ROM.
This ROM function is making use of the stack. So if the stack pointer is
invalid, trying to execute this code leads to a double fault and the
target_run_algorithm() call return with an error.
This patch simply ensure that the stack pointer is properly setup before
calling the spifi_init() ROM function.

Change-Id: I42a2163cfc2c6dfe5ada97ae8eb2bb6d2e283ff7
Signed-off-by: Aurelien Jacobs <aurel@gnuage.org>
Reviewed-on: http://openocd.zylin.com/1836
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-05-16 07:15:31 +00:00
Yegor Yefremov
1a06fc6047 KS869x: add new target
This patch adds Micrel's KS869x target. The configuration was taken from
http://www.mmnt.net/db/0/0/www.micrel.com/ethernet/8695 - Micrel's
FTP server i.e. their OpenOCD 7.0 package.

The only change compared to the original file is the removal of
reset configuration, as it belongs to the board configuration.

Change-Id: Ic8509aa5fe5ce3166a3129e1c055280a3b2b9312
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
Reviewed-on: http://openocd.zylin.com/2125
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-16 07:10:04 +00:00
Andrey Smirnov
46101959a6 kinetis: Revise CPU un-securing code
Old version of the code had several problems, among them are:
 * Located in a generic ADI source file instead of some Kinetis
   specific location
 * Incorrect MCU detection code that would read generic ARM ID
   registers
 * Presence of SRST line was mandatory
 * There didn't seem to be any place where after SRST line assertion
   it would be de-asserted.
 * Reset was asserted after waiting for "Flash Controller Ready" bit
   to be set, which contradicts official programming guide AN4835
 * Mass erase algorithm implemented by that code was very strange:
   ** After mass erase was initiated instead of just polling for the
      state of "Mass Erase Acknowledged" bit the code would repeatedly
      initiate mass erase AND poll the state of the "Mass Erase
      Acknowledged"
   ** Instead of just polling for the state of "Flash Mass Erase in
      Progress"(bit 0 in Control register) to wait for the end of the
      mass erase operation the code would: write 0 to Control
      register, read out Status register ignoring the result and then
      read Control register again and see if it is zero.
 * dap_syssec_kinetis_mdmap assumed that previously selected(before
   it was called) AP was 0.

This commit moves all of the code to kinetis flash driver and
introduces three new commands:

o "kinetis mdm check_security" -- the intent of that function is to be used as
  'examine-end' hook for any Kinetis target that has that kind of
  JTAG/SWD security mechanism.

o "kinetis mdm mass_erase""  -- This function removes secure status from
  MCU be performing special version of flash mass erase.

o "kinetis mdm test_securing" -- Function that allows to test securing
  fucntionality. All it does is erase the page with flash security settings thus
  making MCU 'secured'.

New version of the code implements the algorithms specified in AN4835
"Production Flash Programming Best Practices for Kinetis K-
and L-series MCUs", specifically sections 4.1.1 and 4.2.1.
It also adds KL26 MCU to the list of devices for which this security
check is performed. Implementing that algorithm also allowed to simplify
mass command in kinetis driver, since we no longer need to write security
bytes. The result that the old version of mass erase code can now be
acheived using 'kinetis mdm mass_erase'

Tested on accidentally locked FRDM-KL26Z with KL26 Kinetis MCU.

Change-Id: Ic085195edfd963dda9d3d4d8acd1e40cc366b16b
Signed-off-by: Andrey Smrinov <andrew.smirnov@gmail.com>
Reviewed-on: http://openocd.zylin.com/2034
Tested-by: jenkins
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-05-10 09:15:35 +00:00
Salvador Arroyo
6cadbadb37 mips32: new code for pracc exec
This is only the basic code proposed for mips32_pracc_exec() function.
It checks every pracc address against the expected address when
reading (instruction fetch).
The code expects to start at PRACC_TEXT and any subsequent read address
is obtained by adding 4 to the previous one.
After shifting out all the instructions the code executes a final check.
It checks now for the first pass trough PRACC_TEXT and shift out
only NOP instructions.
A mips core does not need an additional NOP and after the first check
it exits if there is no store access pending.
After shifting out one NOP the core must be reading at pracc text or the
code exits with error.
The code continues shifting out NOPs until all store accesses have
been performed.
After shifting out 10 NOPs it exits with error.
No assumption is made about the number of store instruction shifted out or
the ordering of the store accesses. It only checks that the number of
store accesses is the same as the number of store instructions at dmseg
after execution.
mips32_pracc_read_ctrl_addr() and mips32_pracc_finish() are added to
simpify a bit the code. Fields pa_ctrl and pa_addr are added
in ejtag_info for storing values of pracc control and address.

Change-Id: If6322d5c8cbeadcd4acd3972c0f72c8490f53c34
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1827
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:40:31 +00:00
Salvador Arroyo
fcd7b90db6 mips32: cleanups in legacy pracc code
This is the first patch intended to make a more precise pracc check
when running in legacy mode (code executed by mips32_pracc_exec()).
It only makes some cleanups, mostly due to unnecessary code.
With the last cache optimizations for processor access (pa for short)
all the pracc functions generate the code following some rules that
make pa more easily to check:
	There are no load instructions from dmseg. All the read pas are
	instruction fetches. PARAM_IN related stuff is not needed.
	Registers are restored either from COP0 DeSave or from ejtag
	info fields. PRACC_STACK related stuff is not needed any more.
	The code starts execution at PRACC_TEXT and there are no branch or jump
	instruction in the code, apart from the last jump to PRACC_TEXT.
	The fetch address is ever known.
	For every store instruction to dmseg the function code sets
	the address of the write/store pa.
	The address of every store pa is known.
Current code ends execution when reading a second pass through PRACC_TEXT.
This approach has same inconveniences:
	If the code starts in the delay slot of a jump it makes a jump
	to PRACC_TEXT after executing the first instruction. A second pass
	through PRACC_TEXt is read and the function exits without any warning.
	This seems to occur sometimes when a 24kc core is halted in the delay
	slot of a branch.
	If a debug mode exception is triggered during the execution of a
	function the core restarts execution at PRACC_TEXT. Again the function
	exits without any warning.
	If for whatever reason the core starts fetching  at an unexpected
	address the code now sends a jump instruction to PRACC_TEXT, but due
	to the delay slot the core continues fetching at whatever address + 4
	and a second jump instruction will be send for execution. The result
	of a jump instruction in the delay slot of another jump is
	UNPREDICTABLE. It may work as expected (ar7241), or let the core in
	the delay slot of a jump to PRACC_TEXT for example. This means the
	function called next may also fail (pic32mx).

Change-Id: I9516a5146ee9c8c694d741331edc7daec9bde4e3
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1825
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:39:14 +00:00
Salvador Arroyo
d7127bfa97 mips: use cp0 DeSave to cache $15 / t7
Near all pracc functions store $15 in DeSave and
restore it when exiting.
There is no need to save it, if mips32_pracc_read_regs()
save this register in Desave when entering debug mode.
mips32_pracc_write_regs() needs to update it when
exiting debug mode.
Other pracc functions must not modify DeSave.
The jump code in the fastdata transfer function needs also
some little modifications.
Remark:
Like in current code the user can read/modify $15
with the cp0 31 commands.

Change-Id: I5b7dfc1b6169da846f5d2dd3ad4209a9da2c3fad
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1565
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:38:46 +00:00
Salvador Arroyo
b08306a172 mips: load fast data transfer handler code with mips32_pracc_write_mem()
Currently the code is loaded calling mips32_pracc_write_mem_generic().
Cache synchronization is not performed.
If configured as write back cache there is no chance to execute the
handler. If configured as write through cache and the cache
lines written to are not cache resident (I-side cache miss) may work.
The patch makes possible to execute the handler in a cached active
memory segment (mainly from KSEG0), but nothing else. The data
is still loaded without performing cache synchronization, code loaded
may not be executable.
Performance may not be faster. At start, for example, the code resides in
main memory, not in cache, and the core must transfer code from
memory. We can really modify the code to force a wait for the first
transfer like we do with start and end addresses, making sure the code
is cache resident for the rest of the queued transfers.
This can also may happen if we execute code (greater than the I cache size)
and the handler code is evicted from the cache.
Code tested on ar7241.

Change-Id: Iffdb4dae108b872fef0e7bacc5ea99649cdc1630
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1564
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:38:21 +00:00
Salvador Arroyo
e9497fbf75 mips: load code in buffer mode
Currently the functions mips32_checksum_memory() and mips32_blank_check_memory()
load the code word by word.
The bug in cache code is a good reason for doing so.
If there is no other reason we can load the code as a buffer to save time.
mips_m4k_write_memory() expect a buffer in target endianness, this is done by
target_buffer_set_u32_array().
Cleaned up exit code.
Tested on ar7241 big endian and pic32mx little endian with verify_image.
Flash erase check only tested in pic32mx.

Change-Id: Ib63ed98732b2e23b058e7349a0a57934b7604905
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1562
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
2014-05-09 20:37:42 +00:00
Salvador Arroyo
12f4564e88 mips32: optimized cache code for pracc access
Follows the the same rules of optimization used by all pracc functions.
Solves some bugs in previous code and adds support for write through caches.

Change-Id: If88c6738ca8c8197f327f22b766120a24f71b567
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/1557
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:35:41 +00:00
Paul Fertser
92ea548aaf Update to the current Jim Tcl
This is a post-release version but hopefully some fixes that went in
are worth it; also the changes here make OpenOCD compatible with stock
0.75 version if a distro maintainer decides to use it.

Change-Id: I7ad1814c7c4868198475cdca4750c3d0ee4f5f8b
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2121
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:12:17 +00:00
Paul Fertser
dd2e16a9e8 README.OSX: recommend XCode 5 as that's the current version
Using current "Command Line Tools" with XCode 4 is known to provoke
issues (the build "hangs"), see e.g.

http://stackoverflow.com/questions/18667916/xcrun-lipo-freezes-with-os-x-mavericks-and-xcode-4-x

This fixes https://sourceforge.net/p/openocd/tickets/70/ .

Change-Id: I511b347b9388e0e3f1d136b566915021c4b5fbde
Reported-by: n321203 <n321203@users.sf.net>
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2128
Reviewed-by: Xiaofan <xiaofanc@gmail.com>
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 20:01:40 +00:00
Andreas Fritiofson
4a4f716163 ftdi: Optimize GPIO toggling
Only send the new I/O state for the bytes that changed.

Change-Id: I930edc9518e6019331e68e4756acc5e92dda25a4
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Reviewed-on: http://openocd.zylin.com/1999
Tested-by: jenkins
Reviewed-by: Jens Bauer <jens@gpio.dk>
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
2014-05-09 19:27:50 +00:00
Kamal Dasu
2eb8a31a6b svf: Fix debug and error messages that print hex buffer
Added SVF_BUF_LOG macro to properly print the hex buffer of parsed
string for SIR, SDR, TDI, TDO and MASK. The original debug and error
logs with respect to printing real values were misleading and also
had endianess issues. All the bits are printed now instead of just
u32 values.

Change-Id: Ie89902403bdb61ff458418446c2ca1253ea2a63f
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Reviewed-on: http://openocd.zylin.com/1964
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Tested-by: jenkins
2014-05-05 20:25:10 +00:00
Paul Fertser
b1beaa36e2 doc: document [start end] parameters of "profile" command
Change-Id: I56561b08304e5b854a67b06ab6b9cee7a24919b2
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2115
Tested-by: jenkins
2014-05-05 20:24:46 +00:00
Andrey Smirnov
d92a2ac330 generalplus: Add configuration file for General Plus GP326XXXA series
Add configuration file for General Plus GP326XXXA series. Tested on
GP326833A on GPC-1737B board.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
Change-Id: I1ad0e22598b01317bbc823870a7a262e9192c595
Reviewed-on: http://openocd.zylin.com/2058
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-05-05 20:23:45 +00:00
Spencer Oliver
d9d416f49d armv7a: fix typo in cache_config help text
Change-Id: I48cb83bf56b2f6841c3add68ed94b9f92037357d
Signed-off-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-on: http://openocd.zylin.com/2114
Tested-by: jenkins
2014-05-05 20:19:25 +00:00
Paul Fertser
b1a1a48b30 Fix some C99 format specifiers
As exposed by arm-none-eabi build, fix the wrong modifiers.

Change-Id: Ia6ce7c5c1d40e95059525c3e5d81b752df2fea7c
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2122
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-05-05 20:18:38 +00:00
Ash Charles
66c6665288 Add support for Gumstix AeroCore device
The Gumstix AeroCore board [1] contains a STM32F427 microcontroller.
Schematics for this board will also be made available [2].
The JTAG interface for this chip can be accessed via a USB connection
provided by an FTDI chip (0403:6011).

[1] https://store.gumstix.com/index.php/products/585/
[2] https://pubs.gumstix.com/boards/AEROCORE

Change-Id: I0bf3bb525f51528bedd807b1f7210b09ef2e1015
Signed-off-by: Ash Charles <ashcharles@gmail.com>
Reviewed-on: http://openocd.zylin.com/2117
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
2014-05-05 20:14:30 +00:00
Paul Fertser
8fa67bd57d Restore normal development cycle
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
2014-04-27 15:07:08 +04:00
421 changed files with 19682 additions and 7327 deletions

4
.gitignore vendored
View File

@@ -30,8 +30,8 @@ src/jtag/drivers/OpenULINK/*.rst
*.swp
src/startup.tcl
startup_tcl.c
xscale_debug.h
startup_tcl.inc
xscale_debug.inc
bin2char
bin2char.exe

4
BUGS
View File

@@ -6,11 +6,11 @@ posting a message with your report:
openocd-devel@lists.sourceforge.net
Also, please check the Trac bug database to see if a ticket for
Also, please check the bug database to see if a ticket for
the bug has already been opened. You might be asked to open
such a ticket, or to update an existing ticket with more data.
https://sourceforge.net/apps/trac/openocd/
http://bugs.openocd.org/
To minimize work for OpenOCD developers, you should try to include
all of the information listed below. If you feel that some of the

View File

@@ -172,6 +172,13 @@ not have to) be disregarded if all conditions listed below are met:
@section browsing Browsing Patches
All OpenOCD patches can be reviewed <a href="http://openocd.zylin.com/">here</a>.
@section reviewing Reviewing Patches
From the main <a href="http://openocd.zylin.com/#/q/status:open,n,z">Review
page</a> select the patch you want to review and click on that patch. On the
appearing page select the download method (top right). Apply the
patch. After building and testing you can leave a note with the "Reply"
button and mark the patch with -1, 0 and +1.
*/
/** @file
This file contains the @ref patchguide page.

156
NEWS
View File

@@ -2,105 +2,103 @@ This file includes highlights of the changes made in the OpenOCD
source archive release.
JTAG Layer:
* New CMSIS-DAP driver
* Andes AICE debug adapter support
* New OpenJTAG driver
* New BCM2835 (RaspberryPi) driver
* JTAG VPI client driver (for OpenRISC Reference Platform SoC)
* Xilinx BSCAN_* for OpenRISC support
* ST-LINKv2-1 support
* ST-LINKv2 SWO tracing support (UART emulation)
* JLink-OB (onboard) support
* Altera USB Blaster driver rewrite, initial Blaster II
support
* ULINK driver ported to libusb-1.0, OpenULINK build fixes
* Support up to 64 bit IR lengths
* SVF playback (FPGA programming) fixes
* "ftdi" interface driver got extensive testing and is now
recommended over the old ft2232 implementation
* SWD support with FTDI, Versaloon, J-Link, sysfsgpio
* CMSIS-DAP massive speed and stability improvements
* Versaloon driver ported to libusb-1.0
* STLink can reestablish communication with a target that was
disconnected or rebooted
* STLink FAULT and WAIT SWD handling improved
* New hla_serial command to distinguish between several HLA
adapters attached to a single machine
* Serial number support for CMSIS-DAP and J-Link adapters
* Support for more J-Link adapters
* TAP autoprobing improvements
* Big speedup for SVF playback with USB Blaster
Boundary Scan:
Target Layer:
* New target: Andes nds32
* New target: OpenRISC OR1K
* New target: Intel Quark X10xx
* MIPS EJTAG 1.5/2.0 support
* MIPS speed improvements
* Cortex-M, Cortex-A (MEM-AP, APB-AP) targets working with BE
hosts now
* XScale vector_catch support, reset fixes
* dsp563xx ad-hoc breakpoint/watchpoint support
* RTOS support for embKernel
* Target profiling improvements
* Memory access functions testbench
* Stability improvements for targets that get disconnected or
rebooted during a debug session
* MIPS speed and reliability improvements
* MIPS 1.5/2.0 fixes
* ARMv7-R improvements
* Cortex-A improvements, A7, A15 MPCores support
* FPU support for ARMv7-M (Cortex-M4F)
* TPIU/ITM support (including SWO/SWV tracing), can be
captured with external tools or STLink
* JTAG Serial Port (Advanced Debug System softcore) support
* Profiling support for OpenRISC
* ChibiOS/RT 3.0 support (with and without FPU)
* FreeRTOS current versions support
* Freescale MQX RTOS support
* GDB target description support for MIPS
* The last created target is auto-selected as the current
Flash Layer:
* STM32 family sync with reference manuals, other bugfixes
* STM32F401, STM32F07x support
* Atmel SAM4L, SAMG5x support
* at91sam3sd8{a,b}, at91sam3s8{a,b,c}, at91sam4s,
at91sam3n0{a,b,0a,0b} support, bugfixes
* Atmel SAMD support
* Milandr 1986ВЕ* support
* Kinetis KL, K21 support
* Nuvoton NuMicro MINI5{1,2,4} support
* Nuvoton NUC910 series support
* NXP LPC43xx, LPC2000 fixes
* NXP LPC800, LPC810 support
* More ATmega parts supported
* Fujitsu MB9Ax family support
* EFM32 Wonder Gecko family support
* Nordic nRF51 support
* nRF51 async loader to improve flashing performance and stability
* Cypress PSoC 41xx/42xx and CCG1 families flash driver
* Silabs SiM3 family flash driver
* Marvell Wireless Microcontroller SPI flash driver
* Kinetis mass erase (part unsecuring) implemented
* lpcspifi stability fixes
* STM32 family sync with reference manuals, L0 support, bugfixes
* LPC2000 driver automatically determines part and flash size
* NXP LPC11(x)xx, LPC13xx, LPC15xx, LPC8xx, LPC5410x, LPC407x support
* Atmel SAMD, SAMR, SAML21 devices support
* Atmel SAM4E16 support
* ZeroGecko family support
* TI Tiva C Blizzard and Snowflake families support
* Nuvoton NuMicro M051 support
Board, Target, and Interface Configuration Scripts:
* STM32W108xx generic target config
* STM32F429 discovery board config
* STM32 Nucleo boards configs
* DENX M53EVK board config
* Altera Cyclone V SoC, SoCkit config
* New TI Launchpads board configs
* TI am43xx devices, AM437x GP EVM, AM438x ePOS EVM board
configs
* Marvell Armada 370 family initial support
* TI TMDX570LS31USB (TMS570, Cortex-R4) support scripts
* Freescale FRDM-KL25Z, KL46Z board configs
* Digilent Zedboard config
* Asus RT-N16, Linksys WRT54GL, BT HomeHub board configs
* Atmel Xplained initial support
* Broadcom bcm28155_ap board config
* TUMPA, TUMPA Lite interface configs
* Digilent JTAG-SMT2 interface config
* New RAM testing functions
* Easy-to-use firmware recovery helpers targetting ordinary
users with common equipment
* Normal target configs can work with HLA (STLink, ICDI) adapters
* STM32 discovery and Nucleo boards configs
* Gumstix AeroCore board config
* General Plus GP326XXXA target config
* Micrel KS869x target config
* ASUS RT-N66U board config
* Atmel SAM4E-EK board config
* Atmel AT91SAM4L proper reset handling implemented
* TI OMAP/AM 3505, 3517 target configs
* nRF51822-mKIT board config
* RC Module К1879ХБ1Я target config
* TI TMDX570LS20SUSB board config
* TI TMS570 USB Kit board config
* TI CC2538, CC26xx target configs
* TI AM437x major config improvements, DDR support
* TI AM437X IDK board config
* TI SimpleLink Wi-Fi CC3200 LaunchPad configs
* Silicon Labs EM357, EM358 target configs
* Infineon XMC1000, XMC4000 family targets and boards configs
* Atheros AR9331 target config
* TP-LINK TL-MR3020 board config
* Alphascale asm9260t target and eval kit configs
* Olimex SAM7-LA2 (AT91SAM7A2) board config
* EFM32 Gecko boards configs
* Spansion FM4 target and SK-FM4-176L-S6E2CC board configs
* LPC1xxx target configs were restructured
* IoT-LAB debug adapter config
* DP BusBlaster KT-Link compatible config
Server Layer:
* Auto-generation of GDB target description for ARMv7-M,
ARM4, nds32, OR1K, Quark
* GDB File-I/O Remote Protocol extension support
* Default GDB flashing events handlers to initialise and reset
the target automatically when "load" is used
* Polling period can be configured
* "shutdown" command has an immediate effect
* The "program" command doesn't lead to a shutdown by
default, use optional "exit" parameter for the old behaviour
* Proper OS signal handling was implemented
* Async target notifications for the Tcl RPC
Documentation:
* Extensive README* changes
* The official User's Guide was proofread
* Example cross-build script
* RTOS documentation improvements
* Tcl RPC documentation and examples added
Build and Release:
* *BSD, OS X, clang, ARM, windows build fixes
* New pkg-config support changes the way libusb (and other
dependencies) are handled. Many adapter drivers are now
selected automatically during the configure stage.
This release also contains a number of other important functional and
cosmetic bugfixes. For more details about what has changed since the
last release, see the git repository history:
http://sourceforge.net/p/openocd/code/ci/v0.8.0/log/?path=
http://sourceforge.net/p/openocd/code/ci/v0.9.0/log/?path=
For older NEWS, see the NEWS files associated with each release

111
NEWS-0.8.0 Normal file
View File

@@ -0,0 +1,111 @@
This file includes highlights of the changes made in the OpenOCD
source archive release.
JTAG Layer:
* New CMSIS-DAP driver
* Andes AICE debug adapter support
* New OpenJTAG driver
* New BCM2835 (RaspberryPi) driver
* JTAG VPI client driver (for OpenRISC Reference Platform SoC)
* Xilinx BSCAN_* for OpenRISC support
* ST-LINKv2-1 support
* ST-LINKv2 SWO tracing support (UART emulation)
* JLink-OB (onboard) support
* Altera USB Blaster driver rewrite, initial Blaster II
support
* ULINK driver ported to libusb-1.0, OpenULINK build fixes
* Support up to 64 bit IR lengths
* SVF playback (FPGA programming) fixes
* "ftdi" interface driver got extensive testing and is now
recommended over the old ft2232 implementation
Boundary Scan:
Target Layer:
* New target: Andes nds32
* New target: OpenRISC OR1K
* New target: Intel Quark X10xx
* MIPS EJTAG 1.5/2.0 support
* MIPS speed improvements
* Cortex-M, Cortex-A (MEM-AP, APB-AP) targets working with BE
hosts now
* XScale vector_catch support, reset fixes
* dsp563xx ad-hoc breakpoint/watchpoint support
* RTOS support for embKernel
* Target profiling improvements
* Memory access functions testbench
Flash Layer:
* STM32 family sync with reference manuals, other bugfixes
* STM32F401, STM32F07x support
* Atmel SAM4L, SAMG5x support
* at91sam3sd8{a,b}, at91sam3s8{a,b,c}, at91sam4s,
at91sam3n0{a,b,0a,0b} support, bugfixes
* Atmel SAMD support
* Milandr 1986ВЕ* support
* Kinetis KL, K21 support
* Nuvoton NuMicro MINI5{1,2,4} support
* Nuvoton NUC910 series support
* NXP LPC43xx, LPC2000 fixes
* NXP LPC800, LPC810 support
* More ATmega parts supported
* Fujitsu MB9Ax family support
* EFM32 Wonder Gecko family support
* Nordic nRF51 support
Board, Target, and Interface Configuration Scripts:
* STM32W108xx generic target config
* STM32F429 discovery board config
* STM32 Nucleo boards configs
* DENX M53EVK board config
* Altera Cyclone V SoC, SoCkit config
* New TI Launchpads board configs
* TI am43xx devices, AM437x GP EVM, AM438x ePOS EVM board
configs
* Marvell Armada 370 family initial support
* TI TMDX570LS31USB (TMS570, Cortex-R4) support scripts
* Freescale FRDM-KL25Z, KL46Z board configs
* Digilent Zedboard config
* Asus RT-N16, Linksys WRT54GL, BT HomeHub board configs
* Atmel Xplained initial support
* Broadcom bcm28155_ap board config
* TUMPA, TUMPA Lite interface configs
* Digilent JTAG-SMT2 interface config
* New RAM testing functions
* Easy-to-use firmware recovery helpers targetting ordinary
users with common equipment
Server Layer:
* Auto-generation of GDB target description for ARMv7-M,
ARM4, nds32, OR1K, Quark
* GDB File-I/O Remote Protocol extension support
* Default GDB flashing events handlers to initialise and reset
the target automatically when "load" is used
Documentation:
* Extensive README* changes
* The official User's Guide was proofread
* Example cross-build script
* RTOS documentation improvements
* Tcl RPC documentation and examples added
Build and Release:
* *BSD, OS X, clang, ARM, windows build fixes
* New pkg-config support changes the way libusb (and other
dependencies) are handled. Many adapter drivers are now
selected automatically during the configure stage.
This release also contains a number of other important functional and
cosmetic bugfixes. For more details about what has changed since the
last release, see the git repository history:
http://sourceforge.net/p/openocd/code/ci/v0.8.0/log/?path=
For older NEWS, see the NEWS files associated with each release
(i.e. NEWS-<version>).
For more information about contributing test reports, bug fixes, or new
features and device support, please read the new Developer Manual (or
the BUGS and PATCHES.txt files in the source archive).

17
README
View File

@@ -39,7 +39,11 @@ If you are connecting a particular adapter with some specific target,
you need to source both the jtag interface and the target configs,
e.g.:
openocd -f interface/ftdi/jtagkey2.cfg -f target/ti_calypso.cfg
openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \
-f target/ti_calypso.cfg
openocd -f interface/stlink-v2-1.cfg -c "transport select hla_swd" \
-f target/stm32l0.cfg
NB: when using an FTDI-based adapter you should prefer configs in the
ftdi directory; the old configs for the ft2232 are deprecated.
@@ -57,10 +61,10 @@ In addition to the in-tree documentation, the latest manuals may be
viewed online at the following URLs:
OpenOCD User's Guide:
http://openocd.sourceforge.net/doc/html/index.html
http://openocd.org/doc/html/index.html
OpenOCD Developer's Manual:
http://openocd.sourceforge.net/doc/doxygen/html/index.html
http://openocd.org/doc/doxygen/html/index.html
These reflect the latest development versions, so the following section
introduces how to build the complete documentation from the package.
@@ -123,9 +127,10 @@ Flash drivers
-------------
ADUC702x, AT91SAM, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, Kinetis,
LPC2000, LPC2900, LPCSPIFI, Milandr, NuMicro, PIC32mx, Stellaris,
STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180,
LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400.
LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI,
Milandr, NuMicro, PIC32mx, PSoC4, SiM3x, Stellaris, STM32, STMSMI,
STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400.
==================

View File

@@ -3,23 +3,38 @@ Building OpenOCD for OSX
There are a few prerequisites you will need first:
- Xcode 4 (install from the AppStore)
- Command Line Tools (install from Xcode 4 -> Preferences -> Downloads)
- MacPorts (http://www.macports.org/install.php)
- Xcode 5 (install from the AppStore)
- Command Line Tools (install from Xcode 5 -> Preferences -> Downloads)
- Gentoo Prefix (http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap.xml)
or
- Homebrew (http://mxcl.github.io/homebrew/)
or
- MacPorts (http://www.macports.org/install.php)
libtool, automake, autoconf, pkg-config and libusb can be easily
installed via MacPorts:
sudo port install libtool automake autoconf pkgconfig libusb [libusb-compat]
or with Homebrew:
brew install libtool automake libusb [libusb-compat] [hidapi]
With Gentoo Prefix you can build the release version or the latest
devel version (-9999) the usual way described in the Gentoo
documentation. Alternatively, install the prerequisites and build
manually from the sources.
With Homebrew you can either run:
brew install [--HEAD] openocd (where optional --HEAD asks brew to
install the current git version)
or
brew install libtool automake libusb [libusb-compat] [hidapi] [libftdi]
(to install the needed dependencies and then proceed with the
manual building procedure)
For building with MacPorts you need to run:
sudo port install libtool automake autoconf pkgconfig \
libusb [libusb-compat] [libftdi1]
You should also specify LDFLAGS and CPPFLAGS to allow configure to use
MacPorts' libraries, so run configure like this:
LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options]
If you're using Homebrew, no custom flags are necessary.
See README for the generic building instructions.

View File

@@ -7,6 +7,9 @@ recommended as it doesn't provide enough C99 compatibility).
Alternatively, one can cross-compile it using MinGW-w64 on a *nix
host. See README for the generic instructions.
Also, the MSYS2 project provides both ready-made binaries and an easy
way to self-compile from their software repository out of the box.
Native MinGW-w64/MSYS compilation
-----------------------------
@@ -22,13 +25,21 @@ installation.
USB adapters
------------
You usually need to have WinUSB.sys (or libusbK.sys) driver installed
for a USB-based adapter. Some vendor software (e.g. for ST-LINKv2)
does it on its own. For the other cases the easiest way to assign
WinUSB to a device is to use the latest Zadig installer:
For the adapters that use a HID-based protocol, e.g. CMSIS-DAP, you do
not need to perform any additional configuration.
For all the others you usually need to have WinUSB.sys (or
libusbK.sys) driver installed. Some vendor software (e.g. for
ST-LINKv2) does it on its own. For the other cases the easiest way to
assign WinUSB to a device is to use the latest Zadig installer:
http://zadig.akeo.ie
When using a composite USB device, it's often necessary to assign
WinUSB.sys to the composite parent instead of the specific
interface. To do that one needs to activate an advanced option in the
Zadig installer.
For the old drivers that use libusb-0.1 API you might need to link
against libusb-win32 headers and install the corresponding driver with
Zadig.

View File

@@ -1,10 +1,18 @@
AC_PREREQ(2.64)
AC_INIT([openocd], [0.8.0],
AC_INIT([openocd], [0.9.0],
[OpenOCD Mailing List <openocd-devel@lists.sourceforge.net>])
AC_CONFIG_SRCDIR([src/openocd.c])
m4_include([config_subdir.m4])dnl
# check for makeinfo before calling AM_INIT_AUTOMAKE
AC_CHECK_PROG([MAKEINFO], [makeinfo], [makeinfo])
if test "x$MAKEINFO" = "x"; then
MAKEINFO='echo makeinfo missing; true'
AC_MSG_WARN([Info documentation will not be built.])
fi
AC_SUBST([MAKEINFO])
AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip subdir-objects])
AC_CONFIG_HEADERS([config.h])
@@ -196,7 +204,8 @@ m4_define([USB1_ADAPTERS],
[[stlink], [ST-Link JTAG Programmer], [HLADAPTER_STLINK]],
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
[[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]]])
[[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]],
[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]]])
m4_define([USB_ADAPTERS],
[[[jlink], [Segger J-Link JTAG Programmer], [JLINK]],
@@ -205,8 +214,7 @@ m4_define([USB_ADAPTERS],
[[aice], [Andes JTAG Programmer], [AICE]]])
m4_define([USB0_ADAPTERS],
[[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]],
[[usbprog], [USBProg JTAG Programmer], [USBPROG]],
[[[usbprog], [USBProg JTAG Programmer], [USBPROG]],
[[rlink], [Raisonance RLink JTAG Programmer], [RLINK]],
[[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]]])
@@ -615,6 +623,10 @@ case $host in
;;
esac
if test $is_win32 = yes; then
AC_DEFINE([WIN32_LEAN_AND_MEAN], [1], [1 to exclude old conflicting definitions when building on Windows])
fi
if test $build_parport = yes; then
build_bitbang=yes
AC_DEFINE([BUILD_PARPORT], [1], [1 if you want parport.])
@@ -1174,7 +1186,7 @@ AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft223
AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes])
AM_CONDITIONAL([USB_BLASTER_FTD2XX], [test $build_usb_blaster_ftd2xx = yes])
AM_CONDITIONAL([JTAG_VPI], [test $build_jtag_vpi = yes -o $build_jtag_vpi = yes])
AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes -o $use_libusb1 = yes])
AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes -o $enable_usb_blaster_2 != no])
AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes])
AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes])
AM_CONDITIONAL([PRESTO_LIBFTDI], [test $build_presto_libftdi = yes])
@@ -1248,47 +1260,6 @@ if test $gcc_warnings = yes; then
CFLAGS="$CFLAGS $GCC_WARNINGS"
fi
# Setup for compiling build tools
AC_MSG_CHECKING([for a C compiler for build tools])
if test $cross_compiling = yes; then
AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc)
CFLAGS_FOR_BUILD="-g -O2 $GCC_WARNINGS"
else
CC_FOR_BUILD=$CC
CFLAGS_FOR_BUILD=$CFLAGS
fi
AC_MSG_RESULT([$CC_FOR_BUILD])
AC_SUBST([CC_FOR_BUILD])
AC_SUBST([CFLAGS_FOR_BUILD])
AC_MSG_CHECKING([for suffix of executable build tools])
if test $cross_compiling = yes; then
cat >conftest.c <<\_______EOF
int main ()
{
exit (0);
}
_______EOF
for i in .exe ""; do
compile="$CC_FOR_BUILD conftest.c -o conftest$i"
if AC_TRY_EVAL(compile); then
if (./conftest) 2>&AC_FD_CC; then
EXEEXT_FOR_BUILD=$i
break
fi
fi
done
rm -f conftest*
if test "${EXEEXT_FOR_BUILD+set}" != set; then
AC_MSG_ERROR([Cannot determine suffix of executable build tools])
fi
else
EXEEXT_FOR_BUILD=$EXEEXT
fi
AC_MSG_RESULT([$EXEEXT_FOR_BUILD])
AC_SUBST([EXEEXT_FOR_BUILD])
AC_CONFIG_FILES([
Makefile
src/Makefile
@@ -1318,16 +1289,16 @@ echo
echo OpenOCD configuration summary
echo --------------------------------------------------
m4_foreach([adapter], [USB1_ADAPTERS, USB_ADAPTERS, USB0_ADAPTERS, HIDAPI_ADAPTERS],
[echo -n m4_format(["%-40s"], ADAPTER_DESC([adapter]))
[s=m4_format(["%-40s"], ADAPTER_DESC([adapter]))
case $ADAPTER_VAR([adapter]) in
auto)
echo yes '(auto)'
echo "$s"yes '(auto)'
;;
yes)
echo yes
echo "$s"yes
;;
no)
echo no
echo "$s"no
;;
esac
])

View File

@@ -50,6 +50,9 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
# Amontec JTAGkey and JTAGkey-tiny
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
# TI ICDI
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="664", GROUP="plugdev"
# STLink v1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="664", GROUP="plugdev"

View File

@@ -44,6 +44,7 @@
#include <string.h>
#include <unistd.h>
unsigned int dump_swit;
/* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
* on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
@@ -59,6 +60,9 @@ static void show_task(int port, unsigned data)
unsigned code = data >> 16;
char buf[16];
if (dump_swit)
return;
switch (code) {
case 0:
strcpy(buf, "run");
@@ -87,6 +91,9 @@ static void show_reserved(FILE *f, char *label, int c)
{
unsigned i;
if (dump_swit)
return;
printf("%s - %#02x", label, c);
for (i = 0; (c & 0x80) && i < 4; i++) {
@@ -105,7 +112,6 @@ static bool read_varlen(FILE *f, int c, unsigned *value)
{
unsigned size;
unsigned char buf[4];
unsigned i;
*value = 0;
@@ -130,23 +136,25 @@ static bool read_varlen(FILE *f, int c, unsigned *value)
*value = (buf[3] << 24)
+ (buf[2] << 16)
+ (buf[2] << 8)
+ (buf[1] << 8)
+ (buf[0] << 0);
return true;
err:
printf("(ERROR %d - %s)\n", errno, strerror(errno));
return;
return false;
}
static void show_hard(FILE *f, int c)
{
unsigned type = c >> 3;
unsigned value;
unsigned size;
char *label;
printf("DWT - ", type);
if (dump_swit)
return;
printf("DWT - ");
if (!read_varlen(f, c, &value))
return;
@@ -216,7 +224,7 @@ static void show_hard(FILE *f, int c)
}
break;
default:
printf("UNDEFINED");
printf("UNDEFINED, rawtype: %x", type);
break;
}
@@ -241,19 +249,28 @@ struct {
static void show_swit(FILE *f, int c)
{
unsigned size;
unsigned port = c >> 3;
unsigned char buf[4];
unsigned value = 0;
unsigned i;
printf("SWIT %u - ", port);
if (port + 1 == dump_swit) {
if (!read_varlen(f, c, &value))
return;
printf("%c", value);
return;
}
if (!read_varlen(f, c, &value))
return;
if (dump_swit)
return;
printf("SWIT %u - ", port);
printf("%#08x", value);
for (i = 0; i <= sizeof(format) / sizeof(format[0]); i++) {
for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
if (format[i].port == port) {
printf(", ");
format[i].show(port, value);
@@ -263,10 +280,6 @@ static void show_swit(FILE *f, int c)
printf("\n");
return;
err:
printf("(ERROR %d - %s)\n", errno, strerror(errno));
return;
}
static void show_timestamp(FILE *f, int c)
@@ -275,6 +288,9 @@ static void show_timestamp(FILE *f, int c)
char *label = "";
bool delayed = false;
if (dump_swit)
return;
printf("TIMESTAMP - ");
/* Format 2: header only */
@@ -293,7 +309,7 @@ static void show_timestamp(FILE *f, int c)
}
/* Format 1: one to four bytes of data too */
switch (c) {
switch (c >> 4) {
default:
label = ", reserved control\n";
break;
@@ -356,7 +372,7 @@ int main(int argc, char **argv)
int c;
/* parse arguments */
while ((c = getopt(argc, argv, "f:")) != EOF) {
while ((c = getopt(argc, argv, "f:d:")) != EOF) {
switch (c) {
case 'f':
/* e.g. from UART connected to /dev/ttyUSB0 */
@@ -366,8 +382,10 @@ int main(int argc, char **argv)
return 1;
}
break;
case 'd':
dump_swit = atoi(optarg);
break;
default:
usage:
fprintf(stderr, "usage: %s [-f input]",
basename(argv[0]));
return 1;

View File

@@ -0,0 +1,72 @@
/***************************************************************************
* Copyright (C) 2014 by Angus Gratton *
* Derived from stm32f1x.S:
* Copyright (C) 2011 by Andreas Fritiofson *
* andreas.fritiofson@gmail.com *
* Copyright (C) 2013 by Roman Dmitrienko *
* me@iamroman.org *
* *
* 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/>. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m0
.thumb
.thumb_func
/* Written for NRF51822 (src/flash/nor/nrf51.c) however the NRF NVMC is
* very generic (CPU blocks during flash writes), so this is actually
* just a generic word-oriented copy routine for cortex-m0 (also
* suitable for cortex m0plus/m3/m4.)
*
* To assemble:
* arm-none-eabi-gcc -c cortex-m0.S
*
* To disassemble:
* arm-none-eabi-objdump -o cortex-m0.o
*
* Thanks to Jens Bauer for providing advice on some of the tweaks.
*/
/* Params:
* r0 - byte count (in)
* r1 - workarea start
* r2 - workarea end
* r3 - target address
* Clobbered:
* r4 - rp
* r5 - wp, tmp
*/
wait_fifo:
ldr r5, [r1, #0] /* read wp */
cmp r5, #0 /* abort if wp == 0 */
beq exit
ldr r4, [r1, #4] /* read rp */
cmp r4, r5 /* wait until rp != wp */
beq wait_fifo
ldmia r4!, {r5} /* "*target_address++ = *rp++" */
stmia r3!, {r5}
cmp r4, r2 /* wrap rp at end of work area buffer */
bcc no_wrap
mov r4, r1
adds r4, #8 /* skip rp,wp at start of work area */
no_wrap:
str r4, [r1, #4] /* write back rp */
subs r0, #4 /* decrement byte count */
bne wait_fifo /* loop if not done */
exit:
bkpt #0

View File

@@ -39,6 +39,17 @@
* r11 - current page end address
*/
/*
* This code is embedded within: src/flash/nor/lpcspifi.c as a "C" array.
*
* To rebuild:
* arm-none-eabi-gcc -c lpcspifi_write.S
* arm-none-eabi-objcopy -O binary lpcspifi_write.o lpcspifi_write.bin
* xxd -c 8 -i lpcspifi_write.bin > lpcspifi_write.txt
*
* Then read and edit this result into the "C" source.
*/
#define SSP_BASE_HIGH 0x4008
#define SSP_BASE_LOW 0x3000
#define SSP_CR0_OFFSET 0x00
@@ -204,6 +215,7 @@ error:
movs r0, #0
str r0, [r2, #4] /* set rp = 0 on error */
exit:
bl cs_up /* end the command before returning */
mov r0, r6
bkpt #0x00

View File

@@ -0,0 +1,232 @@
/***************************************************************************
* Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> *
* *
* Adapted from (contrib/loaders/flash/lpcspifi_write.S): *
* Copyright (C) 2012 by George Harris *
* george@luminairecoffee.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m3
.thumb
.thumb_func
/*
* For compilation:
* arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c contrib/loaders/flash/mrvlqspi_write.S
* arm-none-eabi-objcopy -O binary mrvlqspi_write.o code.bin
* Copy code.bin into mrvlqspi flash driver
*/
/*
* Params :
* r0 = workarea start, status (out)
* r1 = workarea end
* r2 = target address (offset from flash base)
* r3 = count (bytes)
* r4 = page size
* r5 = qspi base address
* Clobbered:
* r7 - rp
* r8 - wp, tmp
* r9 - send/receive data
* r10 - current page end address
*/
#define CNTL 0x0
#define CONF 0x4
#define DOUT 0x8
#define DIN 0xc
#define INSTR 0x10
#define ADDR 0x14
#define RDMODE 0x18
#define HDRCNT 0x1c
#define DINCNT 0x20
#define SS_EN (1 << 0)
#define XFER_RDY (1 << 1)
#define RFIFO_EMPTY (1 << 4)
#define WFIFO_EMPTY (1 << 6)
#define WFIFO_FULL (1 << 7)
#define FIFO_FLUSH (1 << 9)
#define RW_EN (1 << 13)
#define XFER_STOP (1 << 14)
#define XFER_START (1 << 15)
#define INS_WRITE_ENABLE 0x06
#define INS_READ_STATUS 0x05
#define INS_PAGE_PROGRAM 0x02
init:
mov.w r10, #0x00
find_next_page_boundary:
add r10, r4 /* Increment to the next page */
cmp r10, r2
/* If we have not reached the next page boundary after the target address, keep going */
bls find_next_page_boundary
write_enable:
/* Flush read/write fifo's */
bl flush_fifo
/* Instruction byte 1 */
movs r8, #0x1
str r8, [r5, #HDRCNT]
/* Set write enable instruction */
movs r8, #INS_WRITE_ENABLE
str r8, [r5, #INSTR]
movs r9, #0x1
bl start_tx
bl stop_tx
page_program:
/* Instruction byte 1, Addr byte 3 */
movs r8, #0x31
str r8, [r5, #HDRCNT]
/* Todo: set addr and data pin to single */
write_address:
mov r8, r2
str r8, [r5, #ADDR]
/* Set page program instruction */
movs r8, #INS_PAGE_PROGRAM
str r8, [r5, #INSTR]
/* Start write transfer */
movs r9, #0x1
bl start_tx
wait_fifo:
ldr r8, [r0] /* read the write pointer */
cmp r8, #0 /* if it's zero, we're gonzo */
beq exit
ldr r7, [r0, #4] /* read the read pointer */
cmp r7, r8 /* wait until they are not equal */
beq wait_fifo
write:
ldrb r9, [r7], #0x01 /* Load one byte from the FIFO, increment the read pointer by 1 */
bl write_data /* send the byte to the flash chip */
cmp r7, r1 /* wrap the read pointer if it is at the end */
it cs
addcs r7, r0, #8 /* skip loader args */
str r7, [r0, #4] /* store the new read pointer */
subs r3, r3, #1 /* decrement count */
cmp r3, #0 /* Exit if we have written everything */
beq write_wait
add r2, #1 /* Increment flash address by 1 */
cmp r10, r2 /* See if we have reached the end of a page */
bne wait_fifo /* If not, keep writing bytes */
write_wait:
bl stop_tx /* Otherwise, end the command and keep going w/ the next page */
add r10, r4 /* Move up the end-of-page address by the page size*/
check_flash_busy: /* Wait for the flash to finish the previous page write */
/* Flush read/write fifo's */
bl flush_fifo
/* Instruction byte 1 */
movs r8, #0x1
str r8, [r5, #HDRCNT]
/* Continuous data in of status register */
movs r8, #0x0
str r8, [r5, #DINCNT]
/* Set write enable instruction */
movs r8, #INS_READ_STATUS
str r8, [r5, #INSTR]
/* Start read transfer */
movs r9, #0x0
bl start_tx
wait_flash_busy:
bl read_data
and.w r9, r9, #0x1
cmp r9, #0x0
bne.n wait_flash_busy
bl stop_tx
cmp r3, #0
bne.n write_enable /* If it is done, start a new page write */
b exit /* All data written, exit */
write_data: /* Send/receive 1 byte of data over QSPI */
ldr r8, [r5, #CNTL]
lsls r8, r8, #24
bmi.n write_data
str r9, [r5, #DOUT]
bx lr
read_data: /* Read 1 byte of data over QSPI */
ldr r8, [r5, #CNTL]
lsls r8, r8, #27
bmi.n read_data
ldr r9, [r5, #DIN]
bx lr
flush_fifo: /* Flush read write fifos */
ldr r8, [r5, #CONF]
orr.w r8, r8, #FIFO_FLUSH
str r8, [r5, #CONF]
flush_reset:
ldr r8, [r5, #CONF]
lsls r8, r8, #22
bmi.n flush_reset
bx lr
start_tx:
ldr r8, [r5, #CNTL]
orr.w r8, r8, #SS_EN
str r8, [r5, #CNTL]
xfer_rdy:
ldr r8, [r5, #CNTL]
lsls r8, r8, #30
bpl.n xfer_rdy
ldr r8, [r5, #CONF]
bfi r8, r9, #13, #1
orr.w r8, r8, #XFER_START
str r8, [r5, #CONF]
bx lr
stop_tx:
ldr r8, [r5, #CNTL]
lsls r8, r8, #30
bpl.n stop_tx
wfifo_wait:
ldr r8, [r5, #CNTL]
lsls r8, r8, #25
bpl.n wfifo_wait
ldr r8, [r5, #CONF]
orr.w r8, r8, #XFER_STOP
str r8, [r5, #CONF]
xfer_start:
ldr r8, [r5, #CONF]
lsls r8, r8, #16
bmi.n xfer_start
ss_disable:
# Disable SS_EN
ldr r8, [r5, #CNTL]
bic.w r8, r8, #SS_EN
str r8, [r5, #CNTL]
wait:
ldr r8, [r5, #CNTL]
lsls r8, r8, #30
bpl.n wait
bx lr
error:
movs r0, #0
str r0, [r2, #4] /* set rp = 0 on error */
exit:
mov r0, r6
bkpt #0x00
.end

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (C) 2014 by Ladislav Bábel *
* ladababel@seznam.cz *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (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. *
***************************************************************************/
#define INITIAL_UNLOCK 0x5A
#define MULTIPLE_UNLOCK 0xF2
#define FLASHCTRL_KEY 0x4002E0C0
#define FLASHCTRL_CONFIG 0x4002E000
#define FLASHCTRL_WRADDR 0x4002E0A0
#define FLASHCTRL_WRDATA 0x4002E0B0
#define BUSYF 0x00100000
/* Write the initial unlock value to KEY (0xA5) */
movs r6, #INITIAL_UNLOCK
str r6, [r0, #FLASHCTRL_KEY]
/* Write the multiple unlock value to KEY (0xF2) */
movs r6, #MULTIPLE_UNLOCK
str r6, [r0, #FLASHCTRL_KEY]
wait_fifo:
ldr r6, [r2, #0]
cmp r6, #0
beq exit
ldr r5, [r2, #4]
cmp r5, r6
beq wait_fifo
/* wait for BUSYF flag */
wait_busy1:
ldr r6, [r0, #FLASHCTRL_CONFIG]
tst r6, #BUSYF
bne wait_busy1
/* Write the destination address to WRADDR */
str r4, [r0, #FLASHCTRL_WRADDR]
/* Write the data half-word to WRDATA in right-justified format */
ldrh r6, [r5]
str r6, [r0, #FLASHCTRL_WRDATA]
adds r5, #2
adds r4, #2
/* wrap rp at end of buffer */
cmp r5, r3
bcc no_wrap
mov r5, r2
adds r5, #8
no_wrap:
str r5, [r2, #4]
subs r1, r1, #1
cmp r1, #0
beq exit
b wait_fifo
exit:
movs r6, #MULTIPLE_LOCK
str r6, [r0, #FLASHCTRL_KEY]
/* wait for BUSYF flag */
wait_busy2:
ldr r6, [r0, #FLASHCTRL_CONFIG]
tst r6, #BUSYF
bne wait_busy2
bkpt #0

View File

@@ -0,0 +1,20 @@
/*
* Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer
* present in the kernel, so it has to be supplied by other means for
* OpenOCD's threads awareness.
*
* Add this file to your project, and, if you're using --gc-sections,
* ``--undefined=uxTopUsedPriority'' (or
* ``-Wl,--undefined=uxTopUsedPriority'' when using gcc for final
* linking) to your LDFLAGS; same with all the other symbols you need.
*/
#include "FreeRTOS.h"
#ifdef __GNUC__
#define USED __attribute__((used))
#else
#define USED
#endif
const int USED uxTopUsedPriority = configMAX_PRIORITIES;

File diff suppressed because it is too large Load Diff

2
jimtcl

Submodule jimtcl updated: 2c1eba991e...51f65c6d38

View File

@@ -32,8 +32,7 @@ endif
libopenocd_la_SOURCES = \
hello.c \
openocd.c \
startup_tcl.c
openocd.c
noinst_HEADERS = \
hello.h \
@@ -75,7 +74,7 @@ libopenocd_la_LIBADD = \
$(top_builddir)/src/rtos/librtos.la \
$(top_builddir)/src/helper/libhelper.la \
$(LIBFTDI_LIBS) $(MINGWLDADD) \
$(HIDAPI_LIBS) $(LIBUSB1_LIBS) $(LIBUSB0_LIBS)
$(HIDAPI_LIBS) $(LIBUSB0_LIBS) $(LIBUSB1_LIBS)
STARTUP_TCL_SRCS = \
$(srcdir)/helper/startup.tcl \
@@ -86,23 +85,23 @@ STARTUP_TCL_SRCS = \
EXTRA_DIST = $(STARTUP_TCL_SRCS)
BUILT_SOURCES = startup.tcl
BUILT_SOURCES = startup_tcl.inc
startup.tcl: $(STARTUP_TCL_SRCS)
cat $^ > $@
BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
BIN2C = $(top_srcdir)/src/helper/bin2char.sh
# Convert .tcl to cfile
startup_tcl.c: startup.tcl $(BIN2C)
$(BIN2C) openocd_startup_tcl < $< > $@ || rm -f $@
# Convert .tcl to c-array
startup_tcl.inc: startup.tcl $(BIN2C)
$(BIN2C) < $< > $@ || { rm -f $@; false; }
# add startup_tcl.c to make clean list
CLEANFILES = startup.tcl startup_tcl.c
# add generated files to make clean list
CLEANFILES = startup.tcl startup_tcl.inc
# we do not want generated file in the dist
dist-hook:
rm -f $(distdir)/startup_tcl.c
rm -f $(distdir)/startup_tcl.inc
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@@ -43,7 +43,10 @@ NOR_DRIVERS = \
kinetis.c \
mini51.c \
nuc1x.c \
nrf51.c
nrf51.c \
mrvlqspi.c \
psoc4.c \
sim3x.c
noinst_HEADERS = \
core.h \

View File

@@ -67,7 +67,7 @@
#define REG_NAME_WIDTH (12)
/* at91sam4s series (has always one flash bank)*/
/* at91sam4s/at91sam4e series (has always one flash bank)*/
#define FLASH_BANK_BASE_S 0x00400000
/* at91sam4sd series (two one flash banks), first bank address */
@@ -260,6 +260,42 @@ static struct sam4_chip *get_current_sam4(struct command_context *cmd_ctx)
/* these are used to *initialize* the "pChip->details" structure. */
static const struct sam4_chip_details all_sam4_details[] = {
/* Start at91sam4e* series */
/*atsam4e16e - LQFP144/LFBGA144*/
{
.chipid_cidr = 0xA3CC0CE0,
.name = "at91sam4e16e",
.total_flash_size = 1024 * 1024,
.total_sram_size = 128 * 1024,
.n_gpnvms = 2,
.n_banks = 1,
{
/* .bank[0] = {*/
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 1024 * 1024,
.nsectors = 128,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = {*/
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
},
/* Start at91sam4s* series */
/*atsam4s16c - LQFP100/BGA100*/
{
@@ -460,6 +496,40 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
/*atsam4s4a - LQFP48/BGA48*/
{
.chipid_cidr = 0x288b09e0,
.name = "at91sam4s4a",
.total_flash_size = 256 * 1024,
.total_sram_size = 64 * 1024,
.n_gpnvms = 2,
.n_banks = 1,
{
/* .bank[0] = {*/
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK_BASE_S,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 256 * 1024,
.nsectors = 32,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = {*/
{
.present = 0,
.probed = 0,
.bank_number = 1,
},
},
},
/*at91sam4sd32c*/
{
.chipid_cidr = 0x29a70ee0,
@@ -504,6 +574,94 @@ static const struct sam4_chip_details all_sam4_details[] = {
},
},
/*at91sam4sd16c*/
{
.chipid_cidr = 0x29a70ce0,
.name = "at91sam4sd16c",
.total_flash_size = 1024 * 1024,
.total_sram_size = 160 * 1024,
.n_gpnvms = 3,
.n_banks = 2,
/* .bank[0] = { */
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = { */
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
},
},
/*at91sam4sa16c*/
{
.chipid_cidr = 0x28a70ce0,
.name = "at91sam4sa16c",
.total_flash_size = 1024 * 1024,
.total_sram_size = 160 * 1024,
.n_gpnvms = 3,
.n_banks = 2,
/* .bank[0] = { */
{
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 0,
.base_address = FLASH_BANK0_BASE_SD,
.controller_address = 0x400e0a00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
/* .bank[1] = { */
{
.probed = 0,
.pChip = NULL,
.pBank = NULL,
.bank_number = 1,
.base_address = FLASH_BANK1_BASE_1024K_SD,
.controller_address = 0x400e0c00,
.flash_wait_states = 6, /* workaround silicon bug */
.present = 1,
.size_bytes = 512 * 1024,
.nsectors = 64,
.sector_size = 8192,
.page_size = 512,
},
},
},
/* at91samg53n19 */
{
.chipid_cidr = 0x247e0ae0,
@@ -1111,6 +1269,7 @@ static const struct archnames { unsigned value; const char *name; } archnames[]
{ 0x37, "CAP7 Series" },
{ 0x39, "CAP9 Series" },
{ 0x3B, "CAP11 Series" },
{ 0x3C, "ATSAM4E" },
{ 0x40, "AT91x40 Series" },
{ 0x42, "AT91x42 Series" },
{ 0x43, "SAMG51 Series"

View File

@@ -24,18 +24,20 @@
#include "imp.h"
#include <target/cortex_m.h>
/* At this time, the SAM4L Flash is available in these capacities:
* ATSAM4Lx4xx: 256KB (512 pages)
* ATSAM4Lx2xx: 128KB (256 pages)
* ATSAM4Lx8xx: 512KB (1024 pages)
*/
/* There are 16 lockable regions regardless of overall capacity. The number
/* There are 16 lockable regions regardless of overall capacity. The number
* of pages per sector is therefore dependant on capacity. */
#define SAM4L_NUM_SECTORS 16
/* Locations in memory map */
#define SAM4L_FLASH 0x00000000 /* Flash region */
#define SAM4L_FLASH ((uint32_t)0x00000000) /* Flash region */
#define SAM4L_FLASH_USER 0x00800000 /* Flash user page region */
#define SAM4L_FLASHCALW 0x400A0000 /* Flash controller */
#define SAM4L_CHIPID 0x400E0740 /* Chip Identification */
@@ -75,6 +77,14 @@
#define SAM4L_FMCD_CMDKEY 0xA5UL /* 'key' to issue commands, see 14.10.2 */
/* SMAP registers and bits */
#define SMAP_BASE 0x400A3000
#define SMAP_SCR (SMAP_BASE + 8)
#define SMAP_SCR_HCR (1 << 1)
struct sam4l_chip_info {
uint32_t id;
uint32_t exid;
@@ -253,7 +263,7 @@ static int sam4l_check_page_erased(struct flash_bank *bank, uint32_t pn,
/* Issue a quick page read to verify that we've erased this page */
res = sam4l_flash_command(bank->target, SAM4L_FCMD_QPR, pn);
if (res != ERROR_OK) {
LOG_ERROR("Quick page read %d failed", pn);
LOG_ERROR("Quick page read %" PRIu32 " failed", pn);
return res;
}
@@ -307,7 +317,7 @@ static int sam4l_probe(struct flash_bank *bank)
chip->flash_kb = 512;
break;
default:
LOG_ERROR("Unknown flash size (chip ID is %08X), assuming 128K", id);
LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id);
chip->flash_kb = 128;
break;
}
@@ -351,8 +361,8 @@ static int sam4l_probe(struct flash_bank *bank)
/* Done */
chip->probed = true;
LOG_INFO("SAM4L MCU: %s (Rev %c) (%uKB Flash with %d %dB pages, %uKB RAM)",
chip->details ? chip->details->name : "unknown", 'A' + (id & 0xF),
LOG_INFO("SAM4L MCU: %s (Rev %c) (%" PRIu32 "KB Flash with %d %" PRId32 "B pages, %" PRIu32 "KB RAM)",
chip->details ? chip->details->name : "unknown", (char)('A' + (id & 0xF)),
chip->flash_kb, chip->num_pages, chip->page_size, chip->ram_kb);
return ERROR_OK;
@@ -633,21 +643,47 @@ static int sam4l_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_OK;
}
COMMAND_HANDLER(sam4l_handle_info_command)
COMMAND_HANDLER(sam4l_handle_reset_deassert)
{
return ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
struct armv7m_common *armv7m = target_to_armv7m(target);
struct adiv5_dap *swjdp = armv7m->arm.dap;
int retval = ERROR_OK;
enum reset_types jtag_reset_config = jtag_get_reset_config();
/* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
* so we just release reset held by SMAP
*
* n_RESET (srst) clears the DP, so reenable debug and set vector catch here
*
* After vectreset SMAP release is not needed however makes no harm
*/
if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
retval = mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
if (retval == ERROR_OK)
retval = mem_ap_write_atomic_u32(swjdp, DCB_DEMCR,
TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
/* do not return on error here, releasing SMAP reset is more important */
}
int retval2 = mem_ap_write_atomic_u32(swjdp, SMAP_SCR, SMAP_SCR_HCR);
if (retval2 != ERROR_OK)
return retval2;
return retval;
}
static const struct command_registration at91sam4l_exec_command_handlers[] = {
{
.name = "info",
.handler = sam4l_handle_info_command,
.name = "smap_reset_deassert",
.handler = sam4l_handle_reset_deassert,
.mode = COMMAND_EXEC,
.help = "Print information about the current at91sam4l chip"
"and its flash configuration.",
.help = "deasert internal reset held by SMAP"
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration at91sam4l_command_handlers[] = {
{
.name = "at91sam4l",

View File

@@ -23,10 +23,14 @@
#endif
#include "imp.h"
#include "helper/binarybuffer.h"
#define SAMD_NUM_SECTORS 16
#define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH 0x00000000 /* physical Flash memory */
#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */
#define SAMD_USER_ROW ((uint32_t)0x00804000) /* User Row of Flash */
#define SAMD_PAC1 0x41000000 /* Peripheral Access Control 1 */
#define SAMD_DSU 0x41002000 /* Device Service Unit */
#define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */
@@ -59,8 +63,11 @@
/* Known identifiers */
#define SAMD_PROCESSOR_M0 0x01
#define SAMD_FAMILY_D 0x00
#define SAMD_FAMILY_L 0x01
#define SAMD_SERIES_20 0x00
#define SAMD_SERIES_21 0x01
#define SAMD_SERIES_10 0x02
#define SAMD_SERIES_11 0x03
struct samd_part {
uint8_t id;
@@ -69,6 +76,32 @@ struct samd_part {
uint32_t ram_kb;
};
/* Known SAMD10 parts */
static const struct samd_part samd10_parts[] = {
{ 0x0, "SAMD10D14AMU", 16, 4 },
{ 0x1, "SAMD10D13AMU", 8, 4 },
{ 0x2, "SAMD10D12AMU", 4, 4 },
{ 0x3, "SAMD10D14ASU", 16, 4 },
{ 0x4, "SAMD10D13ASU", 8, 4 },
{ 0x5, "SAMD10D12ASU", 4, 4 },
{ 0x6, "SAMD10C14A", 16, 4 },
{ 0x7, "SAMD10C13A", 8, 4 },
{ 0x8, "SAMD10C12A", 4, 4 },
};
/* Known SAMD11 parts */
static const struct samd_part samd11_parts[] = {
{ 0x0, "SAMD11D14AMU", 16, 4 },
{ 0x1, "SAMD11D13AMU", 8, 4 },
{ 0x2, "SAMD11D12AMU", 4, 4 },
{ 0x3, "SAMD11D14ASU", 16, 4 },
{ 0x4, "SAMD11D13ASU", 8, 4 },
{ 0x5, "SAMD11D12ASU", 4, 4 },
{ 0x6, "SAMD11C14A", 16, 4 },
{ 0x7, "SAMD11C13A", 8, 4 },
{ 0x8, "SAMD11C12A", 4, 4 },
};
/* Known SAMD20 parts. See Table 12-8 in 42129FSAM10/2013 */
static const struct samd_part samd20_parts[] = {
{ 0x0, "SAMD20J18A", 256, 32 },
@@ -81,6 +114,7 @@ static const struct samd_part samd20_parts[] = {
{ 0x7, "SAMD20G16A", 64, 8 },
{ 0x8, "SAMD20G15A", 32, 4 },
{ 0x9, "SAMD20G14A", 16, 2 },
{ 0xA, "SAMD20E18A", 256, 32 },
{ 0xB, "SAMD20E17A", 128, 16 },
{ 0xC, "SAMD20E16A", 64, 8 },
{ 0xD, "SAMD20E15A", 32, 4 },
@@ -106,6 +140,30 @@ static const struct samd_part samd21_parts[] = {
{ 0xE, "SAMD21E14A", 16, 2 },
};
/* Known SAMR21 parts. */
static const struct samd_part samr21_parts[] = {
{ 0x19, "SAMR21G18A", 256, 32 },
{ 0x1A, "SAMR21G17A", 128, 32 },
{ 0x1B, "SAMR21G16A", 64, 32 },
{ 0x1C, "SAMR21E18A", 256, 32 },
{ 0x1D, "SAMR21E17A", 128, 32 },
{ 0x1E, "SAMR21E16A", 64, 32 },
};
/* Known SAML21 parts. */
static const struct samd_part saml21_parts[] = {
{ 0x00, "SAML21J18A", 256, 32 },
{ 0x01, "SAML21J17A", 128, 16 },
{ 0x02, "SAML21J16A", 64, 8 },
{ 0x05, "SAML21G18A", 256, 32 },
{ 0x06, "SAML21G17A", 128, 16 },
{ 0x07, "SAML21G16A", 64, 8 },
{ 0x0A, "SAML21E18A", 256, 32 },
{ 0x0B, "SAML21E17A", 128, 16 },
{ 0x0C, "SAML21E16A", 64, 8 },
{ 0x0D, "SAML21E15A", 32, 4 },
};
/* Each family of parts contains a parts table in the DEVSEL field of DID. The
* processor ID, family ID, and series ID are used to determine which exact
* family this is and then we can use the corresponding table. */
@@ -123,6 +181,14 @@ static const struct samd_family samd_families[] = {
samd20_parts, ARRAY_SIZE(samd20_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
samd21_parts, ARRAY_SIZE(samd21_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21,
samr21_parts, ARRAY_SIZE(samr21_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10,
samd10_parts, ARRAY_SIZE(samd10_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11,
samd11_parts, ARRAY_SIZE(samd11_parts) },
{ SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21,
saml21_parts, ARRAY_SIZE(saml21_parts) },
};
struct samd_info {
@@ -140,8 +206,8 @@ static struct samd_info *samd_chips;
static const struct samd_part *samd_find_part(uint32_t id)
{
uint8_t processor = (id >> 28);
uint8_t family = (id >> 24) & 0x0F;
uint8_t series = (id >> 16) & 0xFF;
uint8_t family = (id >> 23) & 0x1F;
uint8_t series = (id >> 16) & 0x3F;
uint8_t devsel = id & 0xFF;
for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) {
@@ -175,9 +241,31 @@ static int samd_protect_check(struct flash_bank *bank)
return ERROR_OK;
}
static int samd_get_flash_page_info(struct target *target,
uint32_t *sizep, int *nump)
{
int res;
uint32_t param;
res = target_read_u32(target, SAMD_NVMCTRL + SAMD_NVMCTRL_PARAM, &param);
if (res == ERROR_OK) {
/* The PSZ field (bits 18:16) indicate the page size bytes as 2^(3+n)
* so 0 is 8KB and 7 is 1024KB. */
if (sizep)
*sizep = (8 << ((param >> 16) & 0x7));
/* The NVMP field (bits 15:0) indicates the total number of pages */
if (nump)
*nump = param & 0xFFFF;
} else {
LOG_ERROR("Couldn't read NVM Parameters register");
}
return res;
}
static int samd_probe(struct flash_bank *bank)
{
uint32_t id, param;
uint32_t id;
int res;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
const struct samd_part *part;
@@ -197,28 +285,22 @@ static int samd_probe(struct flash_bank *bank)
return ERROR_FAIL;
}
res = target_read_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_PARAM, &param);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read NVM Parameters register");
return res;
}
bank->size = part->flash_kb * 1024;
chip->sector_size = bank->size / SAMD_NUM_SECTORS;
/* The PSZ field (bits 18:16) indicate the page size bytes as 2^(3+n) so
* 0 is 8KB and 7 is 1024KB. */
chip->page_size = (8 << ((param >> 16) & 0x7));
/* The NVMP field (bits 15:0) indicates the total number of pages */
chip->num_pages = param & 0xFFFF;
res = samd_get_flash_page_info(bank->target, &chip->page_size,
&chip->num_pages);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't determine Flash page size");
return res;
}
/* Sanity check: the total flash size in the DSU should match the page size
* multiplied by the number of pages. */
if (bank->size != chip->num_pages * chip->page_size) {
LOG_WARNING("SAMD: bank size doesn't match NVM parameters. "
"Identified %uKB Flash but NVMCTRL reports %u %uB pages",
"Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages",
part->flash_kb, chip->num_pages, chip->page_size);
}
@@ -243,53 +325,19 @@ static int samd_probe(struct flash_bank *bank)
/* Done */
chip->probed = true;
LOG_INFO("SAMD MCU: %s (%uKB Flash, %uKB RAM)", part->name,
LOG_INFO("SAMD MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name,
part->flash_kb, part->ram_kb);
return ERROR_OK;
}
static int samd_protect(struct flash_bank *bank, int set, int first, int last)
{
int res;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
res = ERROR_OK;
for (int s = first; s <= last; s++) {
if (set != bank->sectors[s].is_protected) {
/* Load an address that is within this sector (we use offset 0) */
res = target_write_u32(bank->target, SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
s * chip->sector_size);
if (res != ERROR_OK)
goto exit;
/* Tell the controller to lock that sector */
uint16_t cmd = (set) ?
SAMD_NVM_CMD(SAMD_NVM_CMD_LR) :
SAMD_NVM_CMD(SAMD_NVM_CMD_UR);
res = target_write_u16(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
cmd);
if (res != ERROR_OK)
goto exit;
}
}
exit:
samd_protect_check(bank);
return res;
}
static bool samd_check_error(struct flash_bank *bank)
static bool samd_check_error(struct target *target)
{
int ret;
bool error;
uint16_t status;
ret = target_read_u16(bank->target,
ret = target_read_u16(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, &status);
if (ret != ERROR_OK) {
LOG_ERROR("Can't read NVM status");
@@ -310,7 +358,7 @@ static bool samd_check_error(struct flash_bank *bank)
}
/* Clear the error conditions by writing a one to them */
ret = target_write_u16(bank->target,
ret = target_write_u16(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_STATUS, status);
if (ret != ERROR_OK)
LOG_ERROR("Can't clear NVM error conditions");
@@ -318,32 +366,216 @@ static bool samd_check_error(struct flash_bank *bank)
return error;
}
static int samd_erase_row(struct flash_bank *bank, uint32_t address)
static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd)
{
int res;
bool error = false;
/* Set an address contained in the row to be erased */
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, address >> 1);
if (res == ERROR_OK) {
/* Issue the Erase Row command to erase that row */
res = target_write_u16(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA,
SAMD_NVM_CMD(SAMD_NVM_CMD_ER));
/* Check (and clear) error conditions */
error = samd_check_error(bank);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (res != ERROR_OK || error) {
LOG_ERROR("Failed to erase row containing %08X" PRIx32, address);
/* Read current configuration. */
uint16_t tmp = 0;
int res = target_read_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB,
&tmp);
if (res != ERROR_OK)
return res;
/* Set cache disable. */
res = target_write_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB,
tmp | (1<<18));
if (res != ERROR_OK)
return res;
/* Issue the NVM command */
int res_cmd = target_write_u16(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLA, SAMD_NVM_CMD(cmd));
/* Try to restore configuration, regardless of NVM command write
* status. */
res = target_write_u16(target, SAMD_NVMCTRL + SAMD_NVMCTRL_CTRLB, tmp);
if (res_cmd != ERROR_OK)
return res_cmd;
if (res != ERROR_OK)
return res;
/* Check to see if the NVM command resulted in an error condition. */
if (samd_check_error(target))
return ERROR_FAIL;
return ERROR_OK;
}
static int samd_erase_row(struct target *target, uint32_t address)
{
int res;
/* Set an address contained in the row to be erased */
res = target_write_u32(target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, address >> 1);
/* Issue the Erase Row command to erase that row. */
if (res == ERROR_OK)
res = samd_issue_nvmctrl_command(target,
address == SAMD_USER_ROW ? SAMD_NVM_CMD_EAR : SAMD_NVM_CMD_ER);
if (res != ERROR_OK) {
LOG_ERROR("Failed to erase row containing %08" PRIx32, address);
return ERROR_FAIL;
}
return ERROR_OK;
}
static bool is_user_row_reserved_bit(uint8_t bit)
{
/* See Table 9-3 in the SAMD20 datasheet for more information. */
switch (bit) {
/* Reserved bits */
case 3:
case 7:
/* Voltage regulator internal configuration with default value of 0x70,
* may not be changed. */
case 17 ... 24:
/* 41 is voltage regulator internal configuration and must not be
* changed. 42 through 47 are reserved. */
case 41 ... 47:
return true;
default:
break;
}
return false;
}
/* Modify the contents of the User Row in Flash. These are described in Table
* 9-3 of the SAMD20 datasheet. The User Row itself has a size of one page
* and contains a combination of "fuses" and calibration data in bits 24:17.
* We therefore try not to erase the row's contents unless we absolutely have
* to and we don't permit modifying reserved bits. */
static int samd_modify_user_row(struct target *target, uint32_t value,
uint8_t startb, uint8_t endb)
{
int res;
if (is_user_row_reserved_bit(startb) || is_user_row_reserved_bit(endb)) {
LOG_ERROR("Can't modify bits in the requested range");
return ERROR_FAIL;
}
/* Retrieve the MCU's page size, in bytes. This is also the size of the
* entire User Row. */
uint32_t page_size;
res = samd_get_flash_page_info(target, &page_size, NULL);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't determine Flash page size");
return res;
}
/* Make sure the size is sane before we allocate. */
assert(page_size > 0 && page_size <= SAMD_PAGE_SIZE_MAX);
/* Make sure we're within the single page that comprises the User Row. */
if (startb >= (page_size * 8) || endb >= (page_size * 8)) {
LOG_ERROR("Can't modify bits outside the User Row page range");
return ERROR_FAIL;
}
uint8_t *buf = malloc(page_size);
if (!buf)
return ERROR_FAIL;
/* Read the user row (comprising one page) by half-words. */
res = target_read_memory(target, SAMD_USER_ROW, 2, page_size / 2, buf);
if (res != ERROR_OK)
goto out_user_row;
/* We will need to erase before writing if the new value needs a '1' in any
* position for which the current value had a '0'. Otherwise we can avoid
* erasing. */
uint32_t cur = buf_get_u32(buf, startb, endb - startb + 1);
if ((~cur) & value) {
res = samd_erase_row(target, SAMD_USER_ROW);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't erase user row");
goto out_user_row;
}
}
/* Modify */
buf_set_u32(buf, startb, endb - startb + 1, value);
/* Write the page buffer back out to the target. A Flash write will be
* triggered automatically. */
res = target_write_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
goto out_user_row;
if (samd_check_error(target)) {
res = ERROR_FAIL;
goto out_user_row;
}
/* Success */
res = ERROR_OK;
out_user_row:
free(buf);
return res;
}
static int samd_protect(struct flash_bank *bank, int set, int first, int last)
{
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
/* We can issue lock/unlock region commands with the target running but
* the settings won't persist unless we're able to modify the LOCK regions
* and that requires the target to be halted. */
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
int res = ERROR_OK;
for (int s = first; s <= last; s++) {
if (set != bank->sectors[s].is_protected) {
/* Load an address that is within this sector (we use offset 0) */
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR,
((s * chip->sector_size) >> 1));
if (res != ERROR_OK)
goto exit;
/* Tell the controller to lock that sector */
res = samd_issue_nvmctrl_command(bank->target,
set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR);
if (res != ERROR_OK)
goto exit;
}
}
/* We've now applied our changes, however they will be undone by the next
* reset unless we also apply them to the LOCK bits in the User Page. The
* LOCK bits start at bit 48, correspoding to Sector 0 and end with bit 63,
* corresponding to Sector 15. A '1' means unlocked and a '0' means
* locked. See Table 9-3 in the SAMD20 datasheet for more details. */
res = samd_modify_user_row(bank->target, set ? 0x0000 : 0xFFFF,
48 + first, 48 + last);
if (res != ERROR_OK)
LOG_WARNING("SAMD: protect settings were not made persistent!");
res = ERROR_OK;
exit:
samd_protect_check(bank);
return res;
}
static int samd_erase(struct flash_bank *bank, int first, int last)
{
int res;
@@ -374,10 +606,10 @@ static int samd_erase(struct flash_bank *bank, int first, int last)
return ERROR_FLASH_OPERATION_FAILED;
}
if (!bank->sectors[s].is_erased) {
if (bank->sectors[s].is_erased != 1) {
/* For each row in that sector */
for (int r = s * rows_in_sector; r < (s + 1) * rows_in_sector; r++) {
res = samd_erase_row(bank, r * chip->page_size * 4);
res = samd_erase_row(bank->target, r * chip->page_size * 4);
if (res != ERROR_OK) {
LOG_ERROR("SAMD: failed to erase sector %d", s);
return res;
@@ -424,7 +656,7 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address,
}
/* Erase the row that we'll be writing to */
res = samd_erase_row(bank, address);
res = samd_erase_row(bank->target, address);
if (res != ERROR_OK)
return res;
@@ -442,7 +674,10 @@ static int samd_write_row(struct flash_bank *bank, uint32_t address,
return res;
}
error = samd_check_error(bank);
/* Access through AHB is stalled while flash is being programmed */
usleep(200);
error = samd_check_error(bank->target);
if (error)
return ERROR_FAIL;
@@ -606,6 +841,166 @@ COMMAND_HANDLER(samd_handle_info_command)
return ERROR_OK;
}
COMMAND_HANDLER(samd_handle_chip_erase_command)
{
struct target *target = get_current_target(CMD_CTX);
if (target) {
/* Enable access to the DSU by disabling the write protect bit */
target_write_u32(target, SAMD_PAC1, (1<<1));
/* Tell the DSU to perform a full chip erase. It takes about 240ms to
* perform the erase. */
target_write_u8(target, SAMD_DSU, (1<<4));
command_print(CMD_CTX, "chip erased");
}
return ERROR_OK;
}
COMMAND_HANDLER(samd_handle_set_security_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (CMD_ARGC < 1 || (CMD_ARGC >= 1 && (strcmp(CMD_ARGV[0], "enable")))) {
command_print(CMD_CTX, "supply the \"enable\" argument to proceed.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (target) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_SSB);
/* Check (and clear) error conditions */
if (res == ERROR_OK)
command_print(CMD_CTX, "chip secured on next power-cycle");
else
command_print(CMD_CTX, "failed to secure chip");
}
return res;
}
COMMAND_HANDLER(samd_handle_eeprom_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (target) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (CMD_ARGC >= 1) {
int val = atoi(CMD_ARGV[0]);
uint32_t code;
if (val == 0)
code = 7;
else {
/* Try to match size in bytes with corresponding size code */
for (code = 0; code <= 6; code++) {
if (val == (2 << (13 - code)))
break;
}
if (code > 6) {
command_print(CMD_CTX, "Invalid EEPROM size. Please see "
"datasheet for a list valid sizes.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
res = samd_modify_user_row(target, code, 4, 6);
} else {
uint16_t val;
res = target_read_u16(target, SAMD_USER_ROW, &val);
if (res == ERROR_OK) {
uint32_t size = ((val >> 4) & 0x7); /* grab size code */
if (size == 0x7)
command_print(CMD_CTX, "EEPROM is disabled");
else {
/* Otherwise, 6 is 256B, 0 is 16KB */
command_print(CMD_CTX, "EEPROM size is %u bytes",
(2 << (13 - size)));
}
}
}
}
return res;
}
COMMAND_HANDLER(samd_handle_bootloader_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (target) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Retrieve the MCU's page size, in bytes. */
uint32_t page_size;
res = samd_get_flash_page_info(target, &page_size, NULL);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't determine Flash page size");
return res;
}
if (CMD_ARGC >= 1) {
int val = atoi(CMD_ARGV[0]);
uint32_t code;
if (val == 0)
code = 7;
else {
/* Try to match size in bytes with corresponding size code */
for (code = 0; code <= 6; code++) {
if ((unsigned int)val == (2UL << (8UL - code)) * page_size)
break;
}
if (code > 6) {
command_print(CMD_CTX, "Invalid bootloader size. Please "
"see datasheet for a list valid sizes.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
res = samd_modify_user_row(target, code, 0, 2);
} else {
uint16_t val;
res = target_read_u16(target, SAMD_USER_ROW, &val);
if (res == ERROR_OK) {
uint32_t size = (val & 0x7); /* grab size code */
uint32_t nb;
if (size == 0x7)
nb = 0;
else
nb = (2 << (8 - size)) * page_size;
/* There are 4 pages per row */
command_print(CMD_CTX, "Bootloader size is %" PRIu32 " bytes (%" PRIu32 " rows)",
nb, (uint32_t)(nb / (page_size * 4)));
}
}
}
return res;
}
static const struct command_registration at91samd_exec_command_handlers[] = {
{
.name = "info",
@@ -614,6 +1009,42 @@ static const struct command_registration at91samd_exec_command_handlers[] = {
.help = "Print information about the current at91samd chip"
"and its flash configuration.",
},
{
.name = "chip-erase",
.handler = samd_handle_chip_erase_command,
.mode = COMMAND_EXEC,
.help = "Erase the entire Flash by using the Chip"
"Erase feature in the Device Service Unit (DSU).",
},
{
.name = "set-security",
.handler = samd_handle_set_security_command,
.mode = COMMAND_EXEC,
.help = "Secure the chip's Flash by setting the Security Bit."
"This makes it impossible to read the Flash contents."
"The only way to undo this is to issue the chip-erase"
"command.",
},
{
.name = "eeprom",
.usage = "[size_in_bytes]",
.handler = samd_handle_eeprom_command,
.mode = COMMAND_EXEC,
.help = "Show or set the EEPROM size setting, stored in the User Row."
"Please see Table 20-3 of the SAMD20 datasheet for allowed values."
"Changes are stored immediately but take affect after the MCU is"
"reset.",
},
{
.name = "bootloader",
.usage = "[size_in_bytes]",
.handler = samd_handle_bootloader_command,
.mode = COMMAND_EXEC,
.help = "Show or set the bootloader size, stored in the User Row."
"Please see Table 20-2 of the SAMD20 datasheet for allowed values."
"Changes are stored immediately but take affect after the MCU is"
"reset.",
},
COMMAND_REGISTRATION_DONE
};

View File

@@ -69,6 +69,7 @@ static const struct avrf_type avft_chips_info[] = {
*/
{"atmega128", 0x9702, 256, 512, 8, 512},
{"at90can128", 0x9781, 256, 512, 8, 512},
{"at90usb128", 0x9782, 256, 512, 8, 512},
{"atmega164p", 0x940a, 128, 128, 4, 128},
{"atmega324p", 0x9508, 128, 256, 4, 256},
{"atmega324pa", 0x9511, 128, 256, 4, 256},

View File

@@ -56,6 +56,9 @@ extern struct flash_driver mdr_flash;
extern struct flash_driver mini51_flash;
extern struct flash_driver nuc1x_flash;
extern struct flash_driver nrf51_flash;
extern struct flash_driver mrvlqspi_flash;
extern struct flash_driver psoc4_flash;
extern struct flash_driver sim3x_flash;
/**
* The list of built-in flash drivers.
@@ -96,6 +99,9 @@ static struct flash_driver *flash_drivers[] = {
&mini51_flash,
&nuc1x_flash,
&nrf51_flash,
&mrvlqspi_flash,
&psoc4_flash,
&sim3x_flash,
NULL,
};

View File

@@ -10,7 +10,10 @@
* *
* Copyright (C) 2013 by Roman Dmitrienko *
* me@iamroman.org *
*
* *
* Copyright (C) 2014 Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp *
* *
* 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 *
@@ -43,6 +46,9 @@
#define EFM_FAMILY_ID_TINY_GECKO 73
#define EFM_FAMILY_ID_LEOPARD_GECKO 74
#define EFM_FAMILY_ID_WONDER_GECKO 75
#define EFM_FAMILY_ID_ZERO_GECKO 76
#define EZR_FAMILY_ID_WONDER_GECKO 120
#define EZR_FAMILY_ID_LEOPARD_GECKO 121
#define EFM32_FLASH_ERASE_TMO 100
#define EFM32_FLASH_WDATAREADY_TMO 100
@@ -57,7 +63,7 @@
#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000)
#define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000)
/* PAGE_SIZE is only present in Leopard and Giant Gecko MCUs */
/* PAGE_SIZE is only present in Leopard, Giant and Wonder Gecko MCUs */
#define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7)
#define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8)
#define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa)
@@ -141,9 +147,11 @@ static int efm32x_read_info(struct flash_bank *bank,
if (((cpuid >> 4) & 0xfff) == 0xc23) {
/* Cortex M3 device */
} else if (((cpuid >> 4) & 0xfff) == 0xc24) {
/* Cortex M4 device */
/* Cortex M4 device(WONDER GECKO) */
} else if (((cpuid >> 4) & 0xfff) == 0xc60) {
/* Cortex M0plus device(ZERO GECKO) */
} else {
LOG_ERROR("Target is not CortexM3 or M4");
LOG_ERROR("Target is not Cortex-Mx Device");
return ERROR_FAIL;
}
@@ -170,6 +178,8 @@ static int efm32x_read_info(struct flash_bank *bank,
if (EFM_FAMILY_ID_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family)
efm32_info->page_size = 512;
else if (EFM_FAMILY_ID_ZERO_GECKO == efm32_info->part_family)
efm32_info->page_size = 1024;
else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family ||
EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
if (efm32_info->prod_rev >= 18) {
@@ -194,7 +204,9 @@ static int efm32x_read_info(struct flash_bank *bank,
LOG_ERROR("Invalid page size %u", efm32_info->page_size);
return ERROR_FAIL;
}
} else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family) {
} else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family ||
EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) {
uint8_t pg_size = 0;
ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
&pg_size);
@@ -838,11 +850,16 @@ static int efm32x_probe(struct flash_bank *bank)
LOG_INFO("Tiny Gecko MCU detected");
break;
case EFM_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
LOG_INFO("Leopard Gecko MCU detected");
break;
case EFM_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_WONDER_GECKO:
LOG_INFO("Wonder Gecko MCU detected");
break;
case EFM_FAMILY_ID_ZERO_GECKO:
LOG_INFO("Zero Gecko MCU detected");
break;
default:
LOG_ERROR("Unsupported MCU family %d",
efm32_mcu_info.part_family);
@@ -933,7 +950,15 @@ static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size)
return ret;
}
printed = snprintf(buf, buf_size, "EFM32 ");
switch (info.part_family) {
case EZR_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
printed = snprintf(buf, buf_size, "EZR32 ");
break;
default:
printed = snprintf(buf, buf_size, "EFM32 ");
}
buf += printed;
buf_size -= printed;
@@ -951,11 +976,16 @@ static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size)
printed = snprintf(buf, buf_size, "Tiny Gecko");
break;
case EFM_FAMILY_ID_LEOPARD_GECKO:
case EZR_FAMILY_ID_LEOPARD_GECKO:
printed = snprintf(buf, buf_size, "Leopard Gecko");
break;
case EFM_FAMILY_ID_WONDER_GECKO:
case EZR_FAMILY_ID_WONDER_GECKO:
printed = snprintf(buf, buf_size, "Wonder Gecko");
break;
case EFM_FAMILY_ID_ZERO_GECKO:
printed = snprintf(buf, buf_size, "Zero Gecko");
break;
}
buf += printed;

View File

@@ -240,7 +240,7 @@ static int fm3_erase(struct flash_bank *bank, int first, int last)
/* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */
/* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */
/* R2 keeps Flash Offset address (ofs) */
const uint8_t fm3_flash_erase_sector_code[] = {
static const uint8_t fm3_flash_erase_sector_code[] = {
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0xAA, 0x24, /* MOVS R4, #0xAA */
0x04, 0x80, /* STRH R4, [R0, #0] */
@@ -849,7 +849,7 @@ static int fm3_chip_erase(struct flash_bank *bank)
/* RAMCODE used for fm3 Flash chip erase: */
/* R0 keeps Flash Sequence address 1 (u32FlashSeq1) */
/* R1 keeps Flash Sequence address 2 (u32FlashSeq2) */
const uint8_t fm3_flash_erase_chip_code[] = {
static const uint8_t fm3_flash_erase_chip_code[] = {
/* *(uint16_t*)u32FlashSeq1 = 0xAA; */
0xAA, 0x22, /* MOVS R2, #0xAA */
0x02, 0x80, /* STRH R2, [R0, #0] */

View File

@@ -31,10 +31,12 @@
#include "config.h"
#endif
#include "jtag/interface.h"
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#include <target/cortex_m.h>
/*
* Implementation Notes
@@ -196,6 +198,289 @@ struct kinetis_flash_bank {
} flash_class;
};
#define MDM_REG_STAT 0x00
#define MDM_REG_CTRL 0x04
#define MDM_REG_ID 0xfc
#define MDM_STAT_FMEACK (1<<0)
#define MDM_STAT_FREADY (1<<1)
#define MDM_STAT_SYSSEC (1<<2)
#define MDM_STAT_SYSRES (1<<3)
#define MDM_STAT_FMEEN (1<<5)
#define MDM_STAT_BACKDOOREN (1<<6)
#define MDM_STAT_LPEN (1<<7)
#define MDM_STAT_VLPEN (1<<8)
#define MDM_STAT_LLSMODEXIT (1<<9)
#define MDM_STAT_VLLSXMODEXIT (1<<10)
#define MDM_STAT_CORE_HALTED (1<<16)
#define MDM_STAT_CORE_SLEEPDEEP (1<<17)
#define MDM_STAT_CORESLEEPING (1<<18)
#define MEM_CTRL_FMEIP (1<<0)
#define MEM_CTRL_DBG_DIS (1<<1)
#define MEM_CTRL_DBG_REQ (1<<2)
#define MEM_CTRL_SYS_RES_REQ (1<<3)
#define MEM_CTRL_CORE_HOLD_RES (1<<4)
#define MEM_CTRL_VLLSX_DBG_REQ (1<<5)
#define MEM_CTRL_VLLSX_DBG_ACK (1<<6)
#define MEM_CTRL_VLLSX_STAT_ACK (1<<7)
#define MDM_ACCESS_TIMEOUT 3000 /* iterations */
static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint32_t value)
{
int retval;
LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value);
retval = dap_queue_ap_write(dap, reg, value);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a write request");
return retval;
}
retval = dap_run(dap);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: dap_run failed");
return retval;
}
return ERROR_OK;
}
static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32_t *result)
{
int retval;
retval = dap_queue_ap_read(dap, reg, result);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a read request");
return retval;
}
retval = dap_run(dap);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: dap_run failed");
return retval;
}
LOG_DEBUG("MDM_REG[0x%02x]: %08" PRIX32, reg, *result);
return ERROR_OK;
}
static int kinetis_mdm_poll_register(struct adiv5_dap *dap, unsigned reg, uint32_t mask, uint32_t value)
{
uint32_t val;
int retval;
int timeout = MDM_ACCESS_TIMEOUT;
do {
retval = kinetis_mdm_read_register(dap, reg, &val);
if (retval != ERROR_OK || (val & mask) == value)
return retval;
alive_sleep(1);
} while (timeout--);
LOG_DEBUG("MDM: polling timed out");
return ERROR_FAIL;
}
/*
* This function implements the procedure to mass erase the flash via
* SWD/JTAG on Kinetis K and L series of devices as it is described in
* AN4835 "Production Flash Programming Best Practices for Kinetis K-
* and L-series MCUs" Section 4.2.1
*/
COMMAND_HANDLER(kinetis_mdm_mass_erase)
{
struct target *target = get_current_target(CMD_CTX);
struct cortex_m_common *cortex_m = target_to_cm(target);
struct adiv5_dap *dap = cortex_m->armv7m.arm.dap;
if (!dap) {
LOG_ERROR("Cannot perform mass erase with a high-level adapter");
return ERROR_FAIL;
}
int retval;
const uint8_t original_ap = dap->ap_current;
/*
* ... Power on the processor, or if power has already been
* applied, assert the RESET pin to reset the processor. For
* devices that do not have a RESET pin, write the System
* Reset Request bit in the MDM-AP control register after
* establishing communication...
*/
/* assert SRST */
if (jtag_get_reset_config() & RESET_HAS_SRST)
adapter_assert_reset();
else
LOG_WARNING("Attempting mass erase without hardware reset. This is not reliable; "
"it's recommended you connect SRST and use ``reset_config srst_only''.");
dap_ap_select(dap, 1);
retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, MEM_CTRL_SYS_RES_REQ);
if (retval != ERROR_OK)
return retval;
/*
* ... Read the MDM-AP status register until the Flash Ready bit sets...
*/
retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
MDM_STAT_FREADY | MDM_STAT_SYSRES,
MDM_STAT_FREADY);
if (retval != ERROR_OK) {
LOG_ERROR("MDM : flash ready timeout");
return retval;
}
/*
* ... Write the MDM-AP control register to set the Flash Mass
* Erase in Progress bit. This will start the mass erase
* process...
*/
retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL,
MEM_CTRL_SYS_RES_REQ | MEM_CTRL_FMEIP);
if (retval != ERROR_OK)
return retval;
/* As a sanity check make sure that device started mass erase procedure */
retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
MDM_STAT_FMEACK, MDM_STAT_FMEACK);
if (retval != ERROR_OK)
return retval;
/*
* ... Read the MDM-AP control register until the Flash Mass
* Erase in Progress bit clears...
*/
retval = kinetis_mdm_poll_register(dap, MDM_REG_CTRL,
MEM_CTRL_FMEIP,
0);
if (retval != ERROR_OK)
return retval;
/*
* ... Negate the RESET signal or clear the System Reset Request
* bit in the MDM-AP control register...
*/
retval = kinetis_mdm_write_register(dap, MDM_REG_CTRL, 0);
if (retval != ERROR_OK)
return retval;
if (jtag_get_reset_config() & RESET_HAS_SRST)
adapter_deassert_reset();
dap_ap_select(dap, original_ap);
return ERROR_OK;
}
static const uint32_t kinetis_known_mdm_ids[] = {
0x001C0000, /* Kinetis-K Series */
0x001C0020, /* Kinetis-L/M/V/E Series */
};
/*
* This function implements the procedure to connect to
* SWD/JTAG on Kinetis K and L series of devices as it is described in
* AN4835 "Production Flash Programming Best Practices for Kinetis K-
* and L-series MCUs" Section 4.1.1
*/
COMMAND_HANDLER(kinetis_check_flash_security_status)
{
struct target *target = get_current_target(CMD_CTX);
struct cortex_m_common *cortex_m = target_to_cm(target);
struct adiv5_dap *dap = cortex_m->armv7m.arm.dap;
if (!dap) {
LOG_WARNING("Cannot check flash security status with a high-level adapter");
return ERROR_OK;
}
uint32_t val;
int retval;
const uint8_t origninal_ap = dap->ap_current;
dap_ap_select(dap, 1);
/*
* ... The MDM-AP ID register can be read to verify that the
* connection is working correctly...
*/
retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read ID register");
goto fail;
}
bool found = false;
for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) {
if (val == kinetis_known_mdm_ids[i]) {
found = true;
break;
}
}
if (!found)
LOG_WARNING("MDM: unknown ID %08" PRIX32, val);
/*
* ... Read the MDM-AP status register until the Flash Ready bit sets...
*/
retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
MDM_STAT_FREADY,
MDM_STAT_FREADY);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: flash ready timeout");
goto fail;
}
/*
* ... Read the System Security bit to determine if security is enabled.
* If System Security = 0, then proceed. If System Security = 1, then
* communication with the internals of the processor, including the
* flash, will not be possible without issuing a mass erase command or
* unsecuring the part through other means (backdoor key unlock)...
*/
retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read MDM_REG_STAT");
goto fail;
}
if (val & MDM_STAT_SYSSEC) {
jtag_poll_set_enabled(false);
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
LOG_WARNING("**** ****");
LOG_WARNING("**** Your Kinetis MCU is in secured state, which means that, ****");
LOG_WARNING("**** with exception for very basic communication, JTAG/SWD ****");
LOG_WARNING("**** interface will NOT work. In order to restore its ****");
LOG_WARNING("**** functionality please issue 'kinetis mdm mass_erase' ****");
LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****");
LOG_WARNING("**** ****");
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
} else {
LOG_INFO("MDM: Chip is unsecured. Continuing.");
jtag_poll_set_enabled(true);
}
dap_ap_select(dap, origninal_ap);
return ERROR_OK;
fail:
LOG_ERROR("MDM: Failed to check security status of the MCU. Cannot proceed further");
jtag_poll_set_enabled(false);
return retval;
}
FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
{
struct kinetis_flash_bank *bank_info;
@@ -512,36 +797,26 @@ static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t
return ERROR_OK;
}
static int kinetis_mass_erase(struct flash_bank *bank)
COMMAND_HANDLER(kinetis_securing_test)
{
int result;
uint8_t ftfx_fstat;
struct target *target = get_current_target(CMD_CTX);
struct flash_bank *bank = NULL;
if (bank->target->state != TARGET_HALTED) {
result = get_flash_bank_by_addr(target, 0x00000000, true, &bank);
if (result != ERROR_OK)
return result;
assert(bank != NULL);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* check if whole bank is blank */
LOG_INFO("Execute Erase All Blocks");
/* set command and sector address */
result = kinetis_ftfx_command(bank, FTFx_CMD_MASSERASE, 0,
0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
/* Anyway Result, write FSEC to unsecure forcely */
/* if (result != ERROR_OK)
return result;*/
/* Write to MCU security status unsecure in Flash security byte(for Kinetis-L need) */
LOG_INFO("Write to MCU security status unsecure Anyway!");
uint8_t padding[4] = {0xFE, 0xFF, 0xFF, 0xFF}; /* Write 0xFFFFFFFE */
result = kinetis_ftfx_command(bank, FTFx_CMD_LWORDPROG, (bank->base + 0x0000040C),
padding[3], padding[2], padding[1], padding[0],
0, 0, 0, 0, &ftfx_fstat);
if (result != ERROR_OK)
return ERROR_FLASH_OPERATION_FAILED;
return ERROR_OK;
return kinetis_ftfx_command(bank, FTFx_CMD_SECTERASE, bank->base + 0x00000400,
0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat);
}
static int kinetis_erase(struct flash_bank *bank, int first, int last)
@@ -556,9 +831,6 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
if ((first > bank->num_sectors) || (last > bank->num_sectors))
return ERROR_FLASH_OPERATION_FAILED;
if ((first == 0) && (last == (bank->num_sectors - 1)))
return kinetis_mass_erase(bank);
/*
* FIXME: TODO: use the 'Erase Flash Block' command if the
* requested erase is PFlash or NVM and encompasses the entire
@@ -1150,8 +1422,58 @@ static int kinetis_blank_check(struct flash_bank *bank)
return ERROR_OK;
}
static const struct command_registration kinetis_securtiy_command_handlers[] = {
{
.name = "check_security",
.mode = COMMAND_EXEC,
.help = "",
.usage = "",
.handler = kinetis_check_flash_security_status,
},
{
.name = "mass_erase",
.mode = COMMAND_EXEC,
.help = "",
.usage = "",
.handler = kinetis_mdm_mass_erase,
},
{
.name = "test_securing",
.mode = COMMAND_EXEC,
.help = "",
.usage = "",
.handler = kinetis_securing_test,
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration kinetis_exec_command_handlers[] = {
{
.name = "mdm",
.mode = COMMAND_ANY,
.help = "",
.usage = "",
.chain = kinetis_securtiy_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration kinetis_command_handler[] = {
{
.name = "kinetis",
.mode = COMMAND_ANY,
.help = "kinetis NAND flash controller commands",
.usage = "",
.chain = kinetis_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver kinetis_flash = {
.name = "kinetis",
.commands = kinetis_command_handler,
.flash_bank_command = kinetis_flash_bank_command,
.erase = kinetis_erase,
.protect = kinetis_protect,

View File

@@ -5,6 +5,13 @@
* LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
* didele.deze@gmail.com *
* *
* LPC1100 variant and auto-probing support Copyright (C) 2014 *
* by Cosmin Gorgovan cosmin [at] linux-geek [dot] org *
* *
* LPC800/LPC1500/LPC54100 support Copyright (C) 2013/2014 *
* by Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp *
* *
* 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 *
@@ -33,7 +40,7 @@
/**
* @file
* flash programming support for NXP LPC17xx and LPC2xxx devices.
* flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x and LPC2xxx devices.
*
* @todo Provide a way to update CCLK after declaring the flash bank. The value which is correct after chip reset will
* rarely still work right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
@@ -58,36 +65,223 @@
* lpc1700:
* - 175x
* - 176x (tested with LPC1768)
* - 177x
* - 178x (tested with LPC1788)
*
* lpc4300 (also available as lpc1800 - alias)
* lpc4000: (lpc1700's alias)
* - 407x
* - 408x (tested with LPC4088)
*
* lpc4300: (also available as lpc1800 - alias)
* - 43x2 | 3 | 5 | 7 (tested with LPC4337/LPC4357)
* - 18x2 | 3 | 5 | 7
*
* lpc800:
* - 810 | 1 | 2 (tested with LPC810/LPC812)
* - 810 | 1 | 2 (tested with LPC810/LPC811/LPC812)
* - 822 | 4 (tested with LPC824)
*
* lpc1100:
* - 11xx
* - 11Axx
* - 11Cxx
* - 11Dxx
* - 11Exx
* - 11Uxx (tested with LPC11U34)
* - 131x
* - 134x
*
* lpc1500:
* - 15x7 | 8 | 9 (tested with LPC1549)
*
* lpc54100:
* - 54101 | 2 (tested with LPC54102)
*
* The auto variant auto-detects parts from the following series:
* - 11xx
* - 11Axx
* - 11Cxx
* - 11Dxx
* - 11Exx
* - 11Uxx
* - 131x
* - 134x
* - 175x
* - 176x
* - 177x
* - 178x
* - 407x
* - 408x
* - 81x
* - 82x
*/
/* Part IDs for autodetection */
/* A script which can automatically extract part ids from user manuals is available here:
* https://github.com/lgeek/lpc_part_ids
*/
#define LPC1110_1 0x0A07102B
#define LPC1110_2 0x1A07102B
#define LPC1111_002_1 0x0A16D02B
#define LPC1111_002_2 0x1A16D02B
#define LPC1111_101_1 0x041E502B
#define LPC1111_101_2 0x2516D02B
#define LPC1111_103_1 0x00010013
#define LPC1111_201_1 0x0416502B
#define LPC1111_201_2 0x2516902B
#define LPC1111_203_1 0x00010012
#define LPC1112_101_1 0x042D502B
#define LPC1112_101_2 0x2524D02B
#define LPC1112_102_1 0x0A24902B
#define LPC1112_102_2 0x1A24902B
#define LPC1112_103_1 0x00020023
#define LPC1112_201_1 0x0425502B
#define LPC1112_201_2 0x2524902B
#define LPC1112_203_1 0x00020022
#define LPC1113_201_1 0x0434502B
#define LPC1113_201_2 0x2532902B
#define LPC1113_203_1 0x00030032
#define LPC1113_301_1 0x0434102B
#define LPC1113_301_2 0x2532102B
#define LPC1113_303_1 0x00030030
#define LPC1114_102_1 0x0A40902B
#define LPC1114_102_2 0x1A40902B
#define LPC1114_201_1 0x0444502B
#define LPC1114_201_2 0x2540902B
#define LPC1114_203_1 0x00040042
#define LPC1114_301_1 0x0444102B
#define LPC1114_301_2 0x2540102B
#define LPC1114_303_1 0x00040040
#define LPC1114_323_1 0x00040060
#define LPC1114_333_1 0x00040070
#define LPC1115_303_1 0x00050080
#define LPC11A02_1 0x4D4C802B
#define LPC11A04_1 0x4D80002B
#define LPC11A11_001_1 0x455EC02B
#define LPC11A12_101_1 0x4574802B
#define LPC11A13_201_1 0x458A402B
#define LPC11A14_301_1 0x35A0002B
#define LPC11A14_301_2 0x45A0002B
#define LPC11C12_301_1 0x1421102B
#define LPC11C14_301_1 0x1440102B
#define LPC11C22_301_1 0x1431102B
#define LPC11C24_301_1 0x1430102B
#define LPC11E11_101 0x293E902B
#define LPC11E12_201 0x2954502B
#define LPC11E13_301 0x296A102B
#define LPC11E14_401 0x2980102B
#define LPC11E36_501 0x00009C41
#define LPC11E37_401 0x00007C45
#define LPC11E37_501 0x00007C41
#define LPC11U12_201_1 0x095C802B
#define LPC11U12_201_2 0x295C802B
#define LPC11U13_201_1 0x097A802B
#define LPC11U13_201_2 0x297A802B
#define LPC11U14_201_1 0x0998802B
#define LPC11U14_201_2 0x2998802B
#define LPC11U23_301 0x2972402B
#define LPC11U24_301 0x2988402B
#define LPC11U24_401 0x2980002B
#define LPC11U34_311 0x0003D440
#define LPC11U34_421 0x0001CC40
#define LPC11U35_401 0x0001BC40
#define LPC11U35_501 0x0000BC40
#define LPC11U36_401 0x00019C40
#define LPC11U37_401 0x00017C40
#define LPC11U37H_401 0x00007C44
#define LPC11U37_501 0x00007C40
#define LPC11E66 0x0000DCC1
#define LPC11E67 0x0000BC81
#define LPC11E68 0x00007C01
#define LPC11U66 0x0000DCC8
#define LPC11U67_1 0x0000BC88
#define LPC11U67_2 0x0000BC80
#define LPC11U68_1 0x00007C08
#define LPC11U68_2 0x00007C00
#define LPC1311 0x2C42502B
#define LPC1311_1 0x1816902B
#define LPC1313 0x2C40102B
#define LPC1313_1 0x1830102B
#define LPC1315 0x3A010523
#define LPC1316 0x1A018524
#define LPC1317 0x1A020525
#define LPC1342 0x3D01402B
#define LPC1343 0x3D00002B
#define LPC1345 0x28010541
#define LPC1346 0x08018542
#define LPC1347 0x08020543
#define LPC1751_1 0x25001110
#define LPC1751_2 0x25001118
#define LPC1752 0x25001121
#define LPC1754 0x25011722
#define LPC1756 0x25011723
#define LPC1758 0x25013F37
#define LPC1759 0x25113737
#define LPC1763 0x26012033
#define LPC1764 0x26011922
#define LPC1765 0x26013733
#define LPC1766 0x26013F33
#define LPC1767 0x26012837
#define LPC1768 0x26013F37
#define LPC1769 0x26113F37
#define LPC1774 0x27011132
#define LPC1776 0x27191F43
#define LPC1777 0x27193747
#define LPC1778 0x27193F47
#define LPC1785 0x281D1743
#define LPC1786 0x281D1F43
#define LPC1787 0x281D3747
#define LPC1788 0x281D3F47
#define LPC4072 0x47011121
#define LPC4074 0x47011132
#define LPC4076 0x47191F43
#define LPC4078 0x47193F47
#define LPC4088 0x481D3F47
#define LPC810_021 0x00008100
#define LPC811_001 0x00008110
#define LPC812_101 0x00008120
#define LPC812_101_1 0x00008121
#define LPC812_101_2 0x00008122
#define LPC812_101_3 0x00008123
#define LPC822_101 0x00008221
#define LPC822_101_1 0x00008222
#define LPC824_201 0x00008241
#define LPC824_201_1 0x00008242
#define IAP_CODE_LEN 0x34
typedef enum {
lpc2000_v1,
lpc2000_v2,
lpc1700,
lpc4300,
lpc800,
lpc1100,
lpc1500,
lpc54100,
lpc_auto,
} lpc2000_variant;
struct lpc2000_flash_bank {
lpc2000_variant variant;
uint32_t cclk;
int cmd51_dst_boundary;
int cmd51_can_64b;
int cmd51_can_256b;
int cmd51_can_8192b;
int calc_checksum;
uint32_t cmd51_max_buffer;
int checksum_vector;
uint32_t iap_max_stack;
uint32_t cmd51_src_offset;
uint32_t lpc4300_bank;
bool probed;
};
enum lpc2000_status_codes {
@@ -125,6 +319,10 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
lpc2000_info->cmd51_max_buffer = 4096;
if (lpc2000_info->variant == lpc2000_v1) {
lpc2000_info->cmd51_dst_boundary = 512;
lpc2000_info->checksum_vector = 5;
lpc2000_info->iap_max_stack = 128;
/* variant 1 has different layout for 128kb and 256kb flashes */
if (bank->size == 128 * 1024) {
bank->num_sectors = 16;
@@ -166,6 +364,10 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
exit(-1);
}
} else if (lpc2000_info->variant == lpc2000_v2) {
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->checksum_vector = 5;
lpc2000_info->iap_max_stack = 128;
/* variant 2 has a uniform layout, only number of sectors differs */
switch (bank->size) {
case 4 * 1024:
@@ -228,6 +430,10 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
}
}
} else if (lpc2000_info->variant == lpc1700) {
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 128;
switch (bank->size) {
case 4 * 1024:
lpc2000_info->cmd51_max_buffer = 256;
@@ -266,13 +472,17 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */
/* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx/LPC40xx devices */
bank->sectors[i].size = (i < 16) ? 4 * 1024 : 32 * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
} else if (lpc2000_info->variant == lpc4300) {
lpc2000_info->cmd51_dst_boundary = 512;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 208;
switch (bank->size) {
case 256 * 1024:
bank->num_sectors = 11;
@@ -299,20 +509,108 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
bank->sectors[i].is_protected = 1;
}
} else if (lpc2000_info->variant == lpc800) {
lpc2000_info->cmd51_max_buffer = 1024;
} else if (lpc2000_info->variant == lpc800) {
lpc2000_info->cmd51_dst_boundary = 64;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 208; /* 148byte for LPC81x,208byte for LPC82x. */
lpc2000_info->cmd51_max_buffer = 256; /* smallest MCU in the series, LPC810, has 1 kB of SRAM */
switch (bank->size) {
case 4 * 1024:
lpc2000_info->cmd51_max_buffer = 256;
bank->num_sectors = 4;
break;
case 8 * 1024:
lpc2000_info->cmd51_max_buffer = 512;
bank->num_sectors = 8;
break;
case 16 * 1024:
bank->num_sectors = 16;
break;
case 32 * 1024:
lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */
bank->num_sectors = 32;
break;
default:
LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1);
}
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
/* all sectors are 1kB-sized for LPC8xx devices */
bank->sectors[i].size = 1 * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
} else if (lpc2000_info->variant == lpc1100) {
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 128;
if ((bank->size % (4 * 1024)) != 0) {
LOG_ERROR("BUG: unknown bank->size encountered,\nLPC1100 flash size must be a multiple of 4096");
exit(-1);
}
lpc2000_info->cmd51_max_buffer = 512; /* smallest MCU in the series, LPC1110, has 1 kB of SRAM */
bank->num_sectors = bank->size / 4096;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
/* all sectors are 4kB-sized */
bank->sectors[i].size = 4 * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
} else if (lpc2000_info->variant == lpc1500) {
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 128;
switch (bank->size) {
case 64 * 1024:
bank->num_sectors = 16;
break;
case 128 * 1024:
bank->num_sectors = 32;
break;
case 256 * 1024:
bank->num_sectors = 64;
break;
default:
LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1);
}
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
/* all sectors are 4kB-sized */
bank->sectors[i].size = 4 * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
} else if (lpc2000_info->variant == lpc54100) {
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 128;
switch (bank->size) {
case 256 * 1024:
bank->num_sectors = 8;
break;
case 512 * 1024:
bank->num_sectors = 16;
break;
default:
LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1);
@@ -322,8 +620,8 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
for (int i = 0; i < bank->num_sectors; i++) {
bank->sectors[i].offset = offset;
/* sectors 0-15 are 1kB-sized for LPC8xx devices */
bank->sectors[i].size = 1 * 1024;
/* all sectors are 32kB-sized */
bank->sectors[i].size = 32 * 1024;
offset += bank->sectors[i].size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
@@ -342,7 +640,8 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
* 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
* 0x8 to 0x1f: command parameter table (1+5 words)
* 0x20 to 0x33: command result table (1+4 words)
* 0x34 to 0xb3|0x104: stack (only 128b needed for lpc17xx/2000, 208 for lpc43xx and 148b for lpc8xx)
* 0x34 to 0xb3|0x104: stack
* (128b needed for lpc1xxx/2000/5410x, 208b for lpc43xx/lpc82x and 148b for lpc81x)
*/
static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working_area **iap_working_area)
@@ -350,7 +649,7 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working
struct target *target = bank->target;
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
if (target_alloc_working_area(target, 0x34 + lpc2000_info->iap_max_stack, iap_working_area) != ERROR_OK) {
if (target_alloc_working_area(target, IAP_CODE_LEN + lpc2000_info->iap_max_stack, iap_working_area) != ERROR_OK) {
LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
return ERROR_FLASH_OPERATION_FAILED;
}
@@ -360,8 +659,12 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working
/* write IAP code to working area */
switch (lpc2000_info->variant) {
case lpc800:
case lpc1100:
case lpc1500:
case lpc1700:
case lpc4300:
case lpc54100:
case lpc_auto:
target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12));
target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0));
break;
@@ -376,14 +679,16 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working
}
int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate);
if (retval != ERROR_OK)
if (retval != ERROR_OK) {
LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)",
(*iap_working_area)->address);
target_free_working_area(target, *iap_working_area);
}
return retval;
}
/* call LPC1700/LPC2000 IAP function */
/* call LPC8xx/LPC1xxx/LPC4xxx/LPC5410x/LPC2000 IAP function */
static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_working_area, int code,
uint32_t param_table[5], uint32_t result_table[4])
@@ -392,16 +697,24 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo
struct target *target = bank->target;
struct arm_algorithm arm_algo; /* for LPC2000 */
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
struct armv7m_algorithm armv7m_info; /* for LPC8xx/LPC1xxx/LPC4xxx/LPC5410x */
uint32_t iap_entry_point = 0; /* to make compiler happier */
switch (lpc2000_info->variant) {
case lpc800:
case lpc1100:
case lpc1700:
case lpc_auto:
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
iap_entry_point = 0x1fff1ff1;
break;
case lpc1500:
case lpc54100:
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
iap_entry_point = 0x03000205;
break;
case lpc2000_v1:
case lpc2000_v2:
arm_algo.common_magic = ARM_COMMON_MAGIC;
@@ -448,11 +761,16 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo
switch (lpc2000_info->variant) {
case lpc800:
case lpc1100:
case lpc1500:
case lpc1700:
case lpc4300:
case lpc54100:
case lpc_auto:
/* IAP stack */
init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + lpc2000_info->cmd51_src_offset);
buf_set_u32(reg_params[3].value, 0, 32,
iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack);
/* return address */
init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
@@ -466,7 +784,8 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo
case lpc2000_v2:
/* IAP stack */
init_reg_param(&reg_params[3], "sp_svc", 32, PARAM_OUT);
buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + lpc2000_info->cmd51_src_offset);
buf_set_u32(reg_params[3].value, 0, 32,
iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack);
/* return address */
init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
@@ -562,57 +881,43 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
return ERROR_COMMAND_SYNTAX_ERROR;
struct lpc2000_flash_bank *lpc2000_info = calloc(1, sizeof(*lpc2000_info));
lpc2000_info->probed = false;
bank->driver_priv = lpc2000_info;
if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0) {
lpc2000_info->variant = lpc2000_v1;
lpc2000_info->cmd51_dst_boundary = 512;
lpc2000_info->cmd51_can_256b = 0;
lpc2000_info->cmd51_can_8192b = 1;
lpc2000_info->checksum_vector = 5;
lpc2000_info->iap_max_stack = 128;
} else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0) {
lpc2000_info->variant = lpc2000_v2;
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->cmd51_can_256b = 1;
lpc2000_info->cmd51_can_8192b = 0;
lpc2000_info->checksum_vector = 5;
lpc2000_info->iap_max_stack = 128;
} else if (strcmp(CMD_ARGV[6], "lpc1700") == 0) {
} else if (strcmp(CMD_ARGV[6], "lpc1700") == 0 || strcmp(CMD_ARGV[6], "lpc4000") == 0) {
lpc2000_info->variant = lpc1700;
lpc2000_info->cmd51_dst_boundary = 256;
lpc2000_info->cmd51_can_256b = 1;
lpc2000_info->cmd51_can_8192b = 0;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 128;
} else if (strcmp(CMD_ARGV[6], "lpc1800") == 0 || strcmp(CMD_ARGV[6], "lpc4300") == 0) {
lpc2000_info->variant = lpc4300;
lpc2000_info->cmd51_dst_boundary = 512;
lpc2000_info->cmd51_can_256b = 0;
lpc2000_info->cmd51_can_8192b = 0;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 208;
} else if (strcmp(CMD_ARGV[6], "lpc800") == 0) {
lpc2000_info->variant = lpc800;
lpc2000_info->cmd51_dst_boundary = 64;
lpc2000_info->cmd51_can_64b = 1;
lpc2000_info->cmd51_can_256b = 0;
lpc2000_info->cmd51_can_8192b = 0;
lpc2000_info->checksum_vector = 7;
lpc2000_info->iap_max_stack = 148;
} else if (strcmp(CMD_ARGV[6], "lpc1100") == 0) {
lpc2000_info->variant = lpc1100;
} else if (strcmp(CMD_ARGV[6], "lpc1500") == 0) {
lpc2000_info->variant = lpc1500;
} else if (strcmp(CMD_ARGV[6], "lpc54100") == 0) {
lpc2000_info->variant = lpc54100;
} else if (strcmp(CMD_ARGV[6], "auto") == 0) {
lpc2000_info->variant = lpc_auto;
} else {
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
free(lpc2000_info);
return ERROR_FLASH_BANK_INVALID;
}
/* see lpc2000_iap_working_area_init() for the reason behind the 0x34 value */
lpc2000_info->cmd51_src_offset = 0x34 + lpc2000_info->iap_max_stack;
/* Maximum size required for the IAP stack.
This value only gets used when probing, only for auto, lpc1100 and lpc1700.
We use the maximum size for any part supported by the driver(!) to be safe
in case the auto variant is mistakenly used on a MCU from one of the series
for which we don't support auto-probing. */
lpc2000_info->iap_max_stack = 208;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk);
lpc2000_info->calc_checksum = 0;
lpc2000_build_sector_list(bank);
uint32_t temp_base = 0;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], temp_base);
@@ -797,14 +1102,8 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_
uint32_t thisrun_bytes;
if (bytes_remaining >= lpc2000_info->cmd51_max_buffer)
thisrun_bytes = lpc2000_info->cmd51_max_buffer;
else if (bytes_remaining >= 1024)
thisrun_bytes = 1024;
else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
thisrun_bytes = 512;
else if ((bytes_remaining >= 256) || (!lpc2000_info->cmd51_can_64b))
thisrun_bytes = 256;
else
thisrun_bytes = 64;
thisrun_bytes = lpc2000_info->cmd51_dst_boundary;
/* Prepare sectors */
param_table[0] = first_sector;
@@ -890,9 +1189,296 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_
return retval;
}
static int get_lpc2000_part_id(struct flash_bank *bank, uint32_t *part_id)
{
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
uint32_t param_table[5] = {0};
uint32_t result_table[4];
struct working_area *iap_working_area;
int retval = lpc2000_iap_working_area_init(bank, &iap_working_area);
if (retval != ERROR_OK)
return retval;
/* The status seems to be bogus with the part ID command on some IAP
firmwares, so ignore it. */
lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table);
struct target *target = bank->target;
target_free_working_area(target, iap_working_area);
/* If the result is zero, the command probably didn't work out. */
if (result_table[0] == 0)
return LPC2000_INVALID_COMMAND;
*part_id = result_table[0];
return LPC2000_CMD_SUCCESS;
}
static int lpc2000_auto_probe_flash(struct flash_bank *bank)
{
uint32_t part_id;
int retval;
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
retval = get_lpc2000_part_id(bank, &part_id);
if (retval != LPC2000_CMD_SUCCESS) {
LOG_ERROR("Could not get part ID");
return retval;
}
switch (part_id) {
case LPC1110_1:
case LPC1110_2:
lpc2000_info->variant = lpc1100;
bank->size = 4 * 1024;
break;
case LPC1111_002_1:
case LPC1111_002_2:
case LPC1111_101_1:
case LPC1111_101_2:
case LPC1111_103_1:
case LPC1111_201_1:
case LPC1111_201_2:
case LPC1111_203_1:
case LPC11A11_001_1:
case LPC11E11_101:
case LPC1311:
case LPC1311_1:
lpc2000_info->variant = lpc1100;
bank->size = 8 * 1024;
break;
case LPC1112_101_1:
case LPC1112_101_2:
case LPC1112_102_1:
case LPC1112_102_2:
case LPC1112_103_1:
case LPC1112_201_1:
case LPC1112_201_2:
case LPC1112_203_1:
case LPC11A02_1:
case LPC11C12_301_1:
case LPC11C22_301_1:
case LPC11A12_101_1:
case LPC11E12_201:
case LPC11U12_201_1:
case LPC11U12_201_2:
case LPC1342:
lpc2000_info->variant = lpc1100;
bank->size = 16 * 1024;
break;
case LPC1113_201_1:
case LPC1113_201_2:
case LPC1113_203_1:
case LPC1113_301_1:
case LPC1113_301_2:
case LPC1113_303_1:
case LPC11A13_201_1:
case LPC11E13_301:
case LPC11U13_201_1:
case LPC11U13_201_2:
case LPC11U23_301:
lpc2000_info->variant = lpc1100;
bank->size = 24 * 1024;
break;
case LPC1114_102_1:
case LPC1114_102_2:
case LPC1114_201_1:
case LPC1114_201_2:
case LPC1114_203_1:
case LPC1114_301_1:
case LPC1114_301_2:
case LPC1114_303_1:
case LPC11A04_1:
case LPC11A14_301_1:
case LPC11A14_301_2:
case LPC11C14_301_1:
case LPC11C24_301_1:
case LPC11E14_401:
case LPC11U14_201_1:
case LPC11U14_201_2:
case LPC11U24_301:
case LPC11U24_401:
case LPC1313:
case LPC1313_1:
case LPC1315:
case LPC1343:
case LPC1345:
lpc2000_info->variant = lpc1100;
bank->size = 32 * 1024;
break;
case LPC1751_1:
case LPC1751_2:
lpc2000_info->variant = lpc1700;
bank->size = 32 * 1024;
break;
case LPC11U34_311:
lpc2000_info->variant = lpc1100;
bank->size = 40 * 1024;
break;
case LPC1114_323_1:
case LPC11U34_421:
case LPC1316:
case LPC1346:
lpc2000_info->variant = lpc1100;
bank->size = 48 * 1024;
break;
case LPC1114_333_1:
lpc2000_info->variant = lpc1100;
bank->size = 56 * 1024;
break;
case LPC1115_303_1:
case LPC11U35_401:
case LPC11U35_501:
case LPC11E66:
case LPC11U66:
case LPC1317:
case LPC1347:
lpc2000_info->variant = lpc1100;
bank->size = 64 * 1024;
break;
case LPC1752:
case LPC4072:
lpc2000_info->variant = lpc1700;
bank->size = 64 * 1024;
break;
case LPC11E36_501:
case LPC11U36_401:
lpc2000_info->variant = lpc1100;
bank->size = 96 * 1024;
break;
case LPC11E37_401:
case LPC11E37_501:
case LPC11U37_401:
case LPC11U37H_401:
case LPC11U37_501:
case LPC11E67:
case LPC11E68:
case LPC11U67_1:
case LPC11U67_2:
lpc2000_info->variant = lpc1100;
bank->size = 128 * 1024;
break;
case LPC1754:
case LPC1764:
case LPC1774:
case LPC4074:
lpc2000_info->variant = lpc1700;
bank->size = 128 * 1024;
break;
case LPC11U68_1:
case LPC11U68_2:
lpc2000_info->variant = lpc1100;
bank->size = 256 * 1024;
break;
case LPC1756:
case LPC1763:
case LPC1765:
case LPC1766:
case LPC1776:
case LPC1785:
case LPC1786:
case LPC4076:
lpc2000_info->variant = lpc1700;
bank->size = 256 * 1024;
break;
case LPC1758:
case LPC1759:
case LPC1767:
case LPC1768:
case LPC1769:
case LPC1777:
case LPC1778:
case LPC1787:
case LPC1788:
case LPC4078:
case LPC4088:
lpc2000_info->variant = lpc1700;
bank->size = 512 * 1024;
break;
case LPC810_021:
lpc2000_info->variant = lpc800;
bank->size = 4 * 1024;
break;
case LPC811_001:
lpc2000_info->variant = lpc800;
bank->size = 8 * 1024;
break;
case LPC812_101:
case LPC812_101_1:
case LPC812_101_2:
case LPC812_101_3:
case LPC822_101:
case LPC822_101_1:
lpc2000_info->variant = lpc800;
bank->size = 16 * 1024;
break;
case LPC824_201:
case LPC824_201_1:
lpc2000_info->variant = lpc800;
bank->size = 32 * 1024;
break;
default:
LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id);
exit(-1);
}
return ERROR_OK;
}
static int lpc2000_probe(struct flash_bank *bank)
{
/* we can't probe on an lpc2000 if this is an lpc2xxx, it has the configured flash */
int status;
uint32_t part_id;
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
if (!lpc2000_info->probed) {
if (lpc2000_info->variant == lpc_auto) {
status = lpc2000_auto_probe_flash(bank);
if (status != ERROR_OK)
return status;
} else if (lpc2000_info->variant == lpc1100 || lpc2000_info->variant == lpc1700) {
status = get_lpc2000_part_id(bank, &part_id);
if (status == LPC2000_CMD_SUCCESS)
LOG_INFO("If auto-detection fails for this part, please email "
"openocd-devel@lists.sourceforge.net, citing part id 0x%" PRIx32 ".\n", part_id);
}
lpc2000_build_sector_list(bank);
lpc2000_info->probed = true;
}
return ERROR_OK;
}
@@ -937,23 +1523,15 @@ COMMAND_HANDLER(lpc2000_handle_part_id_command)
return ERROR_TARGET_NOT_HALTED;
}
uint32_t param_table[5] = {0};
uint32_t result_table[4];
struct working_area *iap_working_area;
retval = lpc2000_iap_working_area_init(bank, &iap_working_area);
if (retval != ERROR_OK)
return retval;
int status_code = lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table);
uint32_t part_id;
int status_code = get_lpc2000_part_id(bank, &part_id);
if (status_code != 0x0) {
if (status_code == ERROR_FLASH_OPERATION_FAILED) {
command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
} else
command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code);
} else
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, result_table[0]);
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, part_id);
return retval;
}

View File

@@ -44,6 +44,10 @@
#define SSP_PROBE_TIMEOUT (100)
#define SSP_MAX_TIMEOUT (3000)
/* Size of the stack to alloc in the working area for the execution of
* the ROM spifi_init() function */
#define SPIFI_INIT_STACK_SIZE 512
struct lpcspifi_flash_bank {
int probed;
uint32_t ssp_base;
@@ -151,7 +155,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
uint32_t ssp_base = lpcspifi_info->ssp_base;
struct armv7m_algorithm armv7m_info;
struct working_area *spifi_init_algorithm;
struct reg_param reg_params[1];
struct reg_param reg_params[2];
int retval = ERROR_OK;
LOG_DEBUG("Uninitializing LPC43xx SSP");
@@ -187,13 +191,13 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
LOG_DEBUG("Allocating working area for SPIFI init algorithm");
/* Get memory for spifi initialization algorithm */
retval = target_alloc_working_area(target, sizeof(spifi_init_code),
&spifi_init_algorithm);
retval = target_alloc_working_area(target, sizeof(spifi_init_code)
+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
if (retval != ERROR_OK) {
LOG_ERROR("Insufficient working area to initialize SPIFI "\
"module. You must allocate at least %zdB of working "\
"area in order to use this driver.",
sizeof(spifi_init_code)
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
);
return retval;
@@ -214,6 +218,8 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
}
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */
/* the spifi_init() rom API makes use of the stack */
init_reg_param(&reg_params[1], "sp", 32, PARAM_OUT);
/* For now, the algorithm will set up the SPIFI module
* @ the IRC clock speed. In the future, it could be made
@@ -221,10 +227,13 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
* already configured them in order to speed up memory-
* mapped reads. */
buf_set_u32(reg_params[0].value, 0, 32, 12);
/* valid stack pointer */
buf_set_u32(reg_params[1].value, 0, 32, (spifi_init_algorithm->address +
sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE) & ~7UL);
/* Run the algorithm */
LOG_DEBUG("Running SPIFI init algorithm");
retval = target_run_algorithm(target, 0 , NULL, 1, reg_params,
retval = target_run_algorithm(target, 0 , NULL, 2, reg_params,
spifi_init_algorithm->address,
spifi_init_algorithm->address + sizeof(spifi_init_code) - 2,
1000, &armv7m_info);
@@ -235,6 +244,7 @@ static int lpcspifi_set_hw_mode(struct flash_bank *bank)
target_free_working_area(target, spifi_init_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
return retval;
}
@@ -678,7 +688,8 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08,
0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20,
0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff
0x50, 0x60, 0xff, 0xf7, 0xef, 0xff, 0x30, 0x46,
0x00, 0xbe, 0xff, 0xff
};
if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),

View File

@@ -482,6 +482,11 @@ static int mdr_probe(struct flash_bank *bank)
page_count = mdr_info->page_count;
page_size = bank->size / page_count;
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->num_sectors = page_count;
bank->sectors = malloc(sizeof(struct flash_sector) * page_count);
@@ -516,6 +521,8 @@ static int get_mdr_info(struct flash_bank *bank, char *buf, int buf_size)
struct flash_driver mdr_flash = {
.name = "mdr",
.usage = "flash bank <name> mdr <base> <size> 0 0 <target#> <type> <page_count> <sec_count>\n"
"<type>: 0 for main memory, 1 for info memory",
.flash_bank_command = mdr_flash_bank_command,
.erase = mdr_erase,
.protect = mdr_protect,

View File

@@ -19,7 +19,7 @@
***************************************************************************/
/*
Flash driver for the Nuvoton NuMicro Mini51 series microcontrollers
Flash driver for the Nuvoton NuMicro Mini51 and M051 series microcontrollers
Part |APROM Size |Part ID (at 0x5000_0000)
----------------------------------------------
@@ -32,6 +32,30 @@
MINI54LAN 16 KB 0x00205400
MINI54ZAN 16 KB 0x00205403
MINI54TAN 16 KB 0x00205404
M052LBN 8 KB 0x10005200
M054LBN 16 KB 0x10005400
M058LBN 32 KB 0x10005800
M0516LBN 64 KB 0x10005A00
M052ZBN 8 KB 0x10005203
M054ZBN 16 KB 0x10005403
M058ZBN 32 KB 0x10005803
M0516ZBN 64 KB 0x10005A03
M052LDN 8 KB 0x20005200
M054LDN 16 KB 0x20005400
M058LDN 32 KB 0x20005800
M0516LDN 64 KB 0x20005A00
M052ZDN 8 KB 0x20005203
M054ZDN 16 KB 0x20005403
M058ZDN 32 KB 0x20005803
M0516ZDN 64 KB 0x20005A03
M052LDE 8 KB 0x30005200
M054LDE 16 KB 0x30005400
M058LDE 32 KB 0x30005800
M0516LDE 64 KB 0x30005A00
M052ZDE 8 KB 0x30005203
M054ZDE 16 KB 0x30005403
M058ZDE 32 KB 0x30005803
M0516ZDE 64 KB 0x30005A03
Datasheet & TRM
---------------
@@ -40,31 +64,18 @@
http://www.keil.com/dd/docs/datashts/nuvoton/mini51/da00-mini51_52_54c1.pdf
M051 ISP datasheet pages 190-206:
http://www.nuvoton.com/hq/resource-download.jsp?tp_GUID=DA05-M052-54-58-516
This driver
-----------
* Only erase and write operations have been implemented;
* Both operations only support the APROM, not the LDROM;
* The TRM suggests that after the boot source has been selected, a software reset should be performed by
setting bit SWRST in ISPCON. However, this doesn't seem to have any effect on the MCU I'm using. At the
moment, the ARM core is reset using the IPRSTC1 register, which seems to do the trick.
* chip_erase, erase, read and write operations have been implemented;
* All operations support APROM, LDROM, FLASH DATA and CONFIG;
Flash access limitations
------------------------
APROM can only be modified when the MCU has booted off the LDROM. For write and erase operations, the
microcontroller will probably need to be rebooted. Pseudocode:
* If operation is write or erase, check bit BS (1) in ISPCON (0x5000_C000);
* If BS is 0 (APROM):
* unlock protected registers by writing 0x59, 0x16, 0x88 to RegLockAddr(0x5000_0100);
* set BS to 1 (LDROM);
* reboot by setting bit CPU_RST(1) in IPRSTC1 (0x50000008);
* poll CPU_RST until it is reset (not sure it's necessary);
* <Perform flash operation>
* reboot from APROM using the same procedure but writing 0 to BS
For implementing the read operation, please note that the APROM isn't memory mapped when booted from LDROM.
*/
@@ -82,42 +93,107 @@
#define ISPDAT 0x5000C008
#define ISPCMD 0x5000C00C
#define ISPTRG 0x5000C010
/* Undocumented isp register */
#define ISPUNKNOWN 0x5000C01C
#define PART_ID_MAIN_MASK 0xFFFFFFF8
#define IPRSTC_CPU_RST 0x02
#define ISPCON_ISPFF 0x40
#define ISPCON_LDUEN 0x20
#define ISPCON_CFGUEN 0x10
#define ISPCON_APUEN 0x08
#define ISPCON_BS_LDROM 0x02
#define ISPCON_ISPEN 0x01
#define ISPCON_SWRST 0x80
#define ISPCON_ISPFF 0x40
#define ISPCMD_READ 0x00
#define ISPCMD_PROGRAM 0x21
#define ISPCMD_ERASE 0x22
#define ISPCMD_CHIP_ERASE 0x26
#define ISPTRG_ISPGO 0x01
#define MINI51 0x00205100
#define MINI52 0x00205200
#define MINI54 0x00205400
#define MINI51_APROM_BASE 0x00000000
#define MINI51_DATA_BASE 0x0001F000
#define MINI51_LDROM_BASE 0x00100000
#define MINI51_CONFIG_BASE 0x00300000
#define MINI51_KB 1024
#define MINI51_PAGE_SIZE 512
#define MINI51_TIMEOUT 1000
struct mini51_flash_bank {
bool probed;
#define ENSURE_OK(status) if (status != ERROR_OK) return status
#define MINI51_MAX_FLASH_BANKS 4
struct mini51_flash_bank_type {
uint32_t base;
uint32_t size;
};
enum mini51_boot_source {
APROM = 0,
LDROM = 1
struct mini51_cpu_type {
char *name;
uint32_t ppid;
unsigned n_banks;
struct mini51_flash_bank_type bank[MINI51_MAX_FLASH_BANKS];
};
#define MINI51_BANKS_MINI51(aprom_size) \
.n_banks = 3, \
{ {MINI51_APROM_BASE, (aprom_size)}, {MINI51_LDROM_BASE, 2*1024}, {MINI51_CONFIG_BASE, 512} }
#define MINI51_BANKS_M051(aprom_size) \
.n_banks = 4, \
{ {MINI51_APROM_BASE, (aprom_size)}, {MINI51_DATA_BASE, 4*1024}, {MINI51_LDROM_BASE, 4*1024}, \
{MINI51_CONFIG_BASE, 1024} }
static const struct mini51_cpu_type mini51_cpu[] = {
{ "MINI51LAN", 0x00205100, MINI51_BANKS_MINI51(4*1024) },
{ "MINI51ZAN", 0x00205103, MINI51_BANKS_MINI51(4*1024) },
{ "MINI51TAN", 0x00205104, MINI51_BANKS_MINI51(4*1024) },
{ "MINI52LAN", 0x00205200, MINI51_BANKS_MINI51(8*1024) },
{ "MINI52ZAN", 0x00205203, MINI51_BANKS_MINI51(8*1024) },
{ "MINI52TAN", 0x00205204, MINI51_BANKS_MINI51(8*1024) },
{ "MINI54LAN", 0x00205400, MINI51_BANKS_MINI51(16*1024) },
{ "MINI54ZAN", 0x00205403, MINI51_BANKS_MINI51(16*1024) },
{ "MINI54TAN", 0x00205404, MINI51_BANKS_MINI51(16*1024) },
{ "M052LBN", 0x10005200, MINI51_BANKS_M051(8*1024) },
{ "M054LBN", 0x10005400, MINI51_BANKS_M051(16*1024) },
{ "M058LBN", 0x10005800, MINI51_BANKS_M051(32*1024) },
{ "M0516LBN", 0x10005A00, MINI51_BANKS_M051(64*1024) },
{ "M052ZBN", 0x10005203, MINI51_BANKS_M051(8*1024) },
{ "M054ZBN", 0x10005403, MINI51_BANKS_M051(16*1024) },
{ "M058ZBN", 0x10005803, MINI51_BANKS_M051(32*1024) },
{ "M0516ZBN", 0x10005A03, MINI51_BANKS_M051(64*1024) },
{ "M052LDN", 0x20005200, MINI51_BANKS_M051(8*1024) },
{ "M054LDN", 0x20005400, MINI51_BANKS_M051(16*1024) },
{ "M058LDN", 0x20005800, MINI51_BANKS_M051(32*1024) },
{ "M0516LDN", 0x20005A00, MINI51_BANKS_M051(64*1024) },
{ "M052ZDN", 0x20005203, MINI51_BANKS_M051(8*1024) },
{ "M054ZDN", 0x20005403, MINI51_BANKS_M051(16*1024) },
{ "M058ZDN", 0x20005803, MINI51_BANKS_M051(32*1024) },
{ "M0516ZDN", 0x20005A03, MINI51_BANKS_M051(64*1024) },
{ "M052LDE", 0x30005200, MINI51_BANKS_M051(8*1024) },
{ "M054LDE", 0x30005400, MINI51_BANKS_M051(16*1024) },
{ "M058LDE", 0x30005800, MINI51_BANKS_M051(32*1024) },
{ "M0516LDE", 0x30005A00, MINI51_BANKS_M051(64*1024) },
{ "M052ZDE", 0x30005203, MINI51_BANKS_M051(8*1024) },
{ "M054ZDE", 0x30005403, MINI51_BANKS_M051(16*1024) },
{ "M058ZDE", 0x30005803, MINI51_BANKS_M051(32*1024) },
{ "M0516ZDE", 0x30005A03, MINI51_BANKS_M051(64*1024) },
};
struct mini51_flash_bank {
bool probed;
const struct mini51_cpu_type *cpu;
};
/* Private methods */
static int mini51_unlock_reg(struct flash_bank *bank)
static int mini51_unlock_reg(struct target *target)
{
int status;
struct target *target = bank->target;
status = target_write_u32(target, REGLOCKADDR, 0x59);
if (status != ERROR_OK)
return status;
@@ -131,86 +207,125 @@ static int mini51_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
}
static int mini51_reboot_with_source(struct flash_bank *bank,
enum mini51_boot_source new_source,
enum mini51_boot_source *prev_source)
static int mini51_get_part_id(struct target *target, uint32_t *part_id)
{
uint32_t ispcon;
uint32_t isprtc1;
bool mini51_reboot = false;
int status;
int timeout = MINI51_TIMEOUT;
/* Read current boot source */
struct target *target = bank->target;
status = target_read_u32(target, ISPCON, &ispcon);
if (status != ERROR_OK)
return status;
*prev_source = (ispcon >> 1) & 1;
if ((new_source == APROM) && (*prev_source != APROM)) {
ispcon &= ~ISPCON_BS_LDROM;
mini51_reboot = true;
} else if ((new_source == LDROM) && (*prev_source != LDROM)) {
ispcon |= ISPCON_BS_LDROM;
mini51_reboot = true;
}
if (mini51_reboot) {
mini51_unlock_reg(bank);
status = target_write_u32(target, ISPCON, ispcon);
if (status != ERROR_OK)
return status;
status = target_write_u32(target, IPRSTC1, IPRSTC_CPU_RST);
if (status != ERROR_OK)
return status;
do {
target_read_u32(target, IPRSTC1, &isprtc1);
timeout--;
} while ((isprtc1 & IPRSTC_CPU_RST) && timeout > 0);
if (timeout == 0) {
LOG_WARNING("Mini51 flash driver: timeout attempting to reboot\n");
return ERROR_FLASH_OPERATION_FAILED;
}
}
return ERROR_OK;
int retu = target_read_u32(target, PART_ID_REG, part_id);
LOG_INFO("device id = 0x%08" PRIx32 "", *part_id);
return retu;
}
static int mini51_get_part_id(struct flash_bank *bank, uint32_t *part_id)
{
return target_read_u32(bank->target, PART_ID_REG, part_id);
}
static int mini51_get_flash_size(struct flash_bank *bank, uint32_t *flash_size)
static int mini51_get_cpu_type(struct target *target, const struct mini51_cpu_type** cpu)
{
uint32_t part_id;
int status;
status = mini51_get_part_id(bank, &part_id);
if (status != ERROR_OK)
return status;
status = mini51_get_part_id(target, &part_id);
ENSURE_OK(status);
switch (part_id & PART_ID_MAIN_MASK) {
case MINI51:
*flash_size = 4 * MINI51_KB;
break;
case MINI52:
*flash_size = 8 * MINI51_KB;
break;
case MINI54:
*flash_size = 16 * MINI51_KB;
break;
default:
*flash_size = 0;
break;
for (size_t i = 0; i < sizeof(mini51_cpu)/sizeof(mini51_cpu[0]); i++) {
if (part_id == mini51_cpu[i].ppid) {
*cpu = &mini51_cpu[i];
LOG_INFO("device name = %s", (*cpu)->name);
return ERROR_OK;
}
}
return ERROR_OK;
return ERROR_FLASH_OPERATION_FAILED;
}
static int mini51_get_flash_size(struct flash_bank *bank, const struct mini51_cpu_type *cpu, uint32_t *flash_size)
{
for (size_t i = 0; i < cpu->n_banks; i++) {
if (bank->base == cpu->bank[i].base) {
*flash_size = cpu->bank[i].size;
LOG_INFO("bank base = 0x%08" PRIx32 ", size = 0x%08" PRIx32 "", bank->base, *flash_size);
return ERROR_OK;
}
}
return ERROR_FLASH_OPERATION_FAILED;
}
static int mini51_isp_execute(struct target *target)
{
int status;
uint32_t ispcon;
int timeout;
uint32_t isptrg;
/* start ISP operation */
status = target_write_u32(target, ISPTRG, ISPTRG_ISPGO);
ENSURE_OK(status);
/* Wait for for command to finish executing */
timeout = MINI51_TIMEOUT;
do {
target_read_u32(target, ISPTRG, &isptrg);
timeout--;
} while ((isptrg & ISPTRG_ISPGO) && (timeout > 0));
if (timeout == 0) {
LOG_WARNING("Mini51 flash driver: Timeout executing flash command\n");
return ERROR_FLASH_OPERATION_FAILED;
}
/* Check for errors */
status = target_read_u32(target, ISPCON, &ispcon);
ENSURE_OK(status);
if (ispcon & ISPCON_ISPFF) {
LOG_WARNING("Mini51 flash driver: operation failed\n");
return ERROR_FLASH_OPERATION_FAILED;
}
return status;
}
static int mini51_isp_execute_cmd(struct target *target, uint32_t cmd, uint32_t address, uint32_t data)
{
int status;
status = target_write_u32(target, ISPDAT, data);
ENSURE_OK(status);
status = target_write_u32(target, ISPADR, address);
ENSURE_OK(status);
status = target_write_u32(target, ISPCMD, cmd);
ENSURE_OK(status);
status = mini51_isp_execute(target);
return status;
}
static int mini51_isp_execute_cmd_read(struct target *target, uint32_t cmd, uint32_t address, uint32_t *data)
{
int status;
status = target_write_u32(target, ISPADR, address);
ENSURE_OK(status);
status = target_write_u32(target, ISPCMD, cmd);
ENSURE_OK(status);
status = mini51_isp_execute(target);
ENSURE_OK(status);
status = target_read_u32(target, ISPDAT, data);
ENSURE_OK(status);
return status;
}
static int mini51_isp_enable(struct target *target)
{
int status;
uint32_t ispcon;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
status = mini51_unlock_reg(target);
ENSURE_OK(status);
status = target_read_u32(target, ISPCON, &ispcon);
ENSURE_OK(status);
ispcon |= ISPCON_ISPEN | ISPCON_LDUEN | ISPCON_APUEN | ISPCON_CFGUEN;
status = target_write_u32(target, ISPCON, ispcon);
return status;
}
/* Public (API) methods */
@@ -232,74 +347,45 @@ static int mini51_protect_check(struct flash_bank *bank)
return ERROR_FLASH_OPERATION_FAILED;
}
static int mini51_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
int status;
uint32_t ispdat;
struct target *target = bank->target;
if ((offset & 0x3) || (count & 0x3)) {
LOG_WARNING("Mini51 flash driver: unaligned access not supported\n");
return ERROR_FLASH_OPERATION_FAILED;
}
status = mini51_isp_enable(target);
ENSURE_OK(status);
for (uint32_t i = offset; i < offset + count; i += 4) {
status = mini51_isp_execute_cmd_read(target, ISPCMD_READ, bank->base + i, &ispdat);
memcpy(buffer, &ispdat, sizeof(ispdat));
ENSURE_OK(status);
buffer += sizeof(ispdat);
}
return ERROR_OK;
}
static int mini51_erase(struct flash_bank *bank, int first, int last)
{
int status;
int timeout;
uint32_t ispcon;
uint32_t isptrg;
enum mini51_boot_source new_source;
enum mini51_boot_source prev_source;
struct target *target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* TODO: add support for erasing the LDROM */
new_source = LDROM;
status = mini51_reboot_with_source(bank, new_source, &prev_source);
if (status != ERROR_OK)
return status;
/* Enable ISP */
status = target_read_u32(target, ISPCON, &ispcon);
if (status != ERROR_OK)
return status;
ispcon |= ISPCON_ISPEN;
status = target_write_u32(target, ISPCON, ispcon);
status = mini51_isp_enable(target);
ENSURE_OK(status);
for (int page_start = first; page_start <= last; page_start++) {
/* Set up erase command */
status = target_write_u32(target, ISPADR, page_start*MINI51_PAGE_SIZE);
if (status != ERROR_OK)
return status;
status = target_write_u32(target, ISPCMD, ISPCMD_ERASE);
if (status != ERROR_OK)
return status;
/* Erase the selected page */
status = target_write_u32(target, ISPTRG, ISPTRG_ISPGO);
if (status != ERROR_OK)
return status;
/* Wait for for command to finish executing */
timeout = MINI51_TIMEOUT;
do {
target_read_u32(target, ISPTRG, &isptrg);
timeout--;
} while ((isptrg & ISPTRG_ISPGO) && (timeout > 0));
if (timeout == 0) {
LOG_WARNING("Mini51 flash driver: Timeout erasing flash\n");
return ERROR_FLASH_OPERATION_FAILED;
}
/* Check for errors */
status = target_read_u32(target, ISPCON, &ispcon);
if (status != ERROR_OK)
return status;
if (ispcon & ISPCON_ISPFF) {
LOG_WARNING("Mini51 flash driver: Erase operation failed\n");
return ERROR_FLASH_OPERATION_FAILED;
}
}
/* Reboot from previous source */
if (prev_source != new_source) {
status = mini51_reboot_with_source(bank, prev_source, &new_source);
if (status != ERROR_OK)
return status;
uint32_t address = bank->base + page_start*MINI51_PAGE_SIZE;
status = mini51_isp_execute_cmd(target, ISPCMD_ERASE, address, 0);
ENSURE_OK(status);
}
return ERROR_OK;
@@ -315,81 +401,22 @@ static int mini51_protect(struct flash_bank *bank, int set, int first, int last)
static int mini51_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int status;
int timeout;
uint32_t ispcon;
uint32_t isptrg;
uint32_t ispdat;
enum mini51_boot_source new_source;
enum mini51_boot_source prev_source;
struct target *target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if ((offset & 0x3) || (count & 0x3)) {
LOG_WARNING("Mini51 flash driver: unaligned access not supported\n");
return ERROR_FLASH_OPERATION_FAILED;
}
/* TODO: add support for writing to LDROM */
new_source = LDROM;
status = mini51_reboot_with_source(bank, new_source, &prev_source);
if (status != ERROR_OK)
return status;
/* Enable ISP */
status = target_read_u32(target, ISPCON, &ispcon);
if (status != ERROR_OK)
return status;
ispcon |= ISPCON_ISPEN;
status = target_write_u32(target, ISPCON, ispcon);
status = mini51_isp_enable(target);
ENSURE_OK(status);
for (uint32_t i = offset; i < offset + count; i += 4) {
/* Set up program command */
status = target_write_u32(target, ISPADR, i);
if (status != ERROR_OK)
return status;
status = target_write_u32(target, ISPCMD, ISPCMD_PROGRAM);
if (status != ERROR_OK)
return status;
memcpy(&ispdat, buffer, sizeof(ispdat));
status = mini51_isp_execute_cmd(target, ISPCMD_PROGRAM, bank->base + i, ispdat);
ENSURE_OK(status);
buffer += sizeof(ispdat);
status = target_write_u32(target, ISPDAT, ispdat);
if (status != ERROR_OK)
return status;
/* Write the selected word */
status = target_write_u32(target, ISPTRG, ISPTRG_ISPGO);
if (status != ERROR_OK)
return status;
/* Wait for for command to finish executing */
timeout = MINI51_TIMEOUT;
do {
target_read_u32(target, ISPTRG, &isptrg);
timeout--;
} while ((isptrg & ISPTRG_ISPGO) && (timeout > 0));
if (timeout == 0) {
LOG_WARNING("Mini51 flash driver: Timeout programming flash\n");
return ERROR_FLASH_OPERATION_FAILED;
}
/* Check for errors */
status = target_read_u32(target, ISPCON, &ispcon);
if (status != ERROR_OK)
return status;
if (ispcon & ISPCON_ISPFF) {
LOG_WARNING("Mini51 flash driver: Programming operation failed\n");
return ERROR_FLASH_OPERATION_FAILED;
}
}
if (prev_source != new_source) {
status = mini51_reboot_with_source(bank, prev_source, &new_source);
if (status != ERROR_OK)
return status;
}
return ERROR_OK;
@@ -398,19 +425,26 @@ static int mini51_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t
static int mini51_probe(struct flash_bank *bank)
{
uint32_t flash_size;
int retval;
int status;
int num_pages;
uint32_t offset = 0;
const struct mini51_cpu_type *cpu;
struct target *target = bank->target;
retval = mini51_get_flash_size(bank, &flash_size);
if (retval != ERROR_OK || flash_size == 0) {
status = mini51_get_cpu_type(target, &cpu);
if (status != ERROR_OK) {
LOG_WARNING("Mini51 flash driver: Failed to detect a known part\n");
return ERROR_FLASH_OPERATION_FAILED;
}
status = mini51_get_flash_size(bank, cpu, &flash_size);
if (status != ERROR_OK) {
LOG_WARNING("Mini51 flash driver: Failed to detect flash size\n");
return ERROR_FLASH_OPERATION_FAILED;
}
num_pages = flash_size / MINI51_PAGE_SIZE;
bank->base = MINI51_APROM_BASE;
bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
bank->size = flash_size;
@@ -425,6 +459,7 @@ static int mini51_probe(struct flash_bank *bank)
struct mini51_flash_bank *mini51_info = bank->driver_priv;
mini51_info->probed = true;
mini51_info->cpu = cpu;
return ERROR_OK;
}
@@ -437,13 +472,111 @@ static int mini51_auto_probe(struct flash_bank *bank)
return mini51_probe(bank);
}
COMMAND_HANDLER(mini51_handle_read_isp_command)
{
uint32_t address;
uint32_t ispdat;
int status;
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
struct target *target = get_current_target(CMD_CTX);
status = mini51_isp_enable(target);
ENSURE_OK(status);
status = mini51_isp_execute_cmd_read(target, ISPCMD_READ, address, &ispdat);
ENSURE_OK(status);
LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat);
return ERROR_OK;
}
COMMAND_HANDLER(mini51_handle_write_isp_command)
{
uint32_t address;
uint32_t ispdat;
int status;
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], ispdat);
struct target *target = get_current_target(CMD_CTX);
status = mini51_isp_enable(target);
ENSURE_OK(status);
status = mini51_isp_execute_cmd(target, ISPCMD_PROGRAM, address, ispdat);
ENSURE_OK(status);
LOG_INFO("0x%08" PRIx32 ": 0x%08" PRIx32, address, ispdat);
return ERROR_OK;
}
COMMAND_HANDLER(mini51_handle_chip_erase_command)
{
int status;
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
struct target *target = get_current_target(CMD_CTX);
status = mini51_isp_enable(target);
ENSURE_OK(status);
/* Write one to undocumented flash control register */
status = target_write_u32(target, ISPUNKNOWN, 1);
ENSURE_OK(status);
status = mini51_isp_execute_cmd(target, ISPCMD_CHIP_ERASE, 0, 0);
ENSURE_OK(status);
return ERROR_OK;
}
static const struct command_registration mini51_exec_command_handlers[] = {
{
.name = "read_isp",
.handler = mini51_handle_read_isp_command,
.usage = "address",
.mode = COMMAND_EXEC,
.help = "read flash through ISP.",
},
{
.name = "write_isp",
.handler = mini51_handle_write_isp_command,
.usage = "address value",
.mode = COMMAND_EXEC,
.help = "write flash through ISP.",
},
{
.name = "chip_erase",
.handler = mini51_handle_chip_erase_command,
.mode = COMMAND_EXEC,
.help = "chip erase.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration mini51_command_handlers[] = {
{
.name = "mini51",
.mode = COMMAND_ANY,
.help = "mini51 flash command group",
.usage = "",
.chain = mini51_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver mini51_flash = {
.name = "mini51",
.commands = mini51_command_handlers,
.flash_bank_command = mini51_flash_bank_command,
.erase = mini51_erase,
.protect = mini51_protect,
.write = mini51_write,
.read = default_flash_read,
.read = mini51_read,
.probe = mini51_probe,
.auto_probe = mini51_auto_probe,
.erase_check = default_flash_blank_check,

961
src/flash/nor/mrvlqspi.c Normal file
View File

@@ -0,0 +1,961 @@
/***************************************************************************
* Copyright (C) 2014 by Mahavir Jain <mjain@marvell.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
***************************************************************************/
/*
* This is QSPI flash controller driver for Marvell's Wireless
* Microcontroller platform.
*
* For more information please refer,
* https://origin-www.marvell.com/microcontrollers/wi-fi-microcontroller-platform/
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "spi.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#define QSPI_R_EN (0x0)
#define QSPI_W_EN (0x1)
#define QSPI_SS_DISABLE (0x0)
#define QSPI_SS_ENABLE (0x1)
#define WRITE_DISBALE (0x0)
#define WRITE_ENABLE (0x1)
#define QSPI_TIMEOUT (1000)
#define FIFO_FLUSH_TIMEOUT (1000)
#define BLOCK_ERASE_TIMEOUT (1000)
#define CHIP_ERASE_TIMEOUT (10000)
#define SS_EN (1 << 0)
#define XFER_RDY (1 << 1)
#define RFIFO_EMPTY (1 << 4)
#define WFIFO_EMPTY (1 << 6)
#define WFIFO_FULL (1 << 7)
#define FIFO_FLUSH (1 << 9)
#define RW_EN (1 << 13)
#define XFER_STOP (1 << 14)
#define XFER_START (1 << 15)
#define CONF_MASK (0x7)
#define CONF_OFFSET (10)
#define INS_WRITE_ENABLE 0x06
#define INS_WRITE_DISABLE 0x04
#define INS_READ_STATUS 0x05
#define INS_PAGE_PROGRAM 0x02
#define CNTL 0x0 /* QSPI_BASE + 0x0 */
#define CONF 0x4
#define DOUT 0x8
#define DIN 0xc
#define INSTR 0x10
#define ADDR 0x14
#define RDMODE 0x18
#define HDRCNT 0x1c
#define DINCNT 0x20
struct mrvlqspi_flash_bank {
int probed;
uint32_t reg_base;
uint32_t bank_num;
const struct flash_device *dev;
};
static inline uint32_t mrvlqspi_get_reg(struct flash_bank *bank, uint32_t reg)
{
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
return reg + mrvlqspi_info->reg_base;
}
static inline int mrvlqspi_set_din_cnt(struct flash_bank *bank, uint32_t count)
{
struct target *target = bank->target;
return target_write_u32(target, mrvlqspi_get_reg(bank, DINCNT), count);
}
static inline int mrvlqspi_set_addr(struct flash_bank *bank, uint32_t addr)
{
struct target *target = bank->target;
return target_write_u32(target, mrvlqspi_get_reg(bank, ADDR), addr);
}
static inline int mrvlqspi_set_instr(struct flash_bank *bank, uint32_t instr)
{
struct target *target = bank->target;
return target_write_u32(target, mrvlqspi_get_reg(bank, INSTR), instr);
}
static inline int mrvlqspi_set_hdr_cnt(struct flash_bank *bank, uint32_t hdr_cnt)
{
struct target *target = bank->target;
return target_write_u32(target, mrvlqspi_get_reg(bank, HDRCNT), hdr_cnt);
}
static int mrvlqspi_set_conf(struct flash_bank *bank, uint32_t conf_val)
{
int retval;
uint32_t regval;
struct target *target = bank->target;
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &regval);
if (retval != ERROR_OK)
return retval;
regval &= ~(CONF_MASK << CONF_OFFSET);
regval |= (conf_val << CONF_OFFSET);
return target_write_u32(target,
mrvlqspi_get_reg(bank, CONF), regval);
}
static int mrvlqspi_set_ss_state(struct flash_bank *bank, bool state, int timeout)
{
int retval;
uint32_t regval;
struct target *target = bank->target;
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CNTL), &regval);
if (retval != ERROR_OK)
return retval;
if (state)
regval |= SS_EN;
else
regval &= ~(SS_EN);
retval = target_write_u32(target,
mrvlqspi_get_reg(bank, CNTL), regval);
if (retval != ERROR_OK)
return retval;
/* wait for xfer_ready to set */
for (;;) {
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CNTL), &regval);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%08" PRIx32, regval);
if ((regval & XFER_RDY) == XFER_RDY)
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
return ERROR_OK;
}
static int mrvlqspi_start_transfer(struct flash_bank *bank, bool rw_mode)
{
int retval;
uint32_t regval;
struct target *target = bank->target;
retval = mrvlqspi_set_ss_state(bank, QSPI_SS_ENABLE, QSPI_TIMEOUT);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &regval);
if (retval != ERROR_OK)
return retval;
if (rw_mode)
regval |= RW_EN;
else
regval &= ~(RW_EN);
regval |= XFER_START;
retval = target_write_u32(target,
mrvlqspi_get_reg(bank, CONF), regval);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int mrvlqspi_stop_transfer(struct flash_bank *bank)
{
int retval;
uint32_t regval;
struct target *target = bank->target;
int timeout = QSPI_TIMEOUT;
/* wait for xfer_ready and wfifo_empty to set */
for (;;) {
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CNTL), &regval);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%08" PRIx32, regval);
if ((regval & (XFER_RDY | WFIFO_EMPTY)) ==
(XFER_RDY | WFIFO_EMPTY))
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &regval);
if (retval != ERROR_OK)
return retval;
regval |= XFER_STOP;
retval = target_write_u32(target,
mrvlqspi_get_reg(bank, CONF), regval);
if (retval != ERROR_OK)
return retval;
/* wait for xfer_start to reset */
for (;;) {
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &regval);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%08" PRIx32, regval);
if ((regval & XFER_START) == 0)
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int mrvlqspi_fifo_flush(struct flash_bank *bank, int timeout)
{
int retval;
uint32_t val;
struct target *target = bank->target;
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &val);
if (retval != ERROR_OK)
return retval;
val |= FIFO_FLUSH;
retval = target_write_u32(target,
mrvlqspi_get_reg(bank, CONF), val);
if (retval != ERROR_OK)
return retval;
/* wait for fifo_flush to clear */
for (;;) {
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CONF), &val);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%08" PRIX32, val);
if ((val & FIFO_FLUSH) == 0)
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
return ERROR_OK;
}
static int mrvlqspi_read_byte(struct flash_bank *bank, uint8_t *data)
{
int retval;
uint32_t val;
struct target *target = bank->target;
/* wait for rfifo_empty to reset */
for (;;) {
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, CNTL), &val);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%08" PRIx32, val);
if ((val & RFIFO_EMPTY) == 0)
break;
usleep(10);
}
retval = target_read_u32(target,
mrvlqspi_get_reg(bank, DIN), &val);
if (retval != ERROR_OK)
return retval;
*data = val & 0xFF;
return ERROR_OK;
}
static int mrvlqspi_flash_busy_status(struct flash_bank *bank, int timeout)
{
uint8_t val;
int retval;
/* Flush read/write fifo's */
retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT);
if (retval != ERROR_OK)
return retval;
/* Set instruction/addr count value */
retval = mrvlqspi_set_hdr_cnt(bank, 0x1);
if (retval != ERROR_OK)
return retval;
/* Read flash status register in continuous manner */
retval = mrvlqspi_set_din_cnt(bank, 0x0);
if (retval != ERROR_OK)
return retval;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, INS_READ_STATUS);
if (retval != ERROR_OK)
return retval;
/* Set data and addr pin length */
retval = mrvlqspi_set_conf(bank, 0x0);
if (retval != ERROR_OK)
return retval;
/* Enable read mode transfer */
retval = mrvlqspi_start_transfer(bank, QSPI_R_EN);
if (retval != ERROR_OK)
return retval;
for (;;) {
retval = mrvlqspi_read_byte(bank, &val);
if (retval != ERROR_OK)
return retval;
if (!(val & 0x1))
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
alive_sleep(1);
}
return mrvlqspi_stop_transfer(bank);
}
static int mrvlqspi_set_write_status(struct flash_bank *bank, bool mode)
{
int retval;
uint32_t instr;
/* Flush read/write fifo's */
retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT);
if (retval != ERROR_OK)
return retval;
/* Set instruction/addr count value */
retval = mrvlqspi_set_hdr_cnt(bank, 0x1);
if (retval != ERROR_OK)
return retval;
if (mode)
instr = INS_WRITE_ENABLE;
else
instr = INS_WRITE_DISABLE;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, instr);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_start_transfer(bank, QSPI_W_EN);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_stop_transfer(bank);
if (retval != ERROR_OK)
return retval;
return retval;
}
static int mrvlqspi_read_id(struct flash_bank *bank, uint32_t *id)
{
uint8_t id_buf[3] = {0, 0, 0};
int retval, i;
LOG_DEBUG("Getting ID");
/* Flush read/write fifo's */
retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT);
if (retval != ERROR_OK)
return retval;
/* Set instruction/addr count value */
retval = mrvlqspi_set_hdr_cnt(bank, 0x1);
if (retval != ERROR_OK)
return retval;
/* Set count for number of bytes to read */
retval = mrvlqspi_set_din_cnt(bank, 0x3);
if (retval != ERROR_OK)
return retval;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, SPIFLASH_READ_ID);
if (retval != ERROR_OK)
return retval;
/* Set data and addr pin length */
retval = mrvlqspi_set_conf(bank, 0x0);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_start_transfer(bank, QSPI_R_EN);
if (retval != ERROR_OK)
return retval;
for (i = 0; i < 3; i++) {
retval = mrvlqspi_read_byte(bank, &id_buf[i]);
if (retval != ERROR_OK)
return retval;
}
LOG_DEBUG("ID is 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8,
id_buf[0], id_buf[1], id_buf[2]);
retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT);
if (retval != ERROR_OK)
return retval;
*id = id_buf[2] << 16 | id_buf[1] << 8 | id_buf[0];
return ERROR_OK;
}
static int mrvlqspi_block_erase(struct flash_bank *bank, uint32_t offset)
{
int retval;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
/* Set flash write enable */
retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE);
if (retval != ERROR_OK)
return retval;
/* Set instruction/addr count value */
retval = mrvlqspi_set_hdr_cnt(bank, (0x1 | (0x3 << 4)));
if (retval != ERROR_OK)
return retval;
/* Set read offset address */
retval = mrvlqspi_set_addr(bank, offset);
if (retval != ERROR_OK)
return retval;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, mrvlqspi_info->dev->erase_cmd);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_start_transfer(bank, QSPI_W_EN);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_stop_transfer(bank);
if (retval != ERROR_OK)
return retval;
return mrvlqspi_flash_busy_status(bank, BLOCK_ERASE_TIMEOUT);
}
static int mrvlqspi_bulk_erase(struct flash_bank *bank)
{
int retval;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
/* Set flash write enable */
retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE);
if (retval != ERROR_OK)
return retval;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, mrvlqspi_info->dev->chip_erase_cmd);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_start_transfer(bank, QSPI_W_EN);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_stop_transfer(bank);
if (retval != ERROR_OK)
return retval;
return mrvlqspi_flash_busy_status(bank, CHIP_ERASE_TIMEOUT);
}
static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
int retval = ERROR_OK;
int sector;
LOG_DEBUG("erase from sector %d to sector %d", first, last);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
LOG_ERROR("Flash sector invalid");
return ERROR_FLASH_SECTOR_INVALID;
}
if (!(mrvlqspi_info->probed)) {
LOG_ERROR("Flash bank not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
for (sector = first; sector <= last; sector++) {
if (bank->sectors[sector].is_protected) {
LOG_ERROR("Flash sector %d protected", sector);
return ERROR_FAIL;
}
}
/* If we're erasing the entire chip and the flash supports
* it, use a bulk erase instead of going sector-by-sector. */
if (first == 0 && last == (bank->num_sectors - 1)
&& mrvlqspi_info->dev->chip_erase_cmd !=
mrvlqspi_info->dev->erase_cmd) {
LOG_DEBUG("Chip supports the bulk erase command."\
" Will use bulk erase instead of sector-by-sector erase.");
retval = mrvlqspi_bulk_erase(bank);
if (retval == ERROR_OK) {
return retval;
} else
LOG_WARNING("Bulk flash erase failed."
" Falling back to sector-by-sector erase.");
}
for (sector = first; sector <= last; sector++) {
retval = mrvlqspi_block_erase(bank,
sector * mrvlqspi_info->dev->sectorsize);
if (retval != ERROR_OK)
return retval;
}
return retval;
}
static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
int retval = ERROR_OK;
uint32_t page_size, fifo_size;
struct working_area *fifo;
struct reg_param reg_params[6];
struct armv7m_algorithm armv7m_info;
struct working_area *write_algorithm;
int sector;
LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
offset, count);
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (offset + count > mrvlqspi_info->dev->size_in_bytes) {
LOG_WARNING("Writes past end of flash. Extra data discarded.");
count = mrvlqspi_info->dev->size_in_bytes - offset;
}
/* Check sector protection */
for (sector = 0; sector < bank->num_sectors; sector++) {
/* Start offset in or before this sector? */
/* End offset in or behind this sector? */
if ((offset <
(bank->sectors[sector].offset + bank->sectors[sector].size))
&& ((offset + count - 1) >= bank->sectors[sector].offset)
&& bank->sectors[sector].is_protected) {
LOG_ERROR("Flash sector %d protected", sector);
return ERROR_FAIL;
}
}
page_size = mrvlqspi_info->dev->pagesize;
/* See contrib/loaders/flash/mrvlqspi.S for src */
static const uint8_t mrvlqspi_flash_write_code[] = {
0x4f, 0xf0, 0x00, 0x0a, 0xa2, 0x44, 0x92, 0x45,
0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6b, 0xf8,
0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80,
0x5f, 0xf0, 0x06, 0x08, 0xc5, 0xf8, 0x10, 0x80,
0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x6b, 0xf8,
0x00, 0xf0, 0x7d, 0xf8, 0x5f, 0xf0, 0x31, 0x08,
0xc5, 0xf8, 0x1c, 0x80, 0x90, 0x46, 0xc5, 0xf8,
0x14, 0x80, 0x5f, 0xf0, 0x02, 0x08, 0xc5, 0xf8,
0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0,
0x5a, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1,
0x00, 0x0f, 0x00, 0xf0, 0x8b, 0x80, 0x47, 0x68,
0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8,
0x01, 0x9b, 0x00, 0xf0, 0x30, 0xf8, 0x8f, 0x42,
0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60,
0x01, 0x3b, 0x00, 0x2b, 0x00, 0xf0, 0x05, 0x80,
0x02, 0xf1, 0x01, 0x02, 0x92, 0x45, 0x7f, 0xf4,
0xe4, 0xaf, 0x00, 0xf0, 0x50, 0xf8, 0xa2, 0x44,
0x00, 0xf0, 0x2d, 0xf8, 0x5f, 0xf0, 0x01, 0x08,
0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x00, 0x08,
0xc5, 0xf8, 0x20, 0x80, 0x5f, 0xf0, 0x05, 0x08,
0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x00, 0x09,
0x00, 0xf0, 0x29, 0xf8, 0x00, 0xf0, 0x13, 0xf8,
0x09, 0xf0, 0x01, 0x09, 0xb9, 0xf1, 0x00, 0x0f,
0xf8, 0xd1, 0x00, 0xf0, 0x34, 0xf8, 0x00, 0x2b,
0xa4, 0xd1, 0x00, 0xf0, 0x53, 0xb8, 0xd5, 0xf8,
0x00, 0x80, 0x5f, 0xea, 0x08, 0x68, 0xfa, 0xd4,
0xc5, 0xf8, 0x08, 0x90, 0x70, 0x47, 0xd5, 0xf8,
0x00, 0x80, 0x5f, 0xea, 0xc8, 0x68, 0xfa, 0xd4,
0xd5, 0xf8, 0x0c, 0x90, 0x70, 0x47, 0xd5, 0xf8,
0x04, 0x80, 0x48, 0xf4, 0x00, 0x78, 0xc5, 0xf8,
0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea,
0x88, 0x58, 0xfa, 0xd4, 0x70, 0x47, 0xd5, 0xf8,
0x00, 0x80, 0x48, 0xf0, 0x01, 0x08, 0xc5, 0xf8,
0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea,
0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80,
0x69, 0xf3, 0x4d, 0x38, 0x48, 0xf4, 0x00, 0x48,
0xc5, 0xf8, 0x04, 0x80, 0x70, 0x47, 0xd5, 0xf8,
0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5,
0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x48, 0x68,
0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4,
0x80, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8,
0x04, 0x80, 0x5f, 0xea, 0x08, 0x48, 0xfa, 0xd4,
0xd5, 0xf8, 0x00, 0x80, 0x28, 0xf0, 0x01, 0x08,
0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80,
0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0x70, 0x47,
0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe
};
if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
&write_algorithm) != ERROR_OK) {
LOG_ERROR("Insufficient working area. You must configure"\
" a working area > %zdB in order to write to SPIFI flash.",
sizeof(mrvlqspi_flash_write_code));
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
retval = target_write_buffer(target, write_algorithm->address,
sizeof(mrvlqspi_flash_write_code),
mrvlqspi_flash_write_code);
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
/* FIFO allocation */
fifo_size = target_get_working_area_avail(target);
if (fifo_size == 0) {
/* if we already allocated the writing code but failed to get fifo
* space, free the algorithm */
target_free_working_area(target, write_algorithm);
LOG_ERROR("Insufficient working area. Please allocate at least"\
" %zdB of working area to enable flash writes.",
sizeof(mrvlqspi_flash_write_code) + 1
);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} else if (fifo_size < page_size)
LOG_WARNING("Working area size is limited; flash writes may be"\
" slow. Increase working area size to at least %zdB"\
" to reduce write times.",
(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
);
if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* target address */
init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */
init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* page size */
init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT); /* qspi base address */
buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
buf_set_u32(reg_params[2].value, 0, 32, offset);
buf_set_u32(reg_params[3].value, 0, 32, count);
buf_set_u32(reg_params[4].value, 0, 32, page_size);
buf_set_u32(reg_params[5].value, 0, 32, (uint32_t) mrvlqspi_info->reg_base);
retval = target_run_flash_async_algorithm(target, buffer, count, 1,
0, NULL,
6, reg_params,
fifo->address, fifo->size,
write_algorithm->address, 0,
&armv7m_info
);
if (retval != ERROR_OK)
LOG_ERROR("Error executing flash write algorithm");
target_free_working_area(target, fifo);
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
destroy_reg_param(&reg_params[4]);
destroy_reg_param(&reg_params[5]);
return retval;
}
int mrvlqspi_flash_read(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
int retval;
uint32_t i;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!(mrvlqspi_info->probed)) {
LOG_ERROR("Flash bank not probed");
return ERROR_FLASH_BANK_NOT_PROBED;
}
/* Flush read/write fifo's */
retval = mrvlqspi_fifo_flush(bank, FIFO_FLUSH_TIMEOUT);
if (retval != ERROR_OK)
return retval;
/* Set instruction/addr count value */
retval = mrvlqspi_set_hdr_cnt(bank, (0x1 | (0x3 << 4)));
if (retval != ERROR_OK)
return retval;
/* Set count for number of bytes to read */
retval = mrvlqspi_set_din_cnt(bank, count);
if (retval != ERROR_OK)
return retval;
/* Set read address */
retval = mrvlqspi_set_addr(bank, offset);
if (retval != ERROR_OK)
return retval;
/* Set instruction */
retval = mrvlqspi_set_instr(bank, SPIFLASH_READ);
if (retval != ERROR_OK)
return retval;
/* Set data and addr pin length */
retval = mrvlqspi_set_conf(bank, 0x0);
if (retval != ERROR_OK)
return retval;
retval = mrvlqspi_start_transfer(bank, QSPI_R_EN);
if (retval != ERROR_OK)
return retval;
for (i = 0; i < count; i++) {
retval = mrvlqspi_read_byte(bank, &buffer[i]);
if (retval != ERROR_OK)
return retval;
}
retval = mrvlqspi_set_ss_state(bank, QSPI_SS_DISABLE, QSPI_TIMEOUT);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int mrvlqspi_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
uint32_t id = 0;
int retval;
struct flash_sector *sectors;
/* If we've already probed, we should be fine to skip this time. */
if (mrvlqspi_info->probed)
return ERROR_OK;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
mrvlqspi_info->probed = 0;
mrvlqspi_info->bank_num = bank->bank_number;
/* Read flash JEDEC ID */
retval = mrvlqspi_read_id(bank, &id);
if (retval != ERROR_OK)
return retval;
mrvlqspi_info->dev = NULL;
for (const struct flash_device *p = flash_devices; p->name ; p++)
if (p->device_id == id) {
mrvlqspi_info->dev = p;
break;
}
if (!mrvlqspi_info->dev) {
LOG_ERROR("Unknown flash device ID 0x%08" PRIx32, id);
return ERROR_FAIL;
}
LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32,
mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id);
/* Set correct size value */
bank->size = mrvlqspi_info->dev->size_in_bytes;
/* create and fill sectors array */
bank->num_sectors = mrvlqspi_info->dev->size_in_bytes /
mrvlqspi_info->dev->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset =
sector * mrvlqspi_info->dev->sectorsize;
sectors[sector].size = mrvlqspi_info->dev->sectorsize;
sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0;
}
bank->sectors = sectors;
mrvlqspi_info->probed = 1;
return ERROR_OK;
}
static int mrvlqspi_auto_probe(struct flash_bank *bank)
{
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
if (mrvlqspi_info->probed)
return ERROR_OK;
return mrvlqspi_probe(bank);
}
static int mrvlqspi_flash_erase_check(struct flash_bank *bank)
{
/* Not implemented yet */
return ERROR_OK;
}
static int mrvlqspi_protect_check(struct flash_bank *bank)
{
/* Not implemented yet */
return ERROR_OK;
}
int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
if (!(mrvlqspi_info->probed)) {
snprintf(buf, buf_size,
"\nQSPI flash bank not probed yet\n");
return ERROR_OK;
}
snprintf(buf, buf_size, "\nQSPI flash information:\n"
" Device \'%s\' ID 0x%08" PRIx32 "\n",
mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id);
return ERROR_OK;
}
FLASH_BANK_COMMAND_HANDLER(mrvlqspi_flash_bank_command)
{
struct mrvlqspi_flash_bank *mrvlqspi_info;
if (CMD_ARGC < 7)
return ERROR_COMMAND_SYNTAX_ERROR;
mrvlqspi_info = malloc(sizeof(struct mrvlqspi_flash_bank));
if (mrvlqspi_info == NULL) {
LOG_ERROR("not enough memory");
return ERROR_FAIL;
}
/* Get QSPI controller register map base address */
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], mrvlqspi_info->reg_base);
bank->driver_priv = mrvlqspi_info;
mrvlqspi_info->probed = 0;
return ERROR_OK;
}
struct flash_driver mrvlqspi_flash = {
.name = "mrvlqspi",
.flash_bank_command = mrvlqspi_flash_bank_command,
.erase = mrvlqspi_flash_erase,
.protect = NULL,
.write = mrvlqspi_flash_write,
.read = mrvlqspi_flash_read,
.probe = mrvlqspi_probe,
.auto_probe = mrvlqspi_auto_probe,
.erase_check = mrvlqspi_flash_erase_check,
.protect_check = mrvlqspi_protect_check,
.info = mrvlqspi_get_info,
};

View File

@@ -33,7 +33,7 @@
#define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
/* non-CFI compatible flashes */
static struct non_cfi non_cfi_flashes[] = {
static const struct non_cfi non_cfi_flashes[] = {
{
.mfr = CFI_MFR_SST,
.id = 0xd4,
@@ -472,7 +472,7 @@ void cfi_fixup_non_cfi(struct flash_bank *bank)
{
unsigned int mask;
struct cfi_flash_bank *cfi_info = bank->driver_priv;
struct non_cfi *non_cfi = non_cfi_flashes;
const struct non_cfi *non_cfi = non_cfi_flashes;
if (cfi_info->x16_as_x8)
mask = 0xFF;

View File

@@ -1,6 +1,8 @@
/***************************************************************************
* Copyright (C) 2013 Synapse Product Development *
* Andrey Smirnov <andrew.smironv@gmail.com> *
* Angus Gratton <gus@projectgus.com> *
* Erdem U. Altunyurt <spamjunkeater@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -23,6 +25,9 @@
#endif
#include "imp.h"
#include <target/algorithm.h>
#include <target/armv7m.h>
#include <helper/types.h>
enum {
NRF51_FLASH_BASE = 0x00000000,
@@ -73,7 +78,7 @@ enum nrf51_uicr_registers {
NRF51_UICR_BASE = 0x10001000, /* User Information
* Configuration Regsters */
NRF51_UICR_SIZE = 252,
NRF51_UICR_SIZE = 0x100,
#define NRF51_UICR_REG(offset) (NRF51_UICR_BASE + offset)
@@ -123,63 +128,26 @@ struct nrf51_device_spec {
unsigned int flash_size_kb;
};
/* The known devices table below is derived from the "nRF51 Series
* Compatibility Matrix" document, which can be found by searching for
* ATTN-51 on the Nordic Semi website:
*
* http://www.nordicsemi.com/eng/content/search?SearchText=ATTN-51
*
* Up to date with Matrix v2.0, plus some additional HWIDs.
*
* The additional HWIDs apply where the build code in the matrix is
* shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is
* for x==0, x!=0 means different (unspecified) HWIDs.
*/
static const struct nrf51_device_spec nrf51_known_devices_table[] = {
/* nRF51822 Devices (IC rev 1). */
{
.hwid = 0x001D,
.variant = "QFAA",
.build_code = "CA/C0",
.flash_size_kb = 256,
},
{
.hwid = 0x002A,
.variant = "QFAA",
.build_code = "FA",
.flash_size_kb = 256,
},
{
.hwid = 0x0044,
.variant = "QFAA",
.build_code = "GC",
.flash_size_kb = 256,
},
{
.hwid = 0x003C,
.variant = "QFAA",
.build_code = "G0",
.flash_size_kb = 256,
},
{
.hwid = 0x0020,
.variant = "CEAA",
.build_code = "BA",
.flash_size_kb = 256,
},
{
.hwid = 0x002F,
.variant = "CEAA",
.build_code = "B0",
.flash_size_kb = 256,
},
{
.hwid = 0x0040,
.variant = "CEAA",
.build_code = "CA",
.flash_size_kb = 256,
},
{
.hwid = 0x0047,
.variant = "CEAA",
.build_code = "DA",
.flash_size_kb = 256,
},
{
.hwid = 0x004D,
.variant = "CEAA",
.build_code = "D0",
.flash_size_kb = 256,
},
{
.hwid = 0x0026,
.variant = "QFAB",
@@ -192,13 +160,200 @@ static const struct nrf51_device_spec nrf51_known_devices_table[] = {
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x0020,
.variant = "CEAA",
.build_code = "BA",
.flash_size_kb = 256,
},
{
.hwid = 0x002F,
.variant = "CEAA",
.build_code = "B0",
.flash_size_kb = 256,
},
/* nRF51822 Devices (IC rev 2). */
{
.hwid = 0x002A,
.variant = "QFAA",
.build_code = "FA0",
.flash_size_kb = 256,
},
{
.hwid = 0x0044,
.variant = "QFAA",
.build_code = "GC0",
.flash_size_kb = 256,
},
{
.hwid = 0x003C,
.variant = "QFAA",
.build_code = "G0",
.flash_size_kb = 256,
},
{
.hwid = 0x004C,
.variant = "QFAB",
.build_code = "B0",
.flash_size_kb = 128,
},
{
.hwid = 0x0040,
.variant = "CEAA",
.build_code = "CA0",
.flash_size_kb = 256,
},
{
.hwid = 0x0047,
.variant = "CEAA",
.build_code = "DA0",
.flash_size_kb = 256,
},
{
.hwid = 0x004D,
.variant = "CEAA",
.build_code = "D00",
.flash_size_kb = 256,
},
/* nRF51822 Devices (IC rev 3). */
{
.hwid = 0x0072,
.variant = "QFAA",
.build_code = "H0",
.flash_size_kb = 256,
},
{
.hwid = 0x007B,
.variant = "QFAB",
.build_code = "C0",
.flash_size_kb = 128,
},
{
.hwid = 0x0083,
.variant = "QFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
{
.hwid = 0x007D,
.variant = "CDAB",
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x0079,
.variant = "CEAA",
.build_code = "E0",
.flash_size_kb = 256,
},
{
.hwid = 0x0087,
.variant = "CFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
/* nRF51422 Devices (IC rev 1). */
{
.hwid = 0x001E,
.variant = "QFAA",
.build_code = "CA",
.flash_size_kb = 256,
},
{
.hwid = 0x0024,
.variant = "QFAA",
.build_code = "C0",
.flash_size_kb = 256,
},
{
.hwid = 0x0031,
.variant = "CEAA",
.build_code = "A0A",
.flash_size_kb = 256,
},
/* nRF51422 Devices (IC rev 2). */
{
.hwid = 0x002D,
.variant = "QFAA",
.build_code = "DAA",
.flash_size_kb = 256,
},
{
.hwid = 0x002E,
.variant = "QFAA",
.build_code = "E0",
.flash_size_kb = 256,
},
{
.hwid = 0x0061,
.variant = "QFAB",
.build_code = "A00",
.flash_size_kb = 128,
},
{
.hwid = 0x0050,
.variant = "CEAA",
.build_code = "B0",
.flash_size_kb = 256,
},
/* nRF51422 Devices (IC rev 3). */
{
.hwid = 0x0073,
.variant = "QFAA",
.build_code = "F0",
.flash_size_kb = 256,
},
{
.hwid = 0x007C,
.variant = "QFAB",
.build_code = "B0",
.flash_size_kb = 128,
},
{
.hwid = 0x0085,
.variant = "QFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
{
.hwid = 0x0086,
.variant = "QFAC",
.build_code = "A1",
.flash_size_kb = 256,
},
{
.hwid = 0x007E,
.variant = "CDAB",
.build_code = "A0",
.flash_size_kb = 128,
},
{
.hwid = 0x007A,
.variant = "CEAA",
.build_code = "C0",
.flash_size_kb = 256,
},
{
.hwid = 0x0088,
.variant = "CFAC",
.build_code = "A0",
.flash_size_kb = 256,
},
/* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards
with built-in jlink seem to use engineering samples not listed
in the nRF51 Series Compatibility Matrix V1.0. */
{
.hwid = 0x0071,
.variant = "QFAC",
.build_code = "AB",
.flash_size_kb = 256,
},
};
static int nrf51_bank_is_probed(struct flash_bank *bank)
@@ -248,6 +403,7 @@ static int nrf51_wait_for_nvmc(struct nrf51_info *chip)
alive_sleep(1);
} while (timeout--);
LOG_DEBUG("Timed out waiting for NVMC_READY");
return ERROR_FLASH_BUSY;
}
@@ -557,19 +713,25 @@ static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank
static int nrf51_erase_all(struct nrf51_info *chip)
{
LOG_DEBUG("Erasing all non-volatile memory");
return nrf51_nvmc_generic_erase(chip,
NRF51_NVMC_ERASEALL,
0x00000001);
}
static int nrf51_erase_page(struct nrf51_info *chip, struct flash_sector *sector)
static int nrf51_erase_page(struct flash_bank *bank,
struct nrf51_info *chip,
struct flash_sector *sector)
{
int res;
if (sector->is_protected)
LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
if (sector->is_protected) {
LOG_ERROR("Cannot erase protected sector at 0x%" PRIx32, sector->offset);
return ERROR_FAIL;
}
if (sector->offset == NRF51_UICR_BASE) {
if (bank->base == NRF51_UICR_BASE) {
uint32_t ppfc;
res = target_read_u32(chip->target, NRF51_FICR_PPFC,
&ppfc);
@@ -579,6 +741,12 @@ static int nrf51_erase_page(struct nrf51_info *chip, struct flash_sector *sector
}
if ((ppfc & 0xFF) == 0xFF) {
/* We can't erase the UICR. Double-check to
see if it's already erased before complaining. */
default_flash_blank_check(bank);
if (sector->is_erased == 1)
return ERROR_OK;
LOG_ERROR("The chip was not pre-programmed with SoftDevice stack and UICR cannot be erased separately. Please issue mass erase before trying to write to this region");
return ERROR_FAIL;
};
@@ -600,55 +768,162 @@ static int nrf51_erase_page(struct nrf51_info *chip, struct flash_sector *sector
return res;
}
static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t buffer_size)
static const uint8_t nrf51_flash_write_code[] = {
/* See contrib/loaders/flash/cortex-m0.S */
/* <wait_fifo>: */
0x0d, 0x68, /* ldr r5, [r1, #0] */
0x00, 0x2d, /* cmp r5, #0 */
0x0b, 0xd0, /* beq.n 1e <exit> */
0x4c, 0x68, /* ldr r4, [r1, #4] */
0xac, 0x42, /* cmp r4, r5 */
0xf9, 0xd0, /* beq.n 0 <wait_fifo> */
0x20, 0xcc, /* ldmia r4!, {r5} */
0x20, 0xc3, /* stmia r3!, {r5} */
0x94, 0x42, /* cmp r4, r2 */
0x01, 0xd3, /* bcc.n 18 <no_wrap> */
0x0c, 0x46, /* mov r4, r1 */
0x08, 0x34, /* adds r4, #8 */
/* <no_wrap>: */
0x4c, 0x60, /* str r4, [r1, #4] */
0x04, 0x38, /* subs r0, #4 */
0xf0, 0xd1, /* bne.n 0 <wait_fifo> */
/* <exit>: */
0x00, 0xbe /* bkpt 0x0000 */
};
/* Start a low level flash write for the specified region */
static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
{
int res;
assert(buffer_size % 4 == 0);
struct target *target = chip->target;
uint32_t buffer_size = 8192;
struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = NRF51_FLASH_BASE + offset;
struct reg_param reg_params[4];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
for (; buffer_size > 0; buffer_size -= 4) {
res = target_write_memory(chip->target, offset, 4, 1, buffer);
if (res != ERROR_OK)
return res;
res = nrf51_wait_for_nvmc(chip);
if (res != ERROR_OK)
return res;
LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
assert(bytes % 4 == 0);
offset += 4;
buffer += 4;
/* allocate working area with flash programming code */
if (target_alloc_working_area(target, sizeof(nrf51_flash_write_code),
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, falling back to slow memory writes");
for (; bytes > 0; bytes -= 4) {
retval = target_write_memory(chip->target, offset, 4, 1, buffer);
if (retval != ERROR_OK)
return retval;
retval = nrf51_wait_for_nvmc(chip);
if (retval != ERROR_OK)
return retval;
offset += 4;
buffer += 4;
}
return ERROR_OK;
}
return ERROR_OK;
LOG_WARNING("using fast async flash loader. This is currently supported");
LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg to disable it");
retval = target_write_buffer(target, write_algorithm->address,
sizeof(nrf51_flash_write_code),
nrf51_flash_write_code);
if (retval != ERROR_OK)
return retval;
/* memory buffer */
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
buffer_size /= 2;
buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
if (buffer_size <= 256) {
/* free working area, write algorithm already allocated */
target_free_working_area(target, write_algorithm);
LOG_WARNING("No large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
}
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* buffer start */
init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* buffer end */
init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT); /* target address */
buf_set_u32(reg_params[0].value, 0, 32, bytes);
buf_set_u32(reg_params[1].value, 0, 32, source->address);
buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[3].value, 0, 32, address);
retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
0, NULL,
4, reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
destroy_reg_param(&reg_params[3]);
return retval;
}
static int nrf51_write_page(struct flash_bank *bank, uint32_t offset, const uint8_t *buffer)
/* Check and erase flash sectors in specified range then start a low level page write.
start/end must be sector aligned.
*/
static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer)
{
assert(offset % 4 == 0);
int res = ERROR_FAIL;
struct nrf51_info *chip = bank->driver_priv;
struct flash_sector *sector = nrf51_find_sector_by_address(bank, offset);
struct flash_sector *sector;
uint32_t offset;
if (!sector)
return ERROR_FLASH_SECTOR_INVALID;
assert(start % chip->code_page_size == 0);
assert(end % chip->code_page_size == 0);
if (sector->is_protected)
goto error;
/* Erase all sectors */
for (offset = start; offset < end; offset += chip->code_page_size) {
sector = nrf51_find_sector_by_address(bank, offset);
if (!sector) {
LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset);
return ERROR_FLASH_SECTOR_INVALID;
}
if (!sector->is_erased) {
res = nrf51_erase_page(chip, sector);
if (res != ERROR_OK) {
LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
if (sector->is_protected) {
LOG_ERROR("Can't erase protected sector @ 0x%08"PRIx32, offset);
goto error;
}
if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */
res = nrf51_erase_page(bank, chip, sector);
if (res != ERROR_OK) {
LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset);
goto error;
}
}
sector->is_erased = 0;
}
res = nrf51_nvmc_write_enable(chip);
if (res != ERROR_OK)
goto error;
sector->is_erased = 0;
res = nrf51_ll_flash_write(chip, offset, buffer, chip->code_page_size);
res = nrf51_ll_flash_write(chip, start, buffer, (end - start));
if (res != ERROR_OK)
goto set_read_only;
@@ -657,7 +932,7 @@ static int nrf51_write_page(struct flash_bank *bank, uint32_t offset, const uint
set_read_only:
nrf51_nvmc_read_only(chip);
error:
LOG_ERROR("Failed to write sector @ 0x%08"PRIx32, sector->offset);
LOG_ERROR("Failed to write to nrf51 flash");
return res;
}
@@ -672,7 +947,7 @@ static int nrf51_erase(struct flash_bank *bank, int first, int last)
/* For each sector to be erased */
for (int s = first; s <= last && res == ERROR_OK; s++)
res = nrf51_erase_page(chip, &bank->sectors[s]);
res = nrf51_erase_page(bank, chip, &bank->sectors[s]);
return res;
}
@@ -681,79 +956,51 @@ static int nrf51_code_flash_write(struct flash_bank *bank,
struct nrf51_info *chip,
const uint8_t *buffer, uint32_t offset, uint32_t count)
{
int res;
struct {
uint32_t start, end;
} region;
/* Need to perform reads to fill any gaps we need to preserve in the first page,
before the start of buffer, or in the last page, after the end of buffer */
uint32_t first_page = offset/chip->code_page_size;
uint32_t last_page = DIV_ROUND_UP(offset+count, chip->code_page_size);
region.start = offset;
region.end = offset + count;
uint32_t first_page_offset = first_page * chip->code_page_size;
uint32_t last_page_offset = last_page * chip->code_page_size;
struct {
size_t length;
const uint8_t *buffer;
} start_extra, end_extra;
LOG_DEBUG("Padding write from 0x%08"PRIx32"-0x%08"PRIx32" as 0x%08"PRIx32"-0x%08"PRIx32,
offset, offset+count, first_page_offset, last_page_offset);
start_extra.length = region.start % chip->code_page_size;
start_extra.buffer = buffer;
end_extra.length = region.end % chip->code_page_size;
end_extra.buffer = buffer + count - end_extra.length;
if (start_extra.length) {
uint8_t page[chip->code_page_size];
uint32_t page_cnt = last_page - first_page;
uint8_t buffer_to_flash[page_cnt*chip->code_page_size];
/* Fill in any space between start of first page and start of buffer */
uint32_t pre = offset - first_page_offset;
if (pre > 0) {
res = target_read_memory(bank->target,
region.start - start_extra.length,
1, start_extra.length, page);
if (res != ERROR_OK)
return res;
memcpy(page + start_extra.length,
start_extra.buffer,
chip->code_page_size - start_extra.length);
res = nrf51_write_page(bank,
region.start - start_extra.length,
page);
first_page_offset,
1,
pre,
buffer_to_flash);
if (res != ERROR_OK)
return res;
}
if (end_extra.length) {
uint8_t page[chip->code_page_size];
/* Fill in main contents of buffer */
memcpy(buffer_to_flash+pre, buffer, count);
/* Fill in any space between end of buffer and end of last page */
uint32_t post = last_page_offset - (offset+count);
if (post > 0) {
/* Retrieve the full row contents from Flash */
res = target_read_memory(bank->target,
region.end,
1,
(chip->code_page_size - end_extra.length),
page + end_extra.length);
if (res != ERROR_OK)
return res;
memcpy(page, end_extra.buffer, end_extra.length);
res = nrf51_write_page(bank,
region.end - end_extra.length,
page);
offset + count,
1,
post,
buffer_to_flash+pre+count);
if (res != ERROR_OK)
return res;
}
region.start += start_extra.length;
region.end -= end_extra.length;
for (uint32_t address = region.start; address < region.end;
address += chip->code_page_size) {
res = nrf51_write_page(bank, address, &buffer[address - region.start]);
if (res != ERROR_OK)
return res;
}
return ERROR_OK;
return nrf51_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash);
}
static int nrf51_uicr_flash_write(struct flash_bank *bank,
@@ -776,8 +1023,8 @@ static int nrf51_uicr_flash_write(struct flash_bank *bank,
if (res != ERROR_OK)
return res;
if (!sector->is_erased) {
res = nrf51_erase_page(chip, sector);
if (sector->is_erased != 1) {
res = nrf51_erase_page(bank, chip, sector);
if (res != ERROR_OK)
return res;
}
@@ -920,8 +1167,9 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size)
if (res != ERROR_OK)
return res;
struct {
uint32_t address, value;
static struct {
const uint32_t address;
uint32_t value;
} ficr[] = {
{ .address = NRF51_FICR_CODEPAGESIZE },
{ .address = NRF51_FICR_CODESIZE },

View File

@@ -328,7 +328,7 @@ static int nuc1x_erase(struct flash_bank *bank, int first, int last)
return retval;
for (i = first; i <= last; i++) {
LOG_DEBUG("erasing sector %d at addresss 0x%" PRIx32 "", i, bank->base + bank->sectors[i].offset);
LOG_DEBUG("erasing sector %d at address 0x%" PRIx32 "", i, bank->base + bank->sectors[i].offset);
retval = target_write_u32(target, NUC1X_FLASH_ISPADR, bank->base + bank->sectors[i].offset);
if (retval != ERROR_OK)
return retval;
@@ -389,7 +389,7 @@ static int nuc1x_write(struct flash_bank *bank, const uint8_t *buffer,
return ERROR_TARGET_NOT_HALTED;
}
LOG_INFO("Novoton NUC: FLASH Write ...");
LOG_INFO("Nuvoton NUC: FLASH Write ...");
int retval = nuc1x_reset2lprom(bank);
if (retval != ERROR_OK)
@@ -452,7 +452,7 @@ static int nuc1x_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
return retval;
} else {
LOG_DEBUG("writed OK");
LOG_DEBUG("Write OK");
}
}
@@ -520,7 +520,7 @@ static int nuc1x_probe(struct flash_bank *bank)
nuc1x_info->probed = 1;
LOG_DEBUG("Novoton NUC: Probed ...");
LOG_DEBUG("Nuvoton NUC: Probed ...");
return ERROR_OK;
}
@@ -574,7 +574,7 @@ static int nuc1x_mass_erase(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
LOG_INFO("Novoton NUC: Chip Erase ... (may take several seconds)");
LOG_INFO("Nuvoton NUC: Chip Erase ... (may take several seconds)");
return retval;
}

809
src/flash/nor/psoc4.c Normal file
View File

@@ -0,0 +1,809 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2011 by Andreas Fritiofson *
* andreas.fritiofson@gmail.com *
* *
* Copyright (C) 2014 by Tomas Vanek (PSoC 4 support derived from STM32) *
* vanekt@fbl.cz *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (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. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <jtag/jtag.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
/* device documets:
PSoC(R) 4: PSoC 4200 Family Datasheet
Document Number: 001-87197 Rev. *B Revised August 29, 2013
PSoC 4100/4200 Family PSoC(R) 4 Architecture TRM
Document No. 001-85634 Rev. *C March 25, 2014
PSoC(R) 4 Registers TRM Spec.
Document No. 001-85847 Rev. *A June 25, 2013
CY8C41xx, CY8C42xx Programming Specifications
Document No. 001-81799 Rev. *C March 4, 2014
*/
/* register locations */
#define PSOC4_CPUSS_SYSREQ 0x40000004
#define PSOC4_CPUSS_SYSARG 0x40000008
#define PSOC4_TEST_MODE 0x40030014
#define PSOC4_SPCIF_GEOMETRY 0x400E0000
#define PSOC4_SFLASH_MACRO 0x0ffff000
/* constants */
#define PSOC4_SROM_KEY1 0xb6
#define PSOC4_SROM_KEY2 0xd3
#define PSOC4_SROM_SYSREQ_BIT (1<<31)
#define PSOC4_SROM_HMASTER_BIT (1<<30)
#define PSOC4_SROM_PRIVILEGED_BIT (1<<28)
#define PSOC4_SROM_STATUS_SUCCEEDED 0xa0000000
#define PSOC4_SROM_STATUS_FAILED 0xf0000000
#define PSOC4_CMD_GET_SILICON_ID 0
#define PSOC4_CMD_LOAD_LATCH 4
#define PSOC4_CMD_WRITE_ROW 5
#define PSOC4_CMD_PROGRAM_ROW 6
#define PSOC4_CMD_ERASE_ALL 0xa
#define PSOC4_CMD_CHECKSUM 0xb
#define PSOC4_CMD_WRITE_PROTECTION 0xd
#define PSOC4_CHIP_PROT_VIRGIN 0x0
#define PSOC4_CHIP_PROT_OPEN 0x1
#define PSOC4_CHIP_PROT_PROTECTED 0x2
#define PSOC4_CHIP_PROT_KILL 0x4
struct psoc4_chip_details {
uint16_t id;
const char *type;
const char *package;
uint32_t flash_size_in_kb;
};
/* list of PSoC 4 chips
* flash_size_in_kb is not necessary as it can be decoded from SPCIF_GEOMETRY
*/
const struct psoc4_chip_details psoc4_devices[] = {
/* 4200 series */
{ 0x04A6, "CY8C4245PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x04B6, "CY8C4245LQI-483", "QFN-40", .flash_size_in_kb = 32 },
{ 0x04C8, "CY8C4245AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x04FB, "CY8C4245AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x04F0, "CY8C4244PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x04F1, "CY8C4244PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x04F6, "CY8C4244LQI-443", "QFN-40", .flash_size_in_kb = 16 },
{ 0x04FA, "CY8C4244AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
/* 4100 series */
{ 0x0410, "CY8C4124PVI-432", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x0411, "CY8C4124PVI-442", "SSOP-28", .flash_size_in_kb = 16 },
{ 0x0416, "CY8C4124LQI-443", "QFN-40", .flash_size_in_kb = 16 },
{ 0x041A, "CY8C4124AXI-443", "TQFP-44", .flash_size_in_kb = 16 },
{ 0x041B, "CY8C4125AXI-473", "TQFP-44", .flash_size_in_kb = 32 },
{ 0x0412, "CY8C4125PVI-482", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x0417, "CY8C4125LQI-483", "QFN-40", .flash_size_in_kb = 32 },
{ 0x041C, "CY8C4125AXI-483", "TQFP-44", .flash_size_in_kb = 32 },
/* CCG1 series */
{ 0x0490, "CYPD1103-35FNXI", "CSP-35", .flash_size_in_kb = 32 },
{ 0x0489, "CYPD1121-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
{ 0x048A, "CYPD1122-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
{ 0x0491, "CYPD1131-35FNXI", "CSP-35", .flash_size_in_kb = 32 },
{ 0x0498, "CYPD1132-16SXI", "SOIC-16", .flash_size_in_kb = 32 },
{ 0x0481, "CYPD1134-28PVXI", "SSOP-28", .flash_size_in_kb = 32 },
{ 0x048B, "CYPD1134-40LQXI", "QFN-40", .flash_size_in_kb = 32 },
};
struct psoc4_flash_bank {
uint32_t row_size;
uint32_t user_bank_size;
int probed;
uint32_t silicon_id;
uint8_t chip_protection;
uint8_t cmd_program_row;
};
static const struct psoc4_chip_details *psoc4_details_by_id(uint32_t silicon_id)
{
const struct psoc4_chip_details *p = psoc4_devices;
unsigned int i;
uint16_t id = silicon_id >> 16; /* ignore die revision */
for (i = 0; i < sizeof(psoc4_devices)/sizeof(psoc4_devices[0]); i++, p++) {
if (p->id == id)
return p;
}
LOG_DEBUG("Unknown PSoC 4 device silicon id 0x%08" PRIx32 ".", silicon_id);
return NULL;
}
static const char *psoc4_decode_chip_protection(uint8_t protection)
{
switch (protection) {
case PSOC4_CHIP_PROT_VIRGIN:
return "protection VIRGIN";
case PSOC4_CHIP_PROT_OPEN:
return "protection open";
case PSOC4_CHIP_PROT_PROTECTED:
return "PROTECTED";
case PSOC4_CHIP_PROT_KILL:
return "protection KILL";
default:
LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection);
return "";
}
}
/* flash bank <name> psoc <base> <size> 0 0 <target#>
*/
FLASH_BANK_COMMAND_HANDLER(psoc4_flash_bank_command)
{
struct psoc4_flash_bank *psoc4_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
psoc4_info = calloc(1, sizeof(struct psoc4_flash_bank));
bank->driver_priv = psoc4_info;
psoc4_info->user_bank_size = bank->size;
return ERROR_OK;
}
/* PSoC 4 system ROM request
* Setting SROM_SYSREQ_BIT in CPUSS_SYSREQ register runs NMI service
* in sysrem ROM. Algorithm just waits for NMI to finish.
* When sysreq_params_size == 0 only one parameter is passed in CPUSS_SYSARG register.
* Otherwise address of memory parameter block is set in CPUSS_SYSARG
* and the first parameter is written to the first word of parameter block
*/
static int psoc4_sysreq(struct target *target, uint8_t cmd, uint16_t cmd_param,
uint32_t *sysreq_params, uint32_t sysreq_params_size)
{
struct working_area *sysreq_wait_algorithm;
struct working_area *sysreq_mem;
struct reg_param reg_params[1];
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
uint32_t param1 = PSOC4_SROM_KEY1
| ((PSOC4_SROM_KEY2 + cmd) << 8)
| (cmd_param << 16);
static uint8_t psoc4_sysreq_wait_code[] = {
/* system request NMI is served immediately after algo run
now we are done: break */
0x00, 0xbe, /* bkpt 0 */
};
const int code_words = (sizeof(psoc4_sysreq_wait_code) + 3) / 4;
/* stack must be aligned */
const int stack_size = 196;
/* tested stack sizes on PSoC 4:
ERASE_ALL 144
PROGRAM_ROW 112
other sysreq 68
*/
/* allocate area for sysreq wait code and stack */
if (target_alloc_working_area(target, code_words * 4 + stack_size,
&sysreq_wait_algorithm) != ERROR_OK) {
LOG_DEBUG("no working area for sysreq code");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
/* Write the code */
retval = target_write_buffer(target,
sysreq_wait_algorithm->address,
sizeof(psoc4_sysreq_wait_code),
psoc4_sysreq_wait_code);
if (retval != ERROR_OK) {
/* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
goto cleanup_algo;
}
if (sysreq_params_size) {
/* Allocate memory for sysreq_params */
retval = target_alloc_working_area(target, sysreq_params_size, &sysreq_mem);
if (retval != ERROR_OK) {
LOG_WARNING("no working area for sysreq parameters");
/* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
goto cleanup_algo;
}
/* Write sysreq_params */
sysreq_params[0] = param1;
retval = target_write_buffer(target, sysreq_mem->address,
sysreq_params_size, (uint8_t *)sysreq_params);
if (retval != ERROR_OK)
goto cleanup_mem;
/* Set address of sysreq parameters block */
retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, sysreq_mem->address);
if (retval != ERROR_OK)
goto cleanup_mem;
} else {
/* Sysreq without memory block of parameters */
/* Set register parameter */
retval = target_write_u32(target, PSOC4_CPUSS_SYSARG, param1);
if (retval != ERROR_OK)
goto cleanup_mem;
}
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD;
/* sysreq stack */
init_reg_param(&reg_params[0], "sp", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32,
sysreq_wait_algorithm->address + sysreq_wait_algorithm->size);
struct armv7m_common *armv7m = target_to_armv7m(target);
if (armv7m == NULL) {
/* something is very wrong if armv7m is NULL */
LOG_ERROR("unable to get armv7m target");
goto cleanup;
}
/* Set SROM request */
retval = target_write_u32(target, PSOC4_CPUSS_SYSREQ,
PSOC4_SROM_SYSREQ_BIT | PSOC4_SROM_HMASTER_BIT | cmd);
if (retval != ERROR_OK)
goto cleanup;
/* Execute wait code */
retval = target_run_algorithm(target, 0, NULL,
sizeof(reg_params) / sizeof(*reg_params), reg_params,
sysreq_wait_algorithm->address, 0, 1000, &armv7m_info);
if (retval != ERROR_OK)
LOG_ERROR("sysreq wait code execution failed");
cleanup:
destroy_reg_param(&reg_params[0]);
cleanup_mem:
if (sysreq_params_size)
target_free_working_area(target, sysreq_mem);
cleanup_algo:
target_free_working_area(target, sysreq_wait_algorithm);
return retval;
}
/* helper routine to get silicon ID from a PSoC 4 chip */
static int psoc4_get_silicon_id(struct target *target, uint32_t *silicon_id, uint8_t *protection)
{
uint32_t params = PSOC4_SROM_KEY1
| ((PSOC4_SROM_KEY2 + PSOC4_CMD_GET_SILICON_ID) << 8);
uint32_t part0, part1;
int retval = psoc4_sysreq(target, PSOC4_CMD_GET_SILICON_ID, 0, NULL, 0);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, PSOC4_CPUSS_SYSARG, &part0);
if (retval != ERROR_OK)
return retval;
if (part0 == params) {
LOG_ERROR("sysreq silicon id request not served");
return ERROR_FAIL;
}
retval = target_read_u32(target, PSOC4_CPUSS_SYSREQ, &part1);
if (retval != ERROR_OK)
return retval;
uint32_t silicon = ((part0 & 0xffff) << 16)
| (((part0 >> 16) & 0xff) << 8)
| (part1 & 0xff);
uint8_t prot = (part1 >> 12) & 0xff;
if (silicon_id)
*silicon_id = silicon;
if (protection)
*protection = prot;
LOG_DEBUG("silicon id: 0x%08" PRIx32 "", silicon);
LOG_DEBUG("protection: 0x%02" PRIx8 "", prot);
return retval;
}
static int psoc4_protect_check(struct flash_bank *bank)
{
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
uint32_t prot_addr = PSOC4_SFLASH_MACRO;
uint32_t protection;
int i, s;
int num_bits;
int retval = ERROR_OK;
num_bits = bank->num_sectors;
for (i = 0; i < num_bits; i += 32) {
retval = target_read_u32(target, prot_addr, &protection);
if (retval != ERROR_OK)
return retval;
prot_addr += 4;
for (s = 0; s < 32; s++) {
if (i + s >= num_bits)
break;
bank->sectors[i + s].is_protected = (protection & (1 << s)) ? 1 : 0;
}
}
retval = psoc4_get_silicon_id(target, NULL, &(psoc4_info->chip_protection));
return retval;
}
static int psoc4_mass_erase(struct flash_bank *bank)
{
struct target *target = bank->target;
int i;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Call "Erase All" system ROM API */
uint32_t param;
int retval = psoc4_sysreq(target, PSOC4_CMD_ERASE_ALL,
0,
&param, sizeof(param));
if (retval == ERROR_OK)
/* set all sectors as erased */
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
return retval;
}
static int psoc4_erase(struct flash_bank *bank, int first, int last)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
if (psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW) {
LOG_INFO("Autoerase enabled, erase command ignored");
return ERROR_OK;
}
if ((first == 0) && (last == (bank->num_sectors - 1)))
return psoc4_mass_erase(bank);
LOG_ERROR("Only mass erase available");
return ERROR_FAIL;
}
static int psoc4_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
if (psoc4_info->probed == 0)
return ERROR_FAIL;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
uint32_t *sysrq_buffer = NULL;
int retval;
int num_bits = bank->num_sectors;
const int param_sz = 8;
int prot_sz = num_bits / 8;
int chip_prot = PSOC4_CHIP_PROT_OPEN;
int flash_macro = 0; /* PSoC 42xx has only macro 0 */
int i;
sysrq_buffer = calloc(1, param_sz + prot_sz);
if (sysrq_buffer == NULL) {
LOG_ERROR("no memory for row buffer");
return ERROR_FAIL;
}
for (i = first; i < num_bits && i <= last; i++)
bank->sectors[i].is_protected = set;
uint32_t *p = sysrq_buffer + 2;
for (i = 0; i < num_bits; i++) {
if (bank->sectors[i].is_protected)
p[i / 32] |= 1 << (i % 32);
}
/* Call "Load Latch" system ROM API */
sysrq_buffer[1] = prot_sz - 1;
retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
0, /* Byte number in latch from what to write */
sysrq_buffer, param_sz + psoc4_info->row_size);
if (retval != ERROR_OK)
goto cleanup;
/* Call "Write Protection" system ROM API */
retval = psoc4_sysreq(target, PSOC4_CMD_WRITE_PROTECTION,
chip_prot | (flash_macro << 8), NULL, 0);
cleanup:
if (retval != ERROR_OK)
psoc4_protect_check(bank);
if (sysrq_buffer)
free(sysrq_buffer);
return retval;
}
COMMAND_HANDLER(psoc4_handle_flash_autoerase_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
bool enable = psoc4_info->cmd_program_row == PSOC4_CMD_WRITE_ROW;
if (CMD_ARGC >= 2)
COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable);
if (enable) {
psoc4_info->cmd_program_row = PSOC4_CMD_WRITE_ROW;
LOG_INFO("Flash auto-erase enabled, non mass erase commands will be ignored.");
} else {
psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
LOG_INFO("Flash auto-erase disabled. Use psoc mass_erase before flash programming.");
}
return retval;
}
static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t *sysrq_buffer = NULL;
int retval = ERROR_OK;
const int param_sz = 8;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (offset & 0x1) {
LOG_ERROR("offset 0x%08" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
sysrq_buffer = malloc(param_sz + psoc4_info->row_size);
if (sysrq_buffer == NULL) {
LOG_ERROR("no memory for row buffer");
return ERROR_FAIL;
}
uint8_t *row_buffer = (uint8_t *)sysrq_buffer + param_sz;
uint32_t row_num = offset / psoc4_info->row_size;
uint32_t row_offset = offset - row_num * psoc4_info->row_size;
if (row_offset)
memset(row_buffer, 0, row_offset);
bool save_poll = jtag_poll_get_enabled();
jtag_poll_set_enabled(false);
while (count) {
uint32_t chunk_size = psoc4_info->row_size - row_offset;
if (chunk_size > count) {
chunk_size = count;
memset(row_buffer + chunk_size, 0, psoc4_info->row_size - chunk_size);
}
memcpy(row_buffer + row_offset, buffer, chunk_size);
LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "",
offset, row_offset, chunk_size);
/* Call "Load Latch" system ROM API */
sysrq_buffer[1] = psoc4_info->row_size - 1;
retval = psoc4_sysreq(target, PSOC4_CMD_LOAD_LATCH,
0, /* Byte number in latch from what to write */
sysrq_buffer, param_sz + psoc4_info->row_size);
if (retval != ERROR_OK)
goto cleanup;
/* Call "Program Row" or "Write Row" system ROM API */
uint32_t sysrq_param;
retval = psoc4_sysreq(target, psoc4_info->cmd_program_row,
row_num & 0xffff,
&sysrq_param, sizeof(sysrq_param));
if (retval != ERROR_OK)
goto cleanup;
buffer += chunk_size;
row_num++;
row_offset = 0;
count -= chunk_size;
}
cleanup:
jtag_poll_set_enabled(save_poll);
if (sysrq_buffer)
free(sysrq_buffer);
return retval;
}
static int psoc4_probe(struct flash_bank *bank)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t flash_size_in_kb = 0;
uint32_t max_flash_size_in_kb;
uint32_t cpu_id;
uint32_t silicon_id;
uint32_t row_size;
uint32_t base_address = 0x00000000;
uint8_t protection;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
psoc4_info->probed = 0;
psoc4_info->cmd_program_row = PSOC4_CMD_PROGRAM_ROW;
/* Get the CPUID from the ARM Core
* http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */
int retval = target_read_u32(target, 0xE000ED00, &cpu_id);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("cpu id = 0x%08" PRIx32 "", cpu_id);
/* set page size, protection granularity and max flash size depending on family */
switch ((cpu_id >> 4) & 0xFFF) {
case 0xc20: /* M0 -> PSoC4 */
row_size = 128;
max_flash_size_in_kb = 32;
break;
default:
LOG_WARNING("Cannot identify target as a PSoC 4 family.");
return ERROR_FAIL;
}
uint32_t spcif_geometry;
retval = target_read_u32(target, PSOC4_SPCIF_GEOMETRY, &spcif_geometry);
if (retval == ERROR_OK) {
row_size = 128 * ((spcif_geometry >> 22) & 3);
flash_size_in_kb = (spcif_geometry & 0xffff) * 256 / 1024;
LOG_INFO("SPCIF geometry: %" PRIu32 " kb flash, row %" PRIu32 " bytes.",
flash_size_in_kb, row_size);
}
/* Early revisions of ST-Link v2 have some problem reading PSOC4_SPCIF_GEOMETRY
and an error is reported late. Dummy read gets this error. */
uint32_t dummy;
target_read_u32(target, PSOC4_CPUSS_SYSREQ, &dummy);
/* get silicon ID from target. */
retval = psoc4_get_silicon_id(target, &silicon_id, &protection);
if (retval != ERROR_OK)
return retval;
const struct psoc4_chip_details *details = psoc4_details_by_id(silicon_id);
if (details) {
LOG_INFO("%s device detected.", details->type);
if (flash_size_in_kb == 0)
flash_size_in_kb = details->flash_size_in_kb;
else if (flash_size_in_kb != details->flash_size_in_kb)
LOG_ERROR("Flash size mismatch");
}
psoc4_info->row_size = row_size;
psoc4_info->silicon_id = silicon_id;
psoc4_info->chip_protection = protection;
/* failed reading flash size or flash size invalid (early silicon),
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
LOG_WARNING("PSoC 4 flash size failed, probe inaccurate - assuming %" PRIu32 " k flash",
max_flash_size_in_kb);
flash_size_in_kb = max_flash_size_in_kb;
}
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have a invalid flash size register value */
if (psoc4_info->user_bank_size) {
LOG_INFO("ignoring flash probed value, using configured bank size");
flash_size_in_kb = psoc4_info->user_bank_size / 1024;
}
LOG_INFO("flash size = %" PRIu32 " kbytes", flash_size_in_kb);
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
/* calculate numbers of pages */
uint32_t num_rows = flash_size_in_kb * 1024 / row_size;
/* check that calculation result makes sense */
assert(num_rows > 0);
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = base_address;
bank->size = num_rows * row_size;
bank->num_sectors = num_rows;
bank->sectors = malloc(sizeof(struct flash_sector) * num_rows);
uint32_t i;
for (i = 0; i < num_rows; i++) {
bank->sectors[i].offset = i * row_size;
bank->sectors[i].size = row_size;
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
LOG_INFO("flash bank set %" PRIu32 " rows", num_rows);
psoc4_info->probed = 1;
return ERROR_OK;
}
static int psoc4_auto_probe(struct flash_bank *bank)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
if (psoc4_info->probed)
return ERROR_OK;
return psoc4_probe(bank);
}
static int get_psoc4_info(struct flash_bank *bank, char *buf, int buf_size)
{
struct psoc4_flash_bank *psoc4_info = bank->driver_priv;
int printed = 0;
if (psoc4_info->probed == 0)
return ERROR_FAIL;
const struct psoc4_chip_details *details = psoc4_details_by_id(psoc4_info->silicon_id);
if (details) {
uint32_t chip_revision = psoc4_info->silicon_id & 0xffff;
printed = snprintf(buf, buf_size, "PSoC 4 %s rev 0x%04" PRIx32 " package %s",
details->type, chip_revision, details->package);
} else
printed = snprintf(buf, buf_size, "PSoC 4 silicon id 0x%08" PRIx32 "",
psoc4_info->silicon_id);
buf += printed;
buf_size -= printed;
const char *prot_txt = psoc4_decode_chip_protection(psoc4_info->chip_protection);
uint32_t size_in_kb = bank->size / 1024;
snprintf(buf, buf_size, " flash %" PRIu32 " kb %s", size_in_kb, prot_txt);
return ERROR_OK;
}
COMMAND_HANDLER(psoc4_handle_mass_erase_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
retval = psoc4_mass_erase(bank);
if (retval == ERROR_OK)
command_print(CMD_CTX, "psoc mass erase complete");
else
command_print(CMD_CTX, "psoc mass erase failed");
return retval;
}
static const struct command_registration psoc4_exec_command_handlers[] = {
{
.name = "mass_erase",
.handler = psoc4_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Erase entire flash device.",
},
{
.name = "flash_autoerase",
.handler = psoc4_handle_flash_autoerase_command,
.mode = COMMAND_EXEC,
.usage = "bank_id on|off",
.help = "Set autoerase mode for flash bank.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration psoc4_command_handlers[] = {
{
.name = "psoc4",
.mode = COMMAND_ANY,
.help = "PSoC 4 flash command group",
.usage = "",
.chain = psoc4_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver psoc4_flash = {
.name = "psoc4",
.commands = psoc4_command_handlers,
.flash_bank_command = psoc4_flash_bank_command,
.erase = psoc4_erase,
.protect = psoc4_protect,
.write = psoc4_write,
.read = default_flash_read,
.probe = psoc4_probe,
.auto_probe = psoc4_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = psoc4_protect_check,
.info = get_psoc4_info,
};

1136
src/flash/nor/sim3x.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -49,8 +49,11 @@ const struct flash_device flash_devices[] = {
FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000),
FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000),
FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000),
FLASH_ID("sp s25fl116k", 0xd8, 0xC7, 0x00154001, 0x100, 0x10000, 0x200000),
FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000),
FLASH_ID("sp s25fl132k", 0xd8, 0xC7, 0x00164001, 0x100, 0x10000, 0x400000),
FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000),
FLASH_ID("sp s25fl164k", 0xd8, 0xC7, 0x00174001, 0x100, 0x10000, 0x800000),
FLASH_ID("sp s25fl128", 0xd8, 0xC7, 0x00182001, 0x100, 0x10000, 0x1000000),
FLASH_ID("sp s25fl256", 0xd8, 0xC7, 0x00190201, 0x100, 0x10000, 0x2000000),
FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
@@ -68,7 +71,9 @@ const struct flash_device flash_devices[] = {
FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000),
FLASH_ID("mcr n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000),
FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000),
FLASH_ID(NULL, 0, 0, 0, 0, 0, 0)
};

View File

@@ -69,6 +69,8 @@
#define FLASH_CRIS (FLASH_CONTROL_BASE | 0x00C)
#define FLASH_CIM (FLASH_CONTROL_BASE | 0x010)
#define FLASH_MISC (FLASH_CONTROL_BASE | 0x014)
#define FLASH_FSIZE (FLASH_CONTROL_BASE | 0xFC0)
#define FLASH_SSIZE (FLASH_CONTROL_BASE | 0xFC4)
#define AMISC 1
#define PMISC 2
@@ -98,19 +100,16 @@ struct stellaris_flash_bank {
uint32_t did1;
uint32_t dc0;
uint32_t dc1;
uint32_t fsize;
uint32_t ssize;
const char *target_name;
uint8_t target_class;
uint32_t sramsiz;
uint32_t flshsz;
/* flash geometry */
uint32_t num_pages;
uint32_t pagesize;
uint32_t pages_in_lockregion;
/* nv memory bits */
uint16_t num_lockbits;
/* main clock status */
uint32_t rcc;
@@ -361,70 +360,96 @@ static const struct {
{0x06, 0x7D, "LM3S9U90"},
{0x06, 0x90, "LM3S9U92"},
{0x06, 0x9B, "LM3S9U96"},
{0x05, 0x18, "LM4F110B2QR"},
{0x05, 0x19, "LM4F110C4QR"},
{0x05, 0x10, "LM4F110E5QR"},
{0x05, 0x11, "LM4F110H5QR"},
{0x05, 0x22, "LM4F111B2QR"},
{0x05, 0x23, "LM4F111C4QR"},
{0x05, 0x20, "LM4F111E5QR"},
{0x05, 0x21, "LM4F111H5QR"},
{0x05, 0x36, "LM4F112C4QC"},
{0x05, 0x30, "LM4F112E5QC"},
{0x05, 0x31, "LM4F112H5QC"},
{0x05, 0x35, "LM4F112H5QD"},
{0x05, 0x01, "LM4F120B2QR"},
{0x05, 0x02, "LM4F120C4QR"},
{0x05, 0x03, "LM4F120E5QR"},
{0x05, 0x04, "LM4F120H5QR"},
{0x05, 0x08, "LM4F121B2QR"},
{0x05, 0x09, "LM4F121C4QR"},
{0x05, 0x0A, "LM4F121E5QR"},
{0x05, 0x0B, "LM4F121H5QR"},
{0x05, 0xD0, "LM4F122C4QC"},
{0x05, 0xD1, "LM4F122E5QC"},
{0x05, 0xD2, "LM4F122H5QC"},
{0x05, 0xD6, "LM4F122H5QD"},
{0x05, 0x48, "LM4F130C4QR"},
{0x05, 0x40, "LM4F130E5QR"},
{0x05, 0x41, "LM4F130H5QR"},
{0x05, 0x52, "LM4F131C4QR"},
{0x05, 0x50, "LM4F131E5QR"},
{0x05, 0x51, "LM4F131H5QR"},
{0x05, 0x66, "LM4F132C4QC"},
{0x05, 0x60, "LM4F132E5QC"},
{0x05, 0x61, "LM4F132H5QC"},
{0x05, 0x65, "LM4F132H5QD"},
{0x05, 0x70, "LM4F210E5QR"},
{0x05, 0x73, "LM4F210H5QR"},
{0x05, 0x80, "LM4F211E5QR"},
{0x05, 0x83, "LM4F211H5QR"},
{0x05, 0xE9, "LM4F212H5BB"},
{0x05, 0xC4, "LM4F212H5QC"},
{0x05, 0xC6, "LM4F212H5QD"},
{0x05, 0xA0, "LM4F230E5QR"},
{0x05, 0xA1, "LM4F230H5QR"},
{0x05, 0xB0, "LM4F231E5QR"},
{0x05, 0xB1, "LM4F231H5QR"},
{0x05, 0xC0, "LM4F232E5QC"},
{0x05, 0xE3, "LM4F232H5BB"},
{0x05, 0xC1, "LM4F232H5QC"},
{0x05, 0xC5, "LM4F232H5QD"},
{0x05, 0xE5, "LM4FS1AH5BB"},
{0x05, 0xEA, "LM4FS1GH5BB"},
{0x05, 0xE4, "LM4FS99H5BB"},
{0x05, 0x01, "LM4F120B2QR/TM4C1233C3PM"},
{0x05, 0x02, "LM4F120C4QR/TM4C1233D5PM"},
{0x05, 0x03, "LM4F120E5QR/TM4C1233E6PM"},
{0x05, 0x04, "LM4F120H5QR/TM4C1233H6PM"},
{0x05, 0x08, "LM4F121B2QR/TM4C1232C3PM"},
{0x05, 0x09, "LM4F121C4QR/TM4C1232D5PM"},
{0x05, 0x0A, "LM4F121E5QR/TM4C1232E6PM"},
{0x05, 0x0B, "LM4F121H5QR/TM4C1232H6PM"},
{0x05, 0x10, "LM4F110E5QR/TM4C1231E6PM"},
{0x05, 0x11, "LM4F110H5QR/TM4C1231H6PM"},
{0x05, 0x18, "LM4F110B2QR/TM4C1231C3PM"},
{0x05, 0x19, "LM4F110C4QR/TM4C1231D5PM"},
{0x05, 0x20, "LM4F111E5QR/TM4C1230E6PM"},
{0x05, 0x21, "LM4F111H5QR/TM4C1230H6PM"},
{0x05, 0x22, "LM4F111B2QR/TM4C1230C3PM"},
{0x05, 0x23, "LM4F111C4QR/TM4C1230D5PM"},
{0x05, 0x30, "LM4F112E5QC/TM4C1231E6PZ"},
{0x05, 0x31, "LM4F112H5QC/TM4C1231H6PZ"},
{0x05, 0x35, "LM4F112H5QD/TM4C1231H6PGE"},
{0x05, 0x36, "LM4F112C4QC/TM4C1231D5PZ"},
{0x05, 0x40, "LM4F130E5QR/TM4C1237E6PM"},
{0x05, 0x41, "LM4F130H5QR/TM4C1237H6PM"},
{0x05, 0x48, "LM4F130C4QR/TM4C1237D5PM"},
{0x05, 0x50, "LM4F131E5QR/TM4C1236E6PM"},
{0x05, 0x51, "LM4F131H5QR/TM4C1236H6PM"},
{0x05, 0x52, "LM4F131C4QR/TM4C1236D5PM"},
{0x05, 0x60, "LM4F132E5QC/TM4C1237E6PZ"},
{0x05, 0x61, "LM4F132H5QC/TM4C1237H6PZ"},
{0x05, 0x65, "LM4F132H5QD/TM4C1237H6PGE"},
{0x05, 0x66, "LM4F132C4QC/TM4C1237D5PZ"},
{0x05, 0x70, "LM4F210E5QR/TM4C123BE6PM"},
{0x05, 0x73, "LM4F210H5QR/TM4C123BH6PM"},
{0x05, 0x80, "LM4F211E5QR/TM4C123AE6PM"},
{0x05, 0x83, "LM4F211H5QR/TM4C123AH6PM"},
{0x05, 0xA0, "LM4F230E5QR/TM4C123GE6PM"},
{0x05, 0xA1, "LM4F230H5QR/TM4C123GH6PM"},
{0x05, 0xB0, "LM4F231E5QR/TM4C123FE6PM"},
{0x05, 0xB1, "LM4F231H5QR/TM4C123FH6PM"},
{0x05, 0xC0, "LM4F232E5QC/TM4C123GE6PZ"},
{0x05, 0xC1, "LM4F232H5QC/TM4C123GH6PZ"},
{0x05, 0xC3, "LM4F212E5QC/TM4C123BE6PZ"},
{0x05, 0xC4, "LM4F212H5QC/TM4C123BH6PZ"},
{0x05, 0xC5, "LM4F232H5QD/TM4C123GH6PGE"},
{0x05, 0xC6, "LM4F212H5QD/TM4C123BH6PGE"},
{0x05, 0xD0, "LM4F122C4QC/TM4C1233D5PZ"},
{0x05, 0xD1, "LM4F122E5QC/TM4C1233E6PZ"},
{0x05, 0xD2, "LM4F122H5QC/TM4C1233H6PZ"},
{0x05, 0xD6, "LM4F122H5QD/TM4C1233H6PGE"},
{0x05, 0xE1, "LM4FSXLH5BB"},
{0x05, 0xE3, "LM4F232H5BB/TM4C123GH6ZRB"},
{0x05, 0xE4, "LM4FS99H5BB"},
{0x05, 0xE5, "LM4FS1AH5BB"},
{0x05, 0xE9, "LM4F212H5BB/TM4C123BH6ZRB"},
{0x05, 0xEA, "LM4FS1GH5BB"},
{0x05, 0xF0, "TM4C123GH6ZXR"},
{0x0A, 0x19, "TM4C1290NCPDT"},
{0x0A, 0x1B, "TM4C1290NCZAD"},
{0x0A, 0x1C, "TM4C1292NCPDT"},
{0x0A, 0x1E, "TM4C1292NCZAD"},
{0x0A, 0x1F, "TM4C1294NCPDT"},
{0x0A, 0x21, "TM4C1294NCZAD"},
{0x0A, 0x22, "TM4C1297NCZAD"},
{0x0A, 0x23, "TM4C1299NCZAD"},
{0x0A, 0x24, "TM4C129CNCPDT"},
{0x0A, 0x26, "TM4C129CNCZAD"},
{0x0A, 0x27, "TM4C129DNCPDT"},
{0x0A, 0x29, "TM4C129DNCZAD"},
{0x0A, 0x2D, "TM4C129ENCPDT"},
{0x0A, 0x2F, "TM4C129ENCZAD"},
{0x0A, 0x30, "TM4C129LNCZAD"},
{0x0A, 0x32, "TM4C129XNCZAD"},
{0x0A, 0x34, "TM4C1294KCPDT"},
{0x0A, 0x35, "TM4C129EKCPDT"},
{0x0A, 0x36, "TM4C1299KCZAD"},
{0x0A, 0x37, "TM4C129XKCZAD"},
{0xFF, 0x00, "Unknown Part"}
};
static const char *StellarisClassname[7] = {
static const char * const StellarisClassname[] = {
"Sandstorm",
"Fury",
"Unknown",
"DustDevil",
"Tempest",
"Blizzard",
"Firestorm"
"Blizzard/TM4C123x",
"Firestorm",
"",
"",
"",
"Snowflake",
};
/***************************************************************************
@@ -482,36 +507,27 @@ static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size)
printed = snprintf(buf,
buf_size,
"did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32
", eproc: %s, ramsize: %ik, flashsize: %ik\n",
", eproc: %s, ramsize: %" PRIu32 "k, flashsize: %" PRIu32 "k\n",
stellaris_info->did1,
stellaris_info->did1,
"ARMv7M",
(int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4),
(int)((1 + (stellaris_info->dc0 & 0xFFFF))*2));
stellaris_info->sramsiz,
(uint32_t)(stellaris_info->num_pages * stellaris_info->pagesize / 1024));
buf += printed;
buf_size -= printed;
printed = snprintf(buf,
snprintf(buf,
buf_size,
"master clock: %ikHz%s, "
"rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n",
"rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 ", "
"pagesize: %" PRIu32 ", pages: %" PRIu32,
(int)(stellaris_info->mck_freq / 1000),
stellaris_info->mck_desc,
stellaris_info->rcc,
stellaris_info->rcc2);
buf += printed;
buf_size -= printed;
stellaris_info->rcc2,
stellaris_info->pagesize,
stellaris_info->num_pages);
if (stellaris_info->num_lockbits > 0) {
snprintf(buf,
buf_size,
"pagesize: %" PRIi32 ", pages: %d, "
"lockbits: %i, pages per lockbit: %i\n",
stellaris_info->pagesize,
(unsigned) stellaris_info->num_pages,
stellaris_info->num_lockbits,
(unsigned) stellaris_info->pages_in_lockregion);
}
return ERROR_OK;
}
@@ -666,7 +682,7 @@ static int stellaris_read_part_info(struct flash_bank *bank)
LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "",
did0, did1, stellaris_info->dc0, stellaris_info->dc1);
ver = did0 >> 28;
ver = DID0_VER(did0);
if ((ver != 0) && (ver != 1)) {
LOG_WARNING("Unknown did0 version, cannot identify target");
return ERROR_FLASH_OPERATION_FAILED;
@@ -724,6 +740,7 @@ static int stellaris_read_part_info(struct flash_bank *bank)
case 4: /* Tempest */
case 5: /* Blizzard */
case 6: /* Firestorm */
case 0xa: /* Snowflake */
stellaris_info->iosc_freq = 16000000; /* +/- 1% */
stellaris_info->iosc_desc = " (±1%)";
/* FALL THROUGH */
@@ -747,10 +764,26 @@ static int stellaris_read_part_info(struct flash_bank *bank)
stellaris_info->did0 = did0;
stellaris_info->did1 = did1;
stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF);
stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF));
stellaris_info->pagesize = 1024;
stellaris_info->pages_in_lockregion = 2;
if (stellaris_info->target_class == 5) { /* Blizzard */
target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize);
target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize);
stellaris_info->num_pages = 2 * (1 + (stellaris_info->fsize & 0xFFFF));
stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4;
stellaris_info->pagesize = 1024;
} else if (stellaris_info->target_class == 0xa) { /* Snowflake */
target_read_u32(target, FLASH_FSIZE, &stellaris_info->fsize);
target_read_u32(target, FLASH_SSIZE, &stellaris_info->ssize);
stellaris_info->pagesize = (1 << ((stellaris_info->fsize >> 16) & 7)) * 1024;
stellaris_info->num_pages = 2048 * (1 + (stellaris_info->fsize & 0xFFFF)) /
stellaris_info->pagesize;
stellaris_info->sramsiz = (1 + (stellaris_info->ssize & 0xFFFF)) / 4;
} else {
stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF));
stellaris_info->sramsiz = (1 + ((stellaris_info->dc0 >> 16) & 0xFFFF)) / 4;
stellaris_info->pagesize = 1024;
}
/* REVISIT for at least Tempest parts, read NVMSTAT.FWB too.
* That exposes a 32-word Flash Write Buffer ... enabling
@@ -767,9 +800,12 @@ static int stellaris_read_part_info(struct flash_bank *bank)
static int stellaris_protect_check(struct flash_bank *bank)
{
struct stellaris_flash_bank *stellaris = bank->driver_priv;
struct target *target = bank->target;
uint32_t flash_sizek = stellaris->pagesize / 1024 *
stellaris->num_pages;
uint32_t fmppe_addr;
int status = ERROR_OK;
unsigned i;
unsigned page;
if (stellaris->did1 == 0)
return ERROR_FLASH_BANK_NOT_PROBED;
@@ -781,32 +817,32 @@ static int stellaris_protect_check(struct flash_bank *bank)
* to report any pages that we can't write. Ignore the Read Enable
* register (FMPRE).
*/
for (i = 0, page = 0;
i < DIV_ROUND_UP(stellaris->num_lockbits, 32u);
i++) {
uint32_t lockbits;
status = target_read_u32(bank->target,
SCB_BASE + (i ? (FMPPE0 + 4 * i) : FMPPE),
&lockbits);
LOG_DEBUG("FMPPE%d = %#8.8x (status %d)", i,
(unsigned) lockbits, status);
if (status != ERROR_OK)
goto done;
if (stellaris->target_class >= 0x0a || flash_sizek > 64)
fmppe_addr = SCB_BASE | FMPPE0;
else
fmppe_addr = SCB_BASE | FMPPE;
for (unsigned j = 0; j < 32; j++) {
unsigned k;
unsigned int page = 0, lockbitnum, lockbitcnt = flash_sizek / 2;
unsigned int bits_per_page = stellaris->pagesize / 2048;
/* Every lock bit always corresponds to a 2k region */
for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) {
uint32_t fmppe;
for (k = 0; k < stellaris->pages_in_lockregion; k++) {
if (page >= (unsigned) bank->num_sectors)
goto done;
bank->sectors[page++].is_protected =
!(lockbits & (1 << j));
target_read_u32(target, fmppe_addr, &fmppe);
for (i = 0; i < 32 && lockbitnum + i < lockbitcnt; i++) {
bool protect = !(fmppe & (1 << i));
if (bits_per_page) {
bank->sectors[page++].is_protected = protect;
i += bits_per_page - 1;
} else { /* 1024k pages, every lockbit covers 2 pages */
bank->sectors[page++].is_protected = protect;
bank->sectors[page++].is_protected = protect;
}
}
fmppe_addr += 4;
}
done:
return status;
}
@@ -870,13 +906,12 @@ static int stellaris_erase(struct flash_bank *bank, int first, int last)
static int stellaris_protect(struct flash_bank *bank, int set, int first, int last)
{
uint32_t fmppe, flash_fmc, flash_cris;
int lockregion;
struct stellaris_flash_bank *stellaris_info = bank->driver_priv;
struct stellaris_flash_bank *stellaris = bank->driver_priv;
struct target *target = bank->target;
uint32_t flash_fmc, flash_cris;
unsigned int bits_per_page = stellaris->pagesize / 2048;
if (bank->target->state != TARGET_HALTED) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
@@ -887,14 +922,18 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (stellaris_info->did1 == 0)
if (stellaris->did1 == 0)
return ERROR_FLASH_BANK_NOT_PROBED;
/* lockregions are 2 pages ... must protect [even..odd] */
if ((first < 0) || (first & 1)
|| (last < first) || !(last & 1)
|| (last >= 2 * stellaris_info->num_lockbits)) {
LOG_ERROR("Can't protect unaligned or out-of-range pages.");
if (stellaris->target_class == 0x03 &&
!((stellaris->did0 >> 8) & 0xFF) &&
!((stellaris->did0) & 0xFF)) {
LOG_ERROR("DustDevil A0 parts can't be unprotected, see errata; refusing to proceed");
return ERROR_FLASH_OPERATION_FAILED;
}
if (!bits_per_page && (first % 2 || !(last % 2))) {
LOG_ERROR("Can't protect unaligned pages");
return ERROR_FLASH_SECTOR_INVALID;
}
@@ -902,57 +941,60 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la
stellaris_read_clock_info(bank);
stellaris_set_flash_timing(bank);
/* convert from pages to lockregions */
first /= 2;
last /= 2;
/* FIXME this assumes single FMPPE, for a max of 64K of flash!!
* Current parts can be much bigger.
*/
if (last >= 32) {
LOG_ERROR("No support yet for protection > 64K");
return ERROR_FLASH_OPERATION_FAILED;
}
target_read_u32(target, SCB_BASE | FMPPE, &fmppe);
for (lockregion = first; lockregion <= last; lockregion++)
fmppe &= ~(1 << lockregion);
/* Clear and disable flash programming interrupts */
target_write_u32(target, FLASH_CIM, 0);
target_write_u32(target, FLASH_MISC, PMISC | AMISC);
/* REVISIT this clobbers state set by any halted firmware ...
* it might want to process those IRQs.
*/
uint32_t flash_sizek = stellaris->pagesize / 1024 *
stellaris->num_pages;
uint32_t fmppe_addr;
LOG_DEBUG("fmppe 0x%" PRIx32 "", fmppe);
target_write_u32(target, SCB_BASE | FMPPE, fmppe);
if (stellaris->target_class >= 0x0a || flash_sizek > 64)
fmppe_addr = SCB_BASE | FMPPE0;
else
fmppe_addr = SCB_BASE | FMPPE;
/* Commit FMPPE */
target_write_u32(target, FLASH_FMA, 1);
int page = 0;
unsigned int lockbitnum, lockbitcnt = flash_sizek / 2;
/* Every lock bit always corresponds to a 2k region */
for (lockbitnum = 0; lockbitnum < lockbitcnt; lockbitnum += 32) {
uint32_t fmppe;
/* Write commit command */
/* REVISIT safety check, since this cannot be undone
* except by the "Recover a locked device" procedure.
* REVISIT DustDevil-A0 parts have an erratum making FMPPE commits
* inadvisable ... it makes future mass erase operations fail.
*/
LOG_WARNING("Flash protection cannot be removed once committed, commit is NOT executed !");
/* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */
target_read_u32(target, fmppe_addr, &fmppe);
for (unsigned int i = 0;
i < 32 && lockbitnum + i < lockbitcnt;
i++) {
if (page >= first && page <= last)
fmppe &= ~(1 << i);
/* Wait until erase complete */
do {
target_read_u32(target, FLASH_FMC, &flash_fmc);
} while (flash_fmc & FMC_COMT);
if (bits_per_page) {
if (!((i + 1) % bits_per_page))
page++;
} else { /* 1024k pages, every lockbit covers 2 pages */
page += 2;
}
}
target_write_u32(target, fmppe_addr, fmppe);
/* Check acess violations */
target_read_u32(target, FLASH_CRIS, &flash_cris);
if (flash_cris & (AMASK)) {
LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
target_write_u32(target, FLASH_CRIS, 0);
return ERROR_FLASH_OPERATION_FAILED;
/* Commit FMPPE* */
target_write_u32(target, FLASH_FMA, 1 + lockbitnum / 16);
/* Write commit command */
target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT);
/* Wait until commit complete */
do {
target_read_u32(target, FLASH_FMC, &flash_fmc);
} while (flash_fmc & FMC_COMT);
/* Check access violations */
target_read_u32(target, FLASH_CRIS, &flash_cris);
if (flash_cris & (AMASK)) {
LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris);
target_write_u32(target, FLASH_CRIS, 0);
return ERROR_FLASH_OPERATION_FAILED;
}
fmppe_addr += 4;
}
return ERROR_OK;
@@ -1216,7 +1258,7 @@ static int stellaris_probe(struct flash_bank *bank)
}
/* provide this for the benefit of the NOR flash framework */
bank->size = 1024 * stellaris_info->num_pages;
bank->size = stellaris_info->num_pages * stellaris_info->pagesize;
bank->num_sectors = stellaris_info->num_pages;
bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
for (int i = 0; i < bank->num_sectors; i++) {
@@ -1317,9 +1359,12 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
struct flash_bank *bank;
int retval;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (retval != ERROR_OK)
return retval;
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
bank = get_flash_bank_by_num_noprobe(0);
if (!bank)
return ERROR_FAIL;
/* REVISIT ... it may be worth sanity checking that the AP is
* inactive before we start. ARM documents that switching a DP's
@@ -1327,6 +1372,12 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
* cycle to recover.
*/
Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0);
if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) {
retval = ERROR_OK;
goto user_action;
}
/* assert SRST */
if (!(jtag_get_reset_config() & RESET_HAS_SRST)) {
LOG_ERROR("Can't recover Stellaris flash without SRST");
@@ -1351,6 +1402,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
/* wait 400+ msec ... OK, "1+ second" is simpler */
usleep(1000);
user_action:
/* USER INTERVENTION required for the power cycle
* Restarting OpenOCD is likely needed because of mode switching.
*/
@@ -1373,7 +1425,7 @@ static const struct command_registration stellaris_exec_command_handlers[] = {
.name = "recover",
.handler = stellaris_handle_recover_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.usage = "",
.help = "recover (and erase) locked device",
},
COMMAND_REGISTRATION_DONE

View File

@@ -894,7 +894,7 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
break;
case 0x422: /* stm32f30x */
case 0x422: /* stm32f302/3xb/c */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 256;
@@ -902,6 +902,14 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->option_offset = 6;
stm32x_info->default_rdp = 0x55AA;
break;
case 0x446: /* stm32f303xD/E */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 512;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
stm32x_info->default_rdp = 0x55AA;
break;
case 0x428: /* value line High density */
page_size = 2048;
stm32x_info->ppage_size = 4;
@@ -921,8 +929,18 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->option_offset = 6;
stm32x_info->default_rdp = 0x55AA;
break;
case 0x438: /* stm32f33x */
case 0x439: /* stm32f302x6/8 */
page_size = 2048;
stm32x_info->ppage_size = 2;
max_flash_size_in_kb = 64;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
stm32x_info->default_rdp = 0x55AA;
break;
case 0x440: /* stm32f05x */
case 0x444: /* stm32f03x */
case 0x445: /* stm32f04x */
page_size = 1024;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 64;
@@ -931,9 +949,10 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->default_rdp = 0x55AA;
break;
case 0x448: /* stm32f07x */
case 0x442: /* stm32f09x */
page_size = 2048;
stm32x_info->ppage_size = 4;
max_flash_size_in_kb = 128;
max_flash_size_in_kb = 256;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
stm32x_info->default_rdp = 0x55AA;
@@ -1022,6 +1041,21 @@ COMMAND_HANDLER(stm32x_handle_part_id_command)
}
#endif
static const char *get_stm32f0_revision(uint16_t rev_id)
{
const char *rev_str = NULL;
switch (rev_id) {
case 0x1000:
rev_str = "1.0";
break;
case 0x2000:
rev_str = "2.0";
break;
}
return rev_str;
}
static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
{
uint32_t dbgmcu_idcode;
@@ -1116,7 +1150,7 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
break;
case 0x422:
device_str = "STM32F30x";
device_str = "STM32F302xB/C";
switch (rev_id) {
case 0x1000:
@@ -1175,46 +1209,62 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
}
break;
case 0x444:
device_str = "STM32F03x";
case 0x438:
device_str = "STM32F33x";
switch (rev_id) {
case 0x1000:
rev_str = "1.0";
break;
case 0x2000:
rev_str = "2.0";
rev_str = "A";
break;
}
break;
case 0x440:
device_str = "STM32F05x";
case 0x439:
device_str = "STM32F302x6/8";
switch (rev_id) {
case 0x1000:
rev_str = "1.0";
rev_str = "A";
break;
case 0x2000:
rev_str = "2.0";
case 0x1001:
rev_str = "Z";
break;
}
break;
case 0x444:
device_str = "STM32F03x";
rev_str = get_stm32f0_revision(rev_id);
break;
case 0x440:
device_str = "STM32F05x";
rev_str = get_stm32f0_revision(rev_id);
break;
case 0x445:
device_str = "STM32F04x";
rev_str = get_stm32f0_revision(rev_id);
break;
case 0x446:
device_str = "STM32F303xD/E";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
}
break;
case 0x448:
device_str = "STM32F07x";
rev_str = get_stm32f0_revision(rev_id);
break;
switch (rev_id) {
case 0x1000:
rev_str = "1.0";
break;
case 0x2000:
rev_str = "2.0";
break;
}
case 0x442:
device_str = "STM32F09x";
rev_str = get_stm32f0_revision(rev_id);
break;
default:

View File

@@ -344,8 +344,8 @@ static int stm32x_write_options(struct flash_bank *bank)
/* rebuild option data */
optiondata = stm32x_info->option_bytes.user_options;
buf_set_u32(&optiondata, 8, 8, stm32x_info->option_bytes.RDP);
buf_set_u32(&optiondata, 16, 12, stm32x_info->option_bytes.protection);
optiondata |= stm32x_info->option_bytes.RDP << 8;
optiondata |= (stm32x_info->option_bytes.protection & 0x0fff) << 16;
/* program options */
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata);
@@ -355,7 +355,7 @@ static int stm32x_write_options(struct flash_bank *bank)
if (stm32x_info->has_large_mem) {
uint32_t optiondata2 = 0;
buf_set_u32(&optiondata2, 16, 12, stm32x_info->option_bytes.protection >> 12);
optiondata2 |= (stm32x_info->option_bytes.protection & 0x00fff000) << 4;
retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2);
if (retval != ERROR_OK)
return retval;
@@ -372,7 +372,7 @@ static int stm32x_write_options(struct flash_bank *bank)
return retval;
/* relock registers */
retval = target_write_u32(target, STM32_FLASH_OPTCR, OPT_LOCK);
retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPT_LOCK);
if (retval != ERROR_OK)
return retval;
@@ -779,7 +779,9 @@ static int stm32x_probe(struct flash_bank *bank)
case 0x423:
max_flash_size_in_kb = 256;
break;
case 0x431:
case 0x433:
case 0x421:
max_flash_size_in_kb = 512;
break;
default:
@@ -926,10 +928,27 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
case 0x1003:
rev_str = "Y";
break;
case 0x1007:
rev_str = "1";
break;
case 0x2001:
rev_str = "3";
break;
}
break;
case 0x421:
device_str = "STM32F446";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
}
break;
case 0x423:
case 0x431:
case 0x433:
device_str = "STM32F4xx (Low Power)";

View File

@@ -36,16 +36,15 @@
/* stm32lx flash register locations */
#define FLASH_BASE 0x40023C00
#define FLASH_ACR 0x40023C00
#define FLASH_PECR 0x40023C04
#define FLASH_PDKEYR 0x40023C08
#define FLASH_PEKEYR 0x40023C0C
#define FLASH_PRGKEYR 0x40023C10
#define FLASH_OPTKEYR 0x40023C14
#define FLASH_SR 0x40023C18
#define FLASH_OBR 0x40023C1C
#define FLASH_WRPR 0x40023C20
#define FLASH_ACR 0x00
#define FLASH_PECR 0x04
#define FLASH_PDKEYR 0x08
#define FLASH_PEKEYR 0x0C
#define FLASH_PRGKEYR 0x10
#define FLASH_OPTKEYR 0x14
#define FLASH_SR 0x18
#define FLASH_OBR 0x1C
#define FLASH_WRPR 0x20
/* FLASH_ACR bites */
#define FLASH_ACR__LATENCY (1<<0)
@@ -86,44 +85,151 @@
#define OPTKEY2 0x24252627
/* other registers */
#define DBGMCU_IDCODE 0xE0042000
#define F_SIZE 0x1FF8004C
#define F_SIZE_MP 0x1FF800CC /* on 0x427 Medium+ and 0x436 HD devices */
#define DBGMCU_IDCODE 0xE0042000
#define DBGMCU_IDCODE_L0 0x40015800
/* Constants */
#define FLASH_PAGE_SIZE 256
#define FLASH_SECTOR_SIZE 4096
#define FLASH_PAGES_PER_SECTOR 16
#define FLASH_BANK0_ADDRESS 0x08000000
/* stm32lx option byte register location */
#define OB_RDP 0x1FF80000
#define OB_USER 0x1FF80004
#define OB_WRP0_1 0x1FF80008
#define OB_WRP2_3 0x1FF8000C
/* option bytes */
#define OPTION_BYTES_ADDRESS 0x1FF80000
/* OB_RDP values */
#define OB_RDP__LEVEL0 0xFF5500AA
#define OB_RDP__LEVEL1 0xFFFF0000
/* stm32lx RCC register locations */
#define RCC_CR 0x40023800
#define RCC_ICSCR 0x40023804
#define RCC_CFGR 0x40023808
/* RCC_ICSCR bits */
#define RCC_ICSCR__MSIRANGE_MASK (7<<13)
#define OPTION_BYTE_0_PR1 0xFFFF0000
#define OPTION_BYTE_0_PR0 0xFF5500AA
static int stm32lx_unlock_program_memory(struct flash_bank *bank);
static int stm32lx_lock_program_memory(struct flash_bank *bank);
static int stm32lx_enable_write_half_page(struct flash_bank *bank);
static int stm32lx_erase_sector(struct flash_bank *bank, int sector);
static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank);
static int stm32lx_mass_erase(struct flash_bank *bank);
static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout);
struct stm32lx_rev {
uint16_t rev;
const char *str;
};
struct stm32lx_part_info {
uint16_t id;
const char *device_str;
const struct stm32lx_rev *revs;
size_t num_revs;
unsigned int page_size;
unsigned int pages_per_sector;
uint16_t max_flash_size_kb;
uint16_t first_bank_size_kb; /* used when has_dual_banks is true */
bool has_dual_banks;
uint32_t flash_base; /* Flash controller registers location */
uint32_t fsize_base; /* Location of FSIZE register */
};
struct stm32lx_flash_bank {
int probed;
bool has_dual_banks;
uint32_t idcode;
uint32_t user_bank_size;
uint32_t flash_base;
const struct stm32lx_part_info *part_info;
};
static const struct stm32lx_rev stm32_416_revs[] = {
{ 0x1000, "A" }, { 0x1008, "Y" }, { 0x1038, "W" }, { 0x1078, "V" },
};
static const struct stm32lx_rev stm32_417_revs[] = {
{ 0x1000, "A" }, { 0x1008, "Z" },
};
static const struct stm32lx_rev stm32_427_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Y" }, { 0x1038, "X" },
};
static const struct stm32lx_rev stm32_429_revs[] = {
{ 0x1000, "A" }, { 0x1018, "Z" },
};
static const struct stm32lx_rev stm32_436_revs[] = {
{ 0x1000, "A" }, { 0x1008, "Z" }, { 0x1018, "Y" },
};
static const struct stm32lx_rev stm32_437_revs[] = {
{ 0x1000, "A" },
};
static const struct stm32lx_part_info stm32lx_parts[] = {
{
.id = 0x416,
.revs = stm32_416_revs,
.num_revs = ARRAY_SIZE(stm32_416_revs),
.device_str = "STM32L1xx (Cat.1 - Low/Medium Density)",
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 128,
.has_dual_banks = false,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF8004C,
},
{
.id = 0x417,
.revs = stm32_417_revs,
.num_revs = ARRAY_SIZE(stm32_417_revs),
.device_str = "STM32L0xx",
.page_size = 128,
.pages_per_sector = 32,
.max_flash_size_kb = 64,
.has_dual_banks = false,
.flash_base = 0x40022000,
.fsize_base = 0x1FF8007C,
},
{
.id = 0x427,
.revs = stm32_427_revs,
.num_revs = ARRAY_SIZE(stm32_427_revs),
.device_str = "STM32L1xx (Cat.3 - Medium+ Density)",
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 256,
.first_bank_size_kb = 192,
.has_dual_banks = true,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF800CC,
},
{
.id = 0x429,
.revs = stm32_429_revs,
.num_revs = ARRAY_SIZE(stm32_429_revs),
.device_str = "STM32L1xx (Cat.2)",
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 128,
.has_dual_banks = false,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF8004C,
},
{
.id = 0x436,
.revs = stm32_436_revs,
.num_revs = ARRAY_SIZE(stm32_436_revs),
.device_str = "STM32L1xx (Cat.4/Cat.3 - Medium+/High Density)",
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 384,
.first_bank_size_kb = 192,
.has_dual_banks = true,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF800CC,
},
{
.id = 0x437,
.revs = stm32_437_revs,
.num_revs = ARRAY_SIZE(stm32_437_revs),
.device_str = "STM32L1xx (Cat.5/Cat.6)",
.page_size = 256,
.pages_per_sector = 16,
.max_flash_size_kb = 512,
.first_bank_size_kb = 256,
.has_dual_banks = true,
.flash_base = 0x40023C00,
.fsize_base = 0x1FF800CC,
},
};
/* flash bank stm32lx <base> <size> 0 0 <target#>
@@ -135,7 +241,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
return ERROR_COMMAND_SYNTAX_ERROR;
/* Create the bank structure */
stm32lx_info = malloc(sizeof(struct stm32lx_flash_bank));
stm32lx_info = calloc(1, sizeof(*stm32lx_info));
/* Check allocation */
if (stm32lx_info == NULL) {
@@ -146,7 +252,6 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
bank->driver_priv = stm32lx_info;
stm32lx_info->probed = 0;
stm32lx_info->has_dual_banks = false;
stm32lx_info->user_bank_size = bank->size;
/* the stm32l erased value is 0x00 */
@@ -155,10 +260,37 @@ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command)
return ERROR_OK;
}
COMMAND_HANDLER(stm32lx_handle_mass_erase_command)
{
int i;
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
retval = stm32lx_mass_erase(bank);
if (retval == ERROR_OK) {
/* set all sectors as erased */
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
command_print(CMD_CTX, "stm32lx mass erase complete");
} else {
command_print(CMD_CTX, "stm32lx mass erase failed");
}
return retval;
}
static int stm32lx_protect_check(struct flash_bank *bank)
{
int retval;
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
uint32_t wrpr;
@@ -166,11 +298,12 @@ static int stm32lx_protect_check(struct flash_bank *bank)
* Read the WRPR word, and check each bit (corresponding to each
* flash sector
*/
retval = target_read_u32(target, FLASH_WRPR, &wrpr);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_WRPR,
&wrpr);
if (retval != ERROR_OK)
return retval;
for (int i = 0; i < 32; i++) {
for (int i = 0; i < bank->num_sectors; i++) {
if (wrpr & (1 << i))
bank->sectors[i].is_protected = 1;
else
@@ -216,6 +349,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
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;
struct working_area *write_algorithm;
struct working_area *source;
@@ -244,10 +380,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
0x00, 0xbe, /* bkpt 0 */
};
/* Check if there is an even number of half pages (128bytes) */
if (count % 128) {
LOG_ERROR("there should be an even number "
"of half pages = 128 bytes (count = %" PRIi32 " bytes)", count);
/* Make sure we're performing a half-page aligned write. */
if (count % hp_nb) {
LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIi32 "B)", hp_nb, count);
return ERROR_FAIL;
}
@@ -275,7 +410,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
else
buffer_size /= 2;
if (buffer_size <= 256) {
if (buffer_size <= stm32lx_info->part_info->page_size) {
/* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
target_free_working_area(target, write_algorithm);
@@ -372,7 +507,7 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff
while (count > 0) {
uint32_t this_count;
this_count = (count > 128) ? 128 : count;
this_count = (count > hp_nb) ? hp_nb : count;
/* Write the next half pages */
retval = target_write_buffer(target, address, this_count, buffer);
@@ -407,7 +542,9 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
uint32_t hp_nb = stm32lx_info->part_info->page_size / 2;
uint32_t halfpages_number;
uint32_t bytes_remaining = 0;
uint32_t address = bank->base + offset;
@@ -431,8 +568,8 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
/* first we need to write any unaligned head bytes upto
* the next 128 byte page */
if (offset % 128)
bytes_remaining = MIN(count, 128 - (offset % 128));
if (offset % hp_nb)
bytes_remaining = MIN(count, hp_nb - (offset % hp_nb));
while (bytes_remaining > 0) {
uint8_t value[4] = {0xff, 0xff, 0xff, 0xff};
@@ -458,13 +595,13 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
count -= bytes_written;
/* this should always pass this check here */
assert((offset % 128) == 0);
assert((offset % hp_nb) == 0);
/* calculate half pages */
halfpages_number = count / 128;
halfpages_number = count / hp_nb;
if (halfpages_number) {
retval = stm32lx_write_half_pages(bank, buffer + bytes_written, offset, 128 * halfpages_number);
retval = stm32lx_write_half_pages(bank, buffer + bytes_written, offset, hp_nb * halfpages_number);
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* attempt slow memory writes */
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
@@ -476,7 +613,7 @@ static int stm32lx_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* write any remaining bytes */
uint32_t page_bytes_written = 128 * halfpages_number;
uint32_t page_bytes_written = hp_nb * halfpages_number;
bytes_written += page_bytes_written;
address += page_bytes_written;
bytes_remaining = count - page_bytes_written;
@@ -513,65 +650,57 @@ reset_pg_and_lock:
return retval;
}
static int stm32lx_read_id_code(struct target *target, uint32_t *id)
{
/* read stm32 device id register */
int retval = target_read_u32(target, DBGMCU_IDCODE, id);
if (retval != ERROR_OK)
return retval;
/* STM32L0 parts will have 0 there, try reading the L0's location for
* DBG_IDCODE in case this is an L0 part. */
if (*id == 0)
retval = target_read_u32(target, DBGMCU_IDCODE_L0, id);
return retval;
}
static int stm32lx_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int i;
uint16_t flash_size_in_kb;
uint16_t max_flash_size_in_kb;
uint32_t device_id;
uint32_t base_address = FLASH_BANK0_ADDRESS;
uint32_t second_bank_base;
uint32_t first_bank_size_in_kb;
stm32lx_info->probed = 0;
stm32lx_info->part_info = NULL;
/* read stm32 device id register */
int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id);
int retval = stm32lx_read_id_code(bank->target, &device_id);
if (retval != ERROR_OK)
return retval;
stm32lx_info->idcode = device_id;
LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id);
/* set max flash size depending on family */
switch (device_id & 0xfff) {
case 0x416:
max_flash_size_in_kb = 128;
break;
case 0x427:
/* single bank, high density */
max_flash_size_in_kb = 256;
break;
case 0x436:
/* According to ST, the devices with id 0x436 have dual bank flash and comes with
* a total flash size of 384k or 256kb. However, the first bank is always 192kb,
* and second one holds the rest. The reason is that the 256kb version is actually
* the same physical flash but only the first 256kb are verified.
*/
max_flash_size_in_kb = 384;
first_bank_size_in_kb = 192;
stm32lx_info->has_dual_banks = true;
break;
case 0x437:
/* Dual bank, high density */
max_flash_size_in_kb = 512;
first_bank_size_in_kb = 192;
stm32lx_info->has_dual_banks = true;
break;
default:
for (unsigned int n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) {
if ((device_id & 0xfff) == stm32lx_parts[n].id)
stm32lx_info->part_info = &stm32lx_parts[n];
}
if (!stm32lx_info->part_info) {
LOG_WARNING("Cannot identify target as a STM32L family.");
return ERROR_FAIL;
}
/* Get the flash size from target. 0x427 and 0x436 devices use a
* different location for the Flash Size register, please see RM0038 r8 or
* newer. */
if ((device_id & 0xfff) == 0x427 || (device_id & 0xfff) == 0x436 ||
(device_id & 0xfff) == 0x437)
retval = target_read_u16(target, F_SIZE_MP, &flash_size_in_kb);
else
retval = target_read_u16(target, F_SIZE, &flash_size_in_kb);
stm32lx_info->flash_base = stm32lx_info->part_info->flash_base;
/* Get the flash size from target. */
retval = target_read_u16(target, stm32lx_info->part_info->fsize_base,
&flash_size_in_kb);
/* 0x436 devices report their flash size as a 0 or 1 code indicating 384K
* or 256K, respectively. Please see RM0038 r8 or newer and refer to
@@ -587,26 +716,29 @@ static int stm32lx_probe(struct flash_bank *bank)
* default to max target family */
if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) {
LOG_WARNING("STM32L flash size failed, probe inaccurate - assuming %dk flash",
max_flash_size_in_kb);
flash_size_in_kb = max_flash_size_in_kb;
} else if (flash_size_in_kb > max_flash_size_in_kb) {
stm32lx_info->part_info->max_flash_size_kb);
flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb;
} else if (flash_size_in_kb > stm32lx_info->part_info->max_flash_size_kb) {
LOG_WARNING("STM32L probed flash size assumed incorrect since FLASH_SIZE=%dk > %dk, - assuming %dk flash",
flash_size_in_kb, max_flash_size_in_kb, max_flash_size_in_kb);
flash_size_in_kb = max_flash_size_in_kb;
flash_size_in_kb, stm32lx_info->part_info->max_flash_size_kb,
stm32lx_info->part_info->max_flash_size_kb);
flash_size_in_kb = stm32lx_info->part_info->max_flash_size_kb;
}
if (stm32lx_info->has_dual_banks) {
if (stm32lx_info->part_info->has_dual_banks) {
/* Use the configured base address to determine if this is the first or second flash bank.
* Verify that the base address is reasonably correct and determine the flash bank size
*/
second_bank_base = base_address + first_bank_size_in_kb * 1024;
if (bank->base == second_bank_base) {
second_bank_base = base_address +
stm32lx_info->part_info->first_bank_size_kb * 1024;
if (bank->base == second_bank_base || !bank->base) {
/* This is the second bank */
base_address = second_bank_base;
flash_size_in_kb = flash_size_in_kb - first_bank_size_in_kb;
} else if (bank->base == 0 || bank->base == base_address) {
flash_size_in_kb = flash_size_in_kb -
stm32lx_info->part_info->first_bank_size_kb;
} else if (bank->base == base_address) {
/* This is the first bank */
flash_size_in_kb = first_bank_size_in_kb;
flash_size_in_kb = stm32lx_info->part_info->first_bank_size_kb;
} else {
LOG_WARNING("STM32L flash bank base address config is incorrect."
" 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32,
@@ -626,9 +758,6 @@ static int stm32lx_probe(struct flash_bank *bank)
LOG_INFO("ignoring flash probed value, using configured bank size: %dkbytes", flash_size_in_kb);
}
/* STM32L - we have 32 sectors, 16 pages per sector -> 512 pages
* 16 pages for a protection area */
/* calculate numbers of sectors (4kB per sector) */
int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE;
@@ -718,95 +847,56 @@ static int stm32lx_erase_check(struct flash_bank *bank)
return retval;
}
/* This method must return a string displaying information about the bank */
static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size)
{
/* This method must return a string displaying information about the bank */
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
uint32_t dbgmcu_idcode;
/* read stm32 device id register */
int retval = target_read_u32(bank->target, DBGMCU_IDCODE, &dbgmcu_idcode);
if (retval != ERROR_OK)
return retval;
uint16_t device_id = dbgmcu_idcode & 0xfff;
uint16_t rev_id = dbgmcu_idcode >> 16;
const char *device_str;
const char *rev_str = NULL;
switch (device_id) {
case 0x416:
device_str = "STM32L1xx (Low/Medium Density)";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
case 0x1008:
rev_str = "Y";
break;
case 0x1018:
rev_str = "X";
break;
case 0x1038:
rev_str = "W";
break;
case 0x1078:
rev_str = "V";
break;
if (!stm32lx_info->probed) {
int retval = stm32lx_probe(bank);
if (retval != ERROR_OK) {
snprintf(buf, buf_size,
"Unable to find bank information.");
return retval;
}
break;
case 0x427:
device_str = "STM32L1xx (Medium+ Density)";
switch (rev_id) {
case 0x1018:
rev_str = "A";
break;
}
break;
case 0x436:
device_str = "STM32L1xx (Medium+/High Density)";
switch (rev_id) {
case 0x1000:
rev_str = "A";
break;
case 0x1008:
rev_str = "Z";
break;
case 0x1018:
rev_str = "Y";
break;
}
break;
case 0x437:
device_str = "STM32L1xx (Medium+/High Density)";
break;
default:
snprintf(buf, buf_size, "Cannot identify target as a STM32L1");
return ERROR_FAIL;
}
if (rev_str != NULL)
snprintf(buf, buf_size, "%s - Rev: %s", device_str, rev_str);
else
snprintf(buf, buf_size, "%s - Rev: unknown (0x%04x)", device_str, rev_id);
const struct stm32lx_part_info *info = stm32lx_info->part_info;
return ERROR_OK;
if (info) {
const char *rev_str = NULL;
uint16_t rev_id = stm32lx_info->idcode >> 16;
for (unsigned int i = 0; i < info->num_revs; i++)
if (rev_id == info->revs[i].rev)
rev_str = info->revs[i].str;
if (rev_str != NULL) {
snprintf(buf, buf_size,
"%s - Rev: %s",
stm32lx_info->part_info->device_str, rev_str);
} else {
snprintf(buf, buf_size,
"%s - Rev: unknown (0x%04x)",
stm32lx_info->part_info->device_str, rev_id);
}
return ERROR_OK;
} else {
snprintf(buf, buf_size, "Cannot identify target as a STM32Lx");
return ERROR_FAIL;
}
}
static const struct command_registration stm32lx_exec_command_handlers[] = {
{
.name = "mass_erase",
.handler = stm32lx_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Erase entire flash device. including available EEPROM",
},
COMMAND_REGISTRATION_DONE
};
@@ -840,6 +930,7 @@ struct flash_driver stm32lx_flash = {
static int stm32lx_unlock_program_memory(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
uint32_t reg32;
@@ -849,7 +940,8 @@ static int stm32lx_unlock_program_memory(struct flash_bank *bank)
*/
/* check flash is not already unlocked */
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
@@ -857,16 +949,19 @@ static int stm32lx_unlock_program_memory(struct flash_bank *bank)
return ERROR_OK;
/* To unlock the PECR write the 2 PEKEY to the PEKEYR register */
retval = target_write_u32(target, FLASH_PEKEYR, PEKEY1);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR,
PEKEY1);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, FLASH_PEKEYR, PEKEY2);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR,
PEKEY2);
if (retval != ERROR_OK)
return retval;
/* Make sure it worked */
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
@@ -875,15 +970,18 @@ static int stm32lx_unlock_program_memory(struct flash_bank *bank)
return ERROR_FLASH_OPERATION_FAILED;
}
retval = target_write_u32(target, FLASH_PRGKEYR, PRGKEY1);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PRGKEYR,
PRGKEY1);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, FLASH_PRGKEYR, PRGKEY2);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PRGKEYR,
PRGKEY2);
if (retval != ERROR_OK)
return retval;
/* Make sure it worked */
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
@@ -898,6 +996,7 @@ static int stm32lx_unlock_program_memory(struct flash_bank *bank)
static int stm32lx_enable_write_half_page(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
uint32_t reg32;
@@ -908,21 +1007,25 @@ static int stm32lx_enable_write_half_page(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
reg32 |= FLASH_PECR__FPRG;
retval = target_write_u32(target, FLASH_PECR, reg32);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
reg32);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
reg32 |= FLASH_PECR__PROG;
retval = target_write_u32(target, FLASH_PECR, reg32);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
reg32);
return retval;
}
@@ -930,26 +1033,31 @@ static int stm32lx_enable_write_half_page(struct flash_bank *bank)
static int stm32lx_lock_program_memory(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
uint32_t reg32;
/* To lock the program memory, simply set the lock bit and lock PECR */
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
reg32 |= FLASH_PECR__PRGLOCK;
retval = target_write_u32(target, FLASH_PECR, reg32);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
reg32);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, FLASH_PECR, &reg32);
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR,
&reg32);
if (retval != ERROR_OK)
return retval;
reg32 |= FLASH_PECR__PELOCK;
retval = target_write_u32(target, FLASH_PECR, reg32);
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
reg32);
if (retval != ERROR_OK)
return retval;
@@ -959,11 +1067,12 @@ static int stm32lx_lock_program_memory(struct flash_bank *bank)
static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
uint32_t reg32;
/*
* To erase a sector (i.e. FLASH_PAGES_PER_SECTOR pages),
* To erase a sector (i.e. stm32lx_info->part_info.pages_per_sector pages),
* first unlock the memory, loop over the pages of this sector
* and write 0x0 to its first word.
*/
@@ -972,9 +1081,11 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
if (retval != ERROR_OK)
return retval;
for (int page = 0; page < FLASH_PAGES_PER_SECTOR; page++) {
for (int page = 0; page < (int)stm32lx_info->part_info->pages_per_sector;
page++) {
reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE;
retval = target_write_u32(target, FLASH_PECR, reg32);
retval = target_write_u32(target,
stm32lx_info->flash_base + FLASH_PECR, reg32);
if (retval != ERROR_OK)
return retval;
@@ -983,7 +1094,7 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
return retval;
uint32_t addr = bank->base + bank->sectors[sector].offset + (page
* FLASH_PAGE_SIZE);
* stm32lx_info->part_info->page_size);
retval = target_write_u32(target, addr, 0x0);
if (retval != ERROR_OK)
return retval;
@@ -1000,21 +1111,79 @@ static int stm32lx_erase_sector(struct flash_bank *bank, int sector)
return ERROR_OK;
}
static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank)
static inline int stm32lx_get_flash_status(struct flash_bank *bank, uint32_t *status)
{
struct target *target = bank->target;
uint32_t status;
int retval = ERROR_OK;
int timeout = 100;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
/* wait for busy to clear */
for (;;) {
retval = target_read_u32(target, FLASH_SR, &status);
return target_read_u32(target, stm32lx_info->flash_base + FLASH_SR, status);
}
static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank)
{
return stm32lx_wait_until_bsy_clear_timeout(bank, 100);
}
static int stm32lx_unlock_options_bytes(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
uint32_t reg32;
/*
* Unlocking the options bytes is done by unlocking the PECR,
* then by writing the 2 FLASH_PEKEYR to the FLASH_OPTKEYR register
*/
/* check flash is not already unlocked */
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, &reg32);
if (retval != ERROR_OK)
return retval;
if ((reg32 & FLASH_PECR__OPTLOCK) == 0)
return ERROR_OK;
if ((reg32 & FLASH_PECR__PELOCK) != 0) {
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY1);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PEKEYR, PEKEY2);
if (retval != ERROR_OK)
return retval;
}
/* To unlock the PECR write the 2 OPTKEY to the FLASH_OPTKEYR register */
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY1);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_OPTKEYR, OPTKEY2);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}
static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int timeout)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
uint32_t status;
int retval = ERROR_OK;
/* wait for busy to clear */
for (;;) {
retval = stm32lx_get_flash_status(bank, &status);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("status: 0x%" PRIx32 "", status);
if ((status & FLASH_SR__BSY) == 0)
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
@@ -1032,5 +1201,87 @@ static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank)
retval = ERROR_FAIL;
}
/* Clear but report errors */
if (status & FLASH_SR__OPTVERR) {
/* If this operation fails, we ignore it and report the original retval */
target_write_u32(target, stm32lx_info->flash_base + FLASH_SR, status & FLASH_SR__OPTVERR);
}
return retval;
}
static int stm32lx_obl_launch(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
int retval;
/* This will fail as the target gets immediately rebooted */
target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
FLASH_PECR__OBL_LAUNCH);
size_t tries = 10;
do {
target_halt(target);
retval = target_poll(target);
} while (--tries > 0 &&
(retval != ERROR_OK || target->state != TARGET_HALTED));
return tries ? ERROR_OK : ERROR_FAIL;
}
static int stm32lx_mass_erase(struct flash_bank *bank)
{
int retval;
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = NULL;
uint32_t reg32;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
stm32lx_info = bank->driver_priv;
retval = stm32lx_unlock_options_bytes(bank);
if (retval != ERROR_OK)
return retval;
/* mass erase flash memory */
/* set the RDP protection level to 1 */
retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR1);
if (retval != ERROR_OK)
return retval;
retval = stm32lx_obl_launch(bank);
if (retval != ERROR_OK)
return retval;
retval = stm32lx_unlock_options_bytes(bank);
if (retval != ERROR_OK)
return retval;
/* set the RDP protection level to 0 */
retval = target_write_u32(target, OPTION_BYTES_ADDRESS, OPTION_BYTE_0_PR0);
if (retval != ERROR_OK)
return retval;
retval = stm32lx_wait_until_bsy_clear_timeout(bank, 30000);
if (retval != ERROR_OK)
return retval;
retval = stm32lx_obl_launch(bank);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, stm32lx_info->flash_base + FLASH_PECR, &reg32);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR, reg32 | FLASH_PECR__OPTLOCK);
if (retval != ERROR_OK)
return retval;
return ERROR_OK;
}

View File

@@ -31,11 +31,18 @@
* Implements Tcl commands used to access NOR flash facilities.
*/
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
struct flash_bank **bank)
COMMAND_HELPER(flash_command_get_bank_maybe_probe, unsigned name_index,
struct flash_bank **bank, bool do_probe)
{
const char *name = CMD_ARGV[name_index];
int retval = get_flash_bank_by_name(name, bank);
int retval;
if (do_probe) {
retval = get_flash_bank_by_name(name, bank);
} else {
*bank = get_flash_bank_by_name_noprobe(name);
retval = ERROR_OK;
}
if (retval != ERROR_OK)
return retval;
if (*bank)
@@ -44,7 +51,20 @@ COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
unsigned bank_num;
COMMAND_PARSE_NUMBER(uint, name, bank_num);
return get_flash_bank_by_num(bank_num, bank);
if (do_probe) {
return get_flash_bank_by_num(bank_num, bank);
} else {
*bank = get_flash_bank_by_num_noprobe(bank_num);
retval = (bank) ? ERROR_OK : ERROR_FAIL;
return retval;
}
}
COMMAND_HELPER(flash_command_get_bank, unsigned name_index,
struct flash_bank **bank)
{
return CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe,
name_index, bank, true);
}
COMMAND_HANDLER(handle_flash_info_command)
@@ -121,7 +141,7 @@ COMMAND_HANDLER(handle_flash_probe_command)
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
retval = CALL_COMMAND_HANDLER(flash_command_get_bank_maybe_probe, 0, &p, false);
if (retval != ERROR_OK)
return retval;
@@ -794,7 +814,7 @@ COMMAND_HANDLER(handle_flash_bank_command)
int retval;
retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c);
if (ERROR_OK != retval) {
LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 "Usage %s",
LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 "; usage: %s",
driver_name, c->base, driver->usage);
free(c);
return retval;

View File

@@ -3,16 +3,28 @@
#
# program utility proc
# usage: program filename
# optional args: verify, reset and address
# optional args: verify, reset, exit and address
#
proc program_error {description exit} {
if {$exit == 1} {
echo $description
shutdown error
}
error $description
}
proc program {filename args} {
set exit 0
foreach arg $args {
if {[string equal $arg "verify"]} {
set verify 1
} elseif {[string equal $arg "reset"]} {
set reset 1
} elseif {[string equal $arg "exit"]} {
set exit 1
} else {
set address $arg
}
@@ -20,16 +32,12 @@ proc program {filename args} {
# make sure init is called
if {[catch {init}] != 0} {
echo "** OpenOCD init Failed **"
shutdown
return
program_error "** OpenOCD init failed **" 1
}
# reset target and call any init scripts
if {[catch {reset init}] != 0} {
echo "** Unable to reset target **"
shutdown
return
program_error "** Unable to reset target **" $exit
}
# start programming phase
@@ -48,7 +56,7 @@ proc program {filename args} {
if {[catch {eval verify_image $flash_args}] == 0} {
echo "** Verified OK **"
} else {
echo "** Verify Failed **"
program_error "** Verify Failed **" $exit
}
}
@@ -60,15 +68,17 @@ proc program {filename args} {
reset run
}
} else {
echo "** Programming Failed **"
program_error "** Programming Failed **" $exit
}
# shutdown OpenOCD
shutdown
if {$exit == 1} {
shutdown
}
return
}
add_help_text program "write an image to flash, address is only required for binary images. verify, reset are optional"
add_usage_text program "<filename> \[address\] \[verify\] \[reset\]"
add_help_text program "write an image to flash, address is only required for binary images. verify, reset, exit are optional"
add_usage_text program "<filename> \[address\] \[verify\] \[reset\] \[exit\]"
# stm32f0x uses the same flash driver as the stm32f1x
# this alias enables the use of either name.

View File

@@ -44,18 +44,9 @@ noinst_HEADERS = \
replacements.h \
fileio.h \
system.h \
bin2char.c \
bin2char.sh \
jim-nvp.h
EXTRA_DIST = startup.tcl
BIN2C = bin2char$(EXEEXT_FOR_BUILD)
BUILT_SOURCES = $(BIN2C)
$(BIN2C): bin2char.c
${CC_FOR_BUILD} ${CFLAGS_FOR_BUILD} $(srcdir)/bin2char.c -o $@
CLEANFILES = bin2char$(EXEEXT_FOR_BUILD)
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

14
src/helper/bin2char.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
[ $# != 0 ] && {
echo "Usage: $0"
echo
echo "Read binary data from standard input and write it as a comma separated"
echo "list of hexadecimal byte values to standard ouput. The output is usable"
echo "as a C array initializer. It is terminated with a comma so it can be"
echo "continued e.g. for zero termination."
exit 1
}
echo "/* Autogenerated with $0 */"
od -v -A n -t x1 | sed 's/ *\(..\) */0x\1,/g'

View File

@@ -231,7 +231,7 @@ char *buf_to_str(const void *_buf, unsigned buf_len, unsigned radix)
}
}
const char *DIGITS = "0123456789ABCDEF";
const char * const DIGITS = "0123456789ABCDEF";
for (unsigned j = 0; j < str_len; j++)
str[j] = DIGITS[(int)str[j]];

View File

@@ -39,7 +39,7 @@
* @param num The number of bits from @c value to copy (1-32).
* @param value Up to 32 bits that will be copied to _buffer.
*/
static inline void buf_set_u32(void *_buffer,
static inline void buf_set_u32(uint8_t *_buffer,
unsigned first, unsigned num, uint32_t value)
{
uint8_t *buffer = _buffer;
@@ -68,7 +68,7 @@ static inline void buf_set_u32(void *_buffer,
* @param num The number of bits from @c value to copy (1-64).
* @param value Up to 64 bits that will be copied to _buffer.
*/
static inline void buf_set_u64(void *_buffer,
static inline void buf_set_u64(uint8_t *_buffer,
unsigned first, unsigned num, uint64_t value)
{
uint8_t *buffer = _buffer;
@@ -106,7 +106,7 @@ static inline void buf_set_u64(void *_buffer,
* @param num The number of bits from @c _buffer to read (1-32).
* @returns Up to 32-bits that were read from @c _buffer.
*/
static inline uint32_t buf_get_u32(const void *_buffer,
static inline uint32_t buf_get_u32(const uint8_t *_buffer,
unsigned first, unsigned num)
{
const uint8_t *buffer = _buffer;
@@ -135,7 +135,7 @@ static inline uint32_t buf_get_u32(const void *_buffer,
* @param num The number of bits from @c _buffer to read (1-64).
* @returns Up to 64-bits that were read from @c _buffer.
*/
static inline uint64_t buf_get_u64(const void *_buffer,
static inline uint64_t buf_get_u64(const uint8_t *_buffer,
unsigned first, unsigned num)
{
const uint8_t *buffer = _buffer;

View File

@@ -121,7 +121,7 @@ static int command_retval_set(Jim_Interp *interp, int retval)
if (return_retval != NULL)
*return_retval = retval;
return (retval == ERROR_OK) ? JIM_OK : JIM_ERR;
return (retval == ERROR_OK) ? JIM_OK : retval;
}
extern struct command_context *global_cmd_ctx;
@@ -365,7 +365,7 @@ static int register_command_handler(struct command_context *cmd_ctx,
LOG_DEBUG("registering '%s'...", ocd_name);
Jim_CmdProc func = c->handler ? &script_command : &command_unknown;
Jim_CmdProc *func = c->handler ? &script_command : &command_unknown;
int retval = Jim_CreateCommand(interp, ocd_name, func, c, NULL);
free(ocd_name);
if (JIM_OK != retval)
@@ -659,21 +659,7 @@ int command_run_line(struct command_context *context, char *line)
}
Jim_DeleteAssocData(interp, "context");
}
if (retcode == JIM_ERR) {
if (retval != ERROR_COMMAND_CLOSE_CONNECTION) {
/* We do not print the connection closed error message */
Jim_MakeErrorMessage(interp);
LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
}
if (retval == ERROR_OK) {
/* It wasn't a low level OpenOCD command that failed */
return ERROR_FAIL;
}
return retval;
} else if (retcode == JIM_EXIT) {
/* ignore.
* exit(Jim_GetExitCode(interp)); */
} else {
if (retcode == JIM_OK) {
const char *result;
int reslen;
@@ -693,7 +679,22 @@ int command_run_line(struct command_context *context, char *line)
LOG_USER_N("\n");
}
retval = ERROR_OK;
} else if (retcode == JIM_EXIT) {
/* ignore.
* exit(Jim_GetExitCode(interp)); */
} else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) {
return retcode;
} else {
Jim_MakeErrorMessage(interp);
LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL));
if (retval == ERROR_OK) {
/* It wasn't a low level OpenOCD command that failed */
return ERROR_FAIL;
}
return retval;
}
return retval;
}
@@ -1070,8 +1071,10 @@ static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Jim_SetResultString(interp, "native", -1);
else if (c->handler)
Jim_SetResultString(interp, "simple", -1);
else
else if (remaining == 0)
Jim_SetResultString(interp, "group", -1);
else
Jim_SetResultString(interp, "unknown", -1);
return JIM_OK;
}

View File

@@ -168,7 +168,7 @@ struct command {
struct command *parent;
struct command *children;
command_handler_t handler;
Jim_CmdProc jim_handler;
Jim_CmdProc *jim_handler;
void *jim_handler_data;
enum command_mode mode;
struct command *next;
@@ -204,7 +204,7 @@ char *command_name(struct command *c, char delim);
struct command_registration {
const char *name;
command_handler_t handler;
Jim_CmdProc jim_handler;
Jim_CmdProc *jim_handler;
void *jim_handler_data;
enum command_mode mode;
const char *help;

View File

@@ -52,7 +52,7 @@ static long long current_time;
static long long start;
static char *log_strings[5] = {
static const char * const log_strings[5] = {
"User : ",
"Error: ",
"Warn : ", /* want a space after each colon, all same width, colons aligned */

View File

@@ -138,5 +138,7 @@ extern int debug_level;
* make no assumptions about what went wrong and try to handle the problem.
*/
#define ERROR_FAIL (-4)
#define ERROR_WAIT (-5)
#endif /* LOG_H */

View File

@@ -141,7 +141,6 @@ static void add_default_dirs(void)
int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
{
int c;
char command_buffer[128];
while (1) {
/* getopt_long stores the option index here. */
@@ -164,24 +163,26 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
break;
case 'f': /* --file | -f */
{
snprintf(command_buffer, 128, "script {%s}", optarg);
add_config_command(command_buffer);
char *command = alloc_printf("script {%s}", optarg);
add_config_command(command);
free(command);
break;
}
case 's': /* --search | -s */
add_script_search_dir(optarg);
break;
case 'd': /* --debug | -d */
if (optarg)
snprintf(command_buffer, 128, "debug_level %s", optarg);
else
snprintf(command_buffer, 128, "debug_level 3");
command_run_line(cmd_ctx, command_buffer);
{
char *command = alloc_printf("debug_level %s", optarg ? optarg : "3");
command_run_line(cmd_ctx, command);
free(command);
break;
}
case 'l': /* --log_output | -l */
if (optarg) {
snprintf(command_buffer, 128, "log_output %s", optarg);
command_run_line(cmd_ctx, command_buffer);
char *command = alloc_printf("log_output %s", optarg);
command_run_line(cmd_ctx, command);
free(command);
}
break;
case 'c': /* --command | -c */

View File

@@ -135,7 +135,6 @@ static inline unsigned usleep(unsigned int usecs)
/* Windows specific */
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <time.h>

View File

@@ -16,10 +16,12 @@ proc exit {} {
proc ocd_bouncer {name args} {
set cmd [format "ocd_%s" $name]
set type [eval ocd_command type $cmd $args]
set errcode error
if {$type == "native"} {
return [eval $cmd $args]
} else {if {$type == "simple"} {
if {[catch {eval $cmd $args}] == 0} {
set errcode [catch {eval $cmd $args}]
if {$errcode == 0} {
return ""
} else {
# 'classic' commands output error message as part of progress output
@@ -30,9 +32,9 @@ proc ocd_bouncer {name args} {
set errmsg [format "%s: command requires more arguments" \
[concat $name " " $args]]
} else {
set errmsg [format "Unknown command type: %s" $type]
set errmsg [format "invalid subcommand \"%s\"" $args]
}}}
return -code error $errmsg
return -code $errcode $errmsg
}
# Try flipping / and \ to find file if the filename does not

View File

@@ -270,6 +270,25 @@ static inline void buf_bswap32(uint8_t *dst, const uint8_t *src, size_t len)
}
}
/**
* Calculate the (even) parity of a 32-bit datum.
* @param x The datum.
* @return 1 if the number of set bits in x is odd, 0 if it is even.
*/
static inline int parity_u32(uint32_t x)
{
#ifdef __GNUC__
return __builtin_parityl(x);
#else
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return x & 1;
#endif
}
#if defined(__ECOS)
/* eCos plain lacks these definition... A series of upstream patches

View File

@@ -48,7 +48,7 @@
*/
extern struct jtag_interface *jtag_interface;
const char *jtag_only[] = { "jtag", NULL };
const char * const jtag_only[] = { "jtag", NULL };
static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
{

View File

@@ -31,7 +31,7 @@
#include "aice_usb.h"
#define AICE_KHZ_TO_SPEED_MAP_SIZE 16
static int aice_khz_to_speed_map[AICE_KHZ_TO_SPEED_MAP_SIZE] = {
static const int aice_khz_to_speed_map[AICE_KHZ_TO_SPEED_MAP_SIZE] = {
30000,
15000,
7500,

View File

@@ -22,9 +22,9 @@
struct aice_interface_param_s {
/** */
char *device_desc;
const char *device_desc;
/** */
char *serial;
const char *serial;
/** */
uint16_t vid;
/** */

View File

@@ -106,9 +106,9 @@ enum aice_command_mode {
struct aice_port_param_s {
/** */
char *device_desc;
const char *device_desc;
/** */
char *serial;
const char *serial;
/** */
uint16_t vid;
/** */
@@ -225,7 +225,7 @@ struct aice_port_api_s {
/** */
struct aice_port {
/** */
char *name;
const char *name;
/** */
int type;
/** */

View File

@@ -2099,7 +2099,7 @@ static int aice_usb_open(struct aice_port_param_s *param)
const uint16_t pids[] = { param->pid, 0 };
struct jtag_libusb_device_handle *devh;
if (jtag_libusb_open(vids, pids, &devh) != ERROR_OK)
if (jtag_libusb_open(vids, pids, NULL, &devh) != ERROR_OK)
return ERROR_FAIL;
/* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
@@ -2123,7 +2123,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, &devh)) != ERROR_OK) {
while ((retval = jtag_libusb_open(vids, pids, NULL, &devh)) != ERROR_OK) {
usleep(1000);
timeout--;
if (!timeout)
@@ -2136,13 +2136,11 @@ static int aice_usb_open(struct aice_port_param_s *param)
#endif
/* usb_set_configuration required under win32 */
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
jtag_libusb_set_configuration(devh, 0);
jtag_libusb_claim_interface(devh, 0);
unsigned int aice_read_ep;
unsigned int aice_write_ep;
jtag_libusb_get_endpoints(udev, &aice_read_ep, &aice_write_ep);
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1);
aice_handler.usb_read_ep = aice_read_ep;
aice_handler.usb_write_ep = aice_write_ep;

View File

@@ -90,11 +90,6 @@ static int jtag_srst = -1;
* List all TAPs that have been created.
*/
static struct jtag_tap *__jtag_all_taps;
/**
* The number of TAPs in the __jtag_all_taps list, used to track the
* assigned chain position to new TAPs
*/
static unsigned jtag_num_taps;
static enum reset_types jtag_reset_config = RESET_NONE;
tap_state_t cmd_queue_cur_state = TAP_RESET;
@@ -166,6 +161,9 @@ bool is_jtag_poll_safe(void)
* It is also implicitly disabled while TRST is active and
* while SRST is gating the JTAG clock.
*/
if (!transport_is_jtag())
return jtag_poll;
if (!jtag_poll || jtag_trst != 0)
return false;
return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING);
@@ -190,7 +188,13 @@ struct jtag_tap *jtag_all_taps(void)
unsigned jtag_tap_count(void)
{
return jtag_num_taps;
struct jtag_tap *t = jtag_all_taps();
unsigned n = 0;
while (t) {
n++;
t = t->next_tap;
}
return n;
}
unsigned jtag_tap_count_enabled(void)
@@ -208,12 +212,15 @@ unsigned jtag_tap_count_enabled(void)
/** Append a new TAP to the chain of all taps. */
void jtag_tap_add(struct jtag_tap *t)
{
t->abs_chain_position = jtag_num_taps++;
unsigned jtag_num_taps = 0;
struct jtag_tap **tap = &__jtag_all_taps;
while (*tap != NULL)
while (*tap != NULL) {
jtag_num_taps++;
tap = &(*tap)->next_tap;
}
*tap = t;
t->abs_chain_position = jtag_num_taps;
}
/* returns a pointer to the n-th device in the scan chain */
@@ -642,6 +649,12 @@ void swd_add_reset(int req_srst)
if (adapter_nsrst_delay)
jtag_add_sleep(adapter_nsrst_delay * 1000);
}
retval = jtag_execute_queue();
if (retval != ERROR_OK) {
LOG_ERROR("SRST timings error");
return;
}
}
}
@@ -879,11 +892,7 @@ void jtag_sleep(uint32_t us)
alive_sleep((us+999)/1000);
}
/* Maximum number of enabled JTAG devices we expect in the scan chain,
* plus one (to detect garbage at the end). Devices that don't support
* IDCODE take up fewer bits, possibly allowing a few more devices.
*/
#define JTAG_MAX_CHAIN_SIZE 20
#define JTAG_MAX_AUTO_TAPS 20
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
@@ -906,7 +915,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod
};
/* initialize to the end of chain ID value */
for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
for (unsigned i = 0; i < num_idcode; i++)
buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG);
jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE);
@@ -991,21 +1000,16 @@ static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma
static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
{
uint32_t idcode = tap->idcode;
/* ignore expected BYPASS codes; warn otherwise */
if (0 == tap->expected_ids_cnt && !idcode)
if (tap->expected_ids_cnt == 0 || !tap->hasidcode)
return true;
/* optionally ignore the JTAG version field - bits 28-31 of IDCODE */
uint32_t mask = tap->ignore_version ? ~(0xf << 28) : ~0;
idcode &= mask;
uint32_t idcode = tap->idcode & mask;
/* Loop over the expected identification codes and test for a match */
unsigned ii, limit = tap->expected_ids_cnt;
for (ii = 0; ii < limit; ii++) {
for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
uint32_t expected = tap->expected_ids[ii] & mask;
if (idcode == expected)
@@ -1019,10 +1023,10 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
/* If none of the expected ids matched, warn */
jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED",
tap->dotted_name, tap->idcode);
for (ii = 0; ii < limit; ii++) {
for (unsigned ii = 0; ii < tap->expected_ids_cnt; ii++) {
char msg[32];
snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit);
snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, tap->expected_ids_cnt);
jtag_examine_chain_display(LOG_LVL_ERROR, msg,
tap->dotted_name, tap->expected_ids[ii]);
}
@@ -1034,130 +1038,108 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap)
*/
static int jtag_examine_chain(void)
{
uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
unsigned bit_count;
int retval;
int tapcount = 0;
bool autoprobe = false;
unsigned max_taps = jtag_tap_count();
/* Autoprobe up to this many. */
if (max_taps < JTAG_MAX_AUTO_TAPS)
max_taps = JTAG_MAX_AUTO_TAPS;
/* Add room for end-of-chain marker. */
max_taps++;
uint8_t *idcode_buffer = malloc(max_taps * 4);
if (idcode_buffer == NULL)
return ERROR_JTAG_INIT_FAILED;
/* DR scan to collect BYPASS or IDCODE register contents.
* Then make sure the scan data has both ones and zeroes.
*/
LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS");
retval = jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
retval = jtag_examine_chain_execute(idcode_buffer, max_taps);
if (retval != ERROR_OK)
return retval;
if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
return ERROR_JTAG_INIT_FAILED;
goto out;
if (!jtag_examine_chain_check(idcode_buffer, max_taps)) {
retval = ERROR_JTAG_INIT_FAILED;
goto out;
}
/* point at the 1st tap */
/* Point at the 1st predefined tap, if any */
struct jtag_tap *tap = jtag_tap_next_enabled(NULL);
if (!tap)
autoprobe = true;
for (bit_count = 0;
tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
tap = jtag_tap_next_enabled(tap)) {
unsigned bit_count = 0;
unsigned autocount = 0;
for (unsigned i = 0; i < max_taps; i++) {
assert(bit_count < max_taps * 32);
uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32);
/* No predefined TAP? Auto-probe. */
if (tap == NULL) {
/* Is there another TAP? */
if (jtag_idcode_is_final(idcode))
break;
/* Default everything in this TAP except IR length.
*
* REVISIT create a jtag_alloc(chip, tap) routine, and
* share it with jim_newtap_cmd().
*/
tap = calloc(1, sizeof *tap);
if (!tap) {
retval = ERROR_FAIL;
goto out;
}
tap->chip = alloc_printf("auto%u", autocount++);
tap->tapname = strdup("tap");
tap->dotted_name = alloc_printf("%s.%s", tap->chip, tap->tapname);
tap->ir_length = 0; /* ... signifying irlen autoprobe */
tap->ir_capture_mask = 0x03;
tap->ir_capture_value = 0x01;
tap->enabled = true;
jtag_tap_init(tap);
}
if ((idcode & 1) == 0) {
/* Zero for LSB indicates a device in bypass */
LOG_INFO("TAP %s does not have IDCODE",
tap->dotted_name);
idcode = 0;
LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name);
tap->hasidcode = false;
tap->idcode = 0;
bit_count += 1;
} else {
/* Friendly devices support IDCODE */
tap->hasidcode = true;
jtag_examine_chain_display(LOG_LVL_INFO,
"tap/device found",
tap->dotted_name, idcode);
tap->idcode = idcode;
jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode);
bit_count += 32;
}
tap->idcode = idcode;
/* ensure the TAP ID matches what was expected */
if (!jtag_examine_chain_match_tap(tap))
retval = ERROR_JTAG_INIT_SOFT_FAIL;
}
/* Fail if too many TAPs were enabled for us to verify them all. */
if (tap) {
LOG_ERROR("Too many TAPs enabled; '%s' ignored.",
tap->dotted_name);
return ERROR_JTAG_INIT_FAILED;
}
/* if autoprobing, the tap list is still empty ... populate it! */
while (autoprobe && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31) {
uint32_t idcode;
char buf[12];
/* Is there another TAP? */
idcode = buf_get_u32(idcode_buffer, bit_count, 32);
if (jtag_idcode_is_final(idcode))
break;
/* Default everything in this TAP except IR length.
*
* REVISIT create a jtag_alloc(chip, tap) routine, and
* share it with jim_newtap_cmd().
*/
tap = calloc(1, sizeof *tap);
if (!tap)
return ERROR_FAIL;
sprintf(buf, "auto%d", tapcount++);
tap->chip = strdup(buf);
tap->tapname = strdup("tap");
sprintf(buf, "%s.%s", tap->chip, tap->tapname);
tap->dotted_name = strdup(buf);
/* tap->ir_length == 0 ... signifying irlen autoprobe */
tap->ir_capture_mask = 0x03;
tap->ir_capture_value = 0x01;
tap->enabled = true;
if ((idcode & 1) == 0) {
bit_count += 1;
tap->hasidcode = false;
} else {
bit_count += 32;
tap->hasidcode = true;
tap->idcode = idcode;
tap->expected_ids_cnt = 1;
tap->expected_ids = malloc(sizeof(uint32_t));
tap->expected_ids[0] = idcode;
}
LOG_WARNING("AUTO %s - use \"jtag newtap "
"%s %s -expected-id 0x%8.8" PRIx32 " ...\"",
tap->dotted_name, tap->chip, tap->tapname,
tap->idcode);
jtag_tap_init(tap);
tap = jtag_tap_next_enabled(tap);
}
/* After those IDCODE or BYPASS register values should be
* only the data we fed into the scan chain.
*/
if (jtag_examine_chain_end(idcode_buffer, bit_count,
8 * sizeof(idcode_buffer))) {
LOG_ERROR("double-check your JTAG setup (interface, "
"speed, missing TAPs, ...)");
return ERROR_JTAG_INIT_FAILED;
if (jtag_examine_chain_end(idcode_buffer, bit_count, max_taps * 32)) {
LOG_ERROR("double-check your JTAG setup (interface, speed, ...)");
retval = ERROR_JTAG_INIT_FAILED;
goto out;
}
/* Return success or, for backwards compatibility if only
* some IDCODE values mismatched, a soft/continuable fault.
*/
out:
free(idcode_buffer);
return retval;
}
@@ -1220,7 +1202,7 @@ static int jtag_validate_ircapture(void)
* least two bits. Guessing will fail if (a) any TAP does
* not conform to the JTAG spec; or (b) when the upper bits
* captured from some conforming TAP are nonzero. Or if
* (c) an IR length is longer than 32 bits -- which is only
* (c) an IR length is longer than JTAG_IRLEN_MAX bits,
* an implementation limit, which could someday be raised.
*
* REVISIT optimization: if there's a *single* TAP we can
@@ -1235,11 +1217,12 @@ static int jtag_validate_ircapture(void)
if (tap->ir_length == 0) {
tap->ir_length = 2;
while ((val = buf_get_u64(ir_test, chain_pos, tap->ir_length + 1)) == 1
&& tap->ir_length <= 64) {
&& tap->ir_length < JTAG_IRLEN_MAX) {
tap->ir_length++;
}
LOG_WARNING("AUTO %s - use \"... -irlen %d\"",
jtag_tap_name(tap), tap->ir_length);
LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -irlen %d "
"-expected-id 0x%08" PRIx32 "\"",
tap->dotted_name, tap->chip, tap->tapname, tap->ir_length, tap->idcode);
}
/* Validate the two LSBs, which must be 01 per JTAG spec.
@@ -1323,9 +1306,10 @@ void jtag_tap_free(struct jtag_tap *tap)
{
jtag_unregister_event_callback(&jtag_reset_callback, tap);
/** @todo is anything missing? no memory leaks please */
free(tap->expected);
free(tap->expected_mask);
free(tap->expected_ids);
free(tap->cur_instr);
free(tap->chip);
free(tap->tapname);
free(tap->dotted_name);
@@ -1544,11 +1528,12 @@ int jtag_init_reset(struct command_context *cmd_ctx)
* REVISIT once Tcl code can read the reset_config modes, this won't
* need to be a C routine at all...
*/
jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
if (jtag_reset_config & RESET_HAS_SRST) {
jtag_add_reset(1, 1);
if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0)
jtag_add_reset(0, 1);
} else {
jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */
}
/* some targets enable us to connect with srst asserted */
@@ -1822,8 +1807,6 @@ void adapter_assert_reset(void)
jtag_add_reset(0, 1);
} else if (transport_is_swd())
swd_add_reset(1);
else if (transport_is_cmsis_dap())
swd_add_reset(1); /* FIXME */
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
@@ -1837,11 +1820,31 @@ void adapter_deassert_reset(void)
jtag_add_reset(0, 0);
else if (transport_is_swd())
swd_add_reset(0);
else if (transport_is_cmsis_dap())
swd_add_reset(0); /* FIXME */
else if (get_current_transport() != NULL)
LOG_ERROR("reset is not supported on %s",
get_current_transport()->name);
else
LOG_ERROR("transport is not selected");
}
int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (jtag->config_trace)
return jtag->config_trace(enabled, pin_protocol, port_size,
trace_freq);
else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
}
return ERROR_OK;
}
int adapter_poll_trace(uint8_t *buf, size_t *size)
{
if (jtag->poll_trace)
return jtag->poll_trace(buf, size);
return ERROR_FAIL;
}

View File

@@ -124,7 +124,7 @@ static const int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA;
* 4: Shift-IR
* 5: Pause-IR
*/
static uint8_t amt_jtagaccel_tap_move[6][6][2] = {
static const uint8_t amt_jtagaccel_tap_move[6][6][2] = {
/* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */
{ {0x1f, 0x00}, {0x0f, 0x00}, {0x05, 0x00}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00} }, /* RESET */
{ {0x1f, 0x00}, {0x00, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x0b, 0x00} }, /* IDLE */

View File

@@ -79,7 +79,7 @@
#define P31 (1 << 31)
struct device_t {
char *name;
const char *name;
int TDO_PIO; /* PIO holding TDO */
uint32_t TDO_MASK; /* TDO bitmask */
int TRST_PIO; /* PIO holding TRST */
@@ -94,7 +94,7 @@ struct device_t {
uint32_t SRST_MASK; /* SRST bitmask */
};
static struct device_t devices[] = {
static const struct device_t devices[] = {
{ "rea_ecr", PIOD, P27, PIOA, NC, PIOD, P23, PIOD, P24, PIOD, P26, PIOC, P5 },
{ .name = NULL },
};
@@ -104,7 +104,7 @@ static char *at91rm9200_device;
/* interface variables
*/
static struct device_t *device;
static const struct device_t *device;
static int dev_mem_fd;
static void *sys_controller;
static uint32_t *pio_base;
@@ -196,7 +196,7 @@ struct jtag_interface at91rm9200_interface = {
static int at91rm9200_init(void)
{
struct device_t *cur_device;
const struct device_t *cur_device;
cur_device = devices;

View File

@@ -21,6 +21,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
/* 2014-12: Addition of the SWD protocol support is based on the initial work
* by Paul Fertser and modifications by Jean-Christian de Rivaz. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -29,6 +32,9 @@
#include <jtag/interface.h>
#include <jtag/commands.h>
/* YUK! - but this is currently a global.... */
extern struct jtag_interface *jtag_interface;
/**
* Function bitbang_stableclocks
* issues a number of clock cycles while staying in a stable state.
@@ -337,3 +343,209 @@ int bitbang_execute_queue(void)
return retval;
}
bool swd_mode;
static int queued_retval;
static int bitbang_swd_init(void)
{
LOG_DEBUG("bitbang_swd_init");
swd_mode = true;
return ERROR_OK;
}
static void bitbang_exchange(bool rnw, uint8_t buf[], unsigned int offset, unsigned int bit_cnt)
{
LOG_DEBUG("bitbang_exchange");
int tdi;
for (unsigned int i = offset; i < bit_cnt + offset; i++) {
int bytec = i/8;
int bcval = 1 << (i % 8);
tdi = !rnw && (buf[bytec] & bcval);
bitbang_interface->write(0, 0, tdi);
if (rnw && buf) {
if (bitbang_interface->swdio_read())
buf[bytec] |= bcval;
else
buf[bytec] &= ~bcval;
}
bitbang_interface->write(1, 0, tdi);
}
}
int bitbang_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
{
LOG_DEBUG("bitbang_swd_switch_seq");
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
bitbang_exchange(false, (uint8_t *)swd_seq_line_reset, 0, swd_seq_line_reset_len);
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
bitbang_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len);
break;
case SWD_TO_JTAG:
LOG_DEBUG("SWD-to-JTAG");
bitbang_exchange(false, (uint8_t *)swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len);
break;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
return ERROR_OK;
}
void bitbang_switch_to_swd(void)
{
LOG_DEBUG("bitbang_switch_to_swd");
bitbang_exchange(false, (uint8_t *)swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len);
}
static void swd_clear_sticky_errors(struct adiv5_dap *dap)
{
const struct swd_driver *swd = jtag_interface->swd;
assert(swd);
swd->write_reg(dap, swd_cmd(false, false, DP_ABORT),
STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR);
}
static void bitbang_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
{
LOG_DEBUG("bitbang_swd_read_reg");
assert(cmd & SWD_CMD_RnW);
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skip bitbang_swd_read_reg because queued_retval=%d", queued_retval);
return;
}
for (;;) {
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
cmd |= SWD_CMD_START | (1 << 7);
bitbang_exchange(false, &cmd, 0, 8);
bitbang_interface->swdio_drive(false);
bitbang_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 32 + 1 + 1);
bitbang_interface->swdio_drive(true);
int ack = buf_get_u32(trn_ack_data_parity_trn, 1, 3);
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,
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 (parity != parity_u32(data)) {
LOG_DEBUG("Wrong parity detected");
queued_retval = ERROR_FAIL;
return;
}
if (value)
*value = data;
if (cmd & SWD_CMD_APnDP)
bitbang_exchange(true, NULL, 0, dap->memaccess_tck);
return;
case SWD_ACK_WAIT:
LOG_DEBUG("SWD_ACK_WAIT");
swd_clear_sticky_errors(dap);
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;
}
}
}
static void bitbang_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
{
LOG_DEBUG("bitbang_swd_write_reg");
assert(!(cmd & SWD_CMD_RnW));
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skip bitbang_swd_write_reg because queued_retval=%d", queued_retval);
return;
}
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);
bitbang_exchange(false, &cmd, 0, 8);
bitbang_interface->swdio_drive(false);
bitbang_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 1);
bitbang_interface->swdio_drive(true);
bitbang_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,
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 (cmd & SWD_CMD_APnDP)
bitbang_exchange(true, NULL, 0, dap->memaccess_tck);
return;
case SWD_ACK_WAIT:
LOG_DEBUG("SWD_ACK_WAIT");
swd_clear_sticky_errors(dap);
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;
}
}
}
static int bitbang_swd_run_queue(struct adiv5_dap *dap)
{
LOG_DEBUG("bitbang_swd_run_queue");
/* A transaction must be followed by another transaction or at least 8 idle cycles to
* ensure that data is clocked through the AP. */
bitbang_exchange(true, NULL, 0, 8);
int retval = queued_retval;
queued_retval = ERROR_OK;
LOG_DEBUG("SWD queue return value: %02x", retval);
return retval;
}
const struct swd_driver bitbang_swd = {
.init = bitbang_swd_init,
.switch_seq = bitbang_swd_switch_seq,
.read_reg = bitbang_swd_read_reg,
.write_reg = bitbang_swd_write_reg,
.run = bitbang_swd_run_queue,
};

View File

@@ -24,6 +24,8 @@
#ifndef BITBANG_H
#define BITBANG_H
#include <jtag/swd.h>
struct bitbang_interface {
/* low level callbacks (for bitbang)
*/
@@ -31,10 +33,18 @@ struct bitbang_interface {
void (*write)(int tck, int tms, int tdi);
void (*reset)(int trst, int srst);
void (*blink)(int on);
int (*swdio_read)(void);
void (*swdio_drive)(bool on);
};
const struct swd_driver bitbang_swd;
extern bool swd_mode;
int bitbang_execute_queue(void);
extern struct bitbang_interface *bitbang_interface;
void bitbang_switch_to_swd(void);
int bitbang_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
#endif /* BITBANG_H */

View File

@@ -42,6 +42,7 @@ static void buspirate_path_move(int num_states, tap_state_t *path);
static void buspirate_runtest(int num_cycles);
static void buspirate_scan(bool ir_scan, enum scan_type type,
uint8_t *buffer, int scan_size, struct scan_command *command);
static void buspirate_stableclocks(int num_cycles);
#define CMD_UNKNOWN 0x00
#define CMD_PORT_MODE 0x01
@@ -192,6 +193,10 @@ static int buspirate_execute_queue(void)
buspirate_tap_execute();
jtag_sleep(cmd->cmd.sleep->us);
break;
case JTAG_STABLECLOCKS:
DEBUG_JTAG_IO("stable clock %i cycles", cmd->cmd.stableclocks->num_cycles);
buspirate_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
default:
LOG_ERROR("BUG: unknown JTAG command type encountered");
exit(-1);
@@ -602,6 +607,16 @@ static void buspirate_scan(bool ir_scan, enum scan_type type,
buspirate_state_move();
}
static void buspirate_stableclocks(int num_cycles)
{
int i;
int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
buspirate_tap_make_space(0, num_cycles);
for (i = 0; i < num_cycles; i++)
buspirate_tap_append(tms, 0);
}
/************************* TAP related stuff **********/

View File

@@ -1,4 +1,7 @@
/***************************************************************************
* Copyright (C) 2014 by Paul Fertser *
* fercerpav@gmail.com *
* *
* Copyright (C) 2013 by mike brown *
* mike@theshedworks.org.uk *
* *
@@ -33,12 +36,6 @@
#include <hidapi.h>
#ifdef _DEBUG_JTAG_IO_
#define DEBUG_IO(expr...) LOG_DEBUG(expr)
#else
#define DEBUG_IO(expr...) do {} while (0)
#endif
/*
* See CMSIS-DAP documentation:
* Version 0.01 - Beta.
@@ -60,6 +57,8 @@
/* vid = pid = 0 marks the end of the list */
static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 };
static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 };
static wchar_t *cmsis_dap_serial;
static bool swd_mode;
#define PACKET_SIZE (64 + 1) /* 64 bytes plus report id */
#define USB_TIMEOUT 1000
@@ -136,7 +135,7 @@ static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 };
/* CMSIS-DAP Vendor Commands
* None as yet... */
static char *info_caps_str[] = {
static const char * const info_caps_str[] = {
"SWD Supported",
"JTAG Supported"
};
@@ -153,6 +152,17 @@ struct cmsis_dap {
uint8_t mode;
};
struct pending_transfer_result {
uint8_t cmd;
uint32_t data;
void *buffer;
};
static int pending_transfer_count, pending_queue_len;
static struct pending_transfer_result *pending_transfers;
static int queued_retval;
static struct cmsis_dap *cmsis_dap_handle;
static int cmsis_dap_usb_open(void)
@@ -161,15 +171,19 @@ static int cmsis_dap_usb_open(void)
int i;
struct hid_device_info *devs, *cur_dev;
unsigned short target_vid, target_pid;
wchar_t *target_serial = NULL;
bool found = false;
bool serial_found = false;
target_vid = 0;
target_pid = 0;
/*
The CMSIS-DAP specification stipulates:
"The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
debuggers to idenify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
*/
* The CMSIS-DAP specification stipulates:
* "The Product String must contain "CMSIS-DAP" somewhere in the string. This is used by the
* debuggers to identify a CMSIS-DAP compliant Debug Unit that is connected to a host computer."
*/
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (NULL != cur_dev) {
@@ -178,21 +192,34 @@ static int cmsis_dap_usb_open(void)
LOG_DEBUG("Cannot read product string of device 0x%x:0x%x",
cur_dev->vendor_id, cur_dev->product_id);
} else {
if (wcsstr(cur_dev->product_string, L"CMSIS-DAP"))
/*
if the user hasn't specified VID:PID *and*
product string contains "CMSIS-DAP", pick it
*/
break;
if (wcsstr(cur_dev->product_string, L"CMSIS-DAP")) {
/* if the user hasn't specified VID:PID *and*
* product string contains "CMSIS-DAP", pick it
*/
found = true;
}
}
} else {
/*
otherwise, exhaustively compare against all VID:PID in list
*/
/* otherwise, exhaustively compare against all VID:PID in list */
for (i = 0; cmsis_dap_vid[i] || cmsis_dap_pid[i]; i++) {
if ((cmsis_dap_vid[i] == cur_dev->vendor_id) && (cmsis_dap_pid[i] == cur_dev->product_id))
break;
found = true;
}
if (cmsis_dap_vid[i] || cmsis_dap_pid[i])
found = true;
}
if (found) {
/* we have found an adapter, so exit further checks */
/* check serial number matches if given */
if (cmsis_dap_serial != NULL) {
if (wcscmp(cmsis_dap_serial, cur_dev->serial_number) == 0) {
serial_found = true;
break;
}
} else
break;
}
cur_dev = cur_dev->next;
@@ -201,19 +228,26 @@ static int cmsis_dap_usb_open(void)
if (NULL != cur_dev) {
target_vid = cur_dev->vendor_id;
target_pid = cur_dev->product_id;
if (serial_found)
target_serial = cmsis_dap_serial;
}
hid_free_enumeration(devs);
if (target_vid == 0 && target_pid == 0) {
LOG_ERROR("unable to find CMSIS-DAP device");
return ERROR_FAIL;
}
if (hid_init() != 0) {
LOG_ERROR("unable to open HIDAPI");
return ERROR_FAIL;
}
dev = hid_open(target_vid, target_pid, NULL);
dev = hid_open(target_vid, target_pid, target_serial);
if (dev == NULL) {
LOG_ERROR("unable to open CMSIS-DAP device");
LOG_ERROR("unable to open CMSIS-DAP device 0x%x:0x%x", target_vid, target_pid);
return ERROR_FAIL;
}
@@ -237,6 +271,8 @@ static int cmsis_dap_usb_open(void)
int packet_size = PACKET_SIZE;
/* atmel cmsis-dap uses 512 byte reports */
/* TODO: HID report descriptor should be parsed instead of
* hardcoding a match by VID */
if (target_vid == 0x03eb)
packet_size = 512 + 1;
@@ -256,13 +292,13 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
hid_close(dap->dev_handle);
hid_exit();
if (cmsis_dap_handle->packet_buffer)
free(cmsis_dap_handle->packet_buffer);
if (cmsis_dap_handle) {
free(cmsis_dap_handle);
cmsis_dap_handle = NULL;
}
free(cmsis_dap_handle->packet_buffer);
free(cmsis_dap_handle);
cmsis_dap_handle = NULL;
free(cmsis_dap_serial);
cmsis_dap_serial = NULL;
free(pending_transfers);
pending_transfers = NULL;
return;
}
@@ -271,7 +307,7 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
{
/* Pad the rest of the TX buffer with 0's */
memset(dap->packet_buffer + txlen, 0, dap->packet_size - 1 - txlen);
memset(dap->packet_buffer + txlen, 0, dap->packet_size - txlen);
/* write data to device */
int retval = hid_write(dap->dev_handle, dap->packet_buffer, dap->packet_size);
@@ -418,7 +454,7 @@ static int cmsis_dap_cmd_DAP_Disconnect(void)
return ERROR_OK;
}
static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t delay, uint16_t retry)
static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t retry_count, uint16_t match_retry)
{
int retval;
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
@@ -426,10 +462,10 @@ static int cmsis_dap_cmd_DAP_TFER_Configure(uint8_t idle, uint16_t delay, uint16
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_TFER_CONFIGURE;
buffer[2] = idle;
buffer[3] = delay & 0xff;
buffer[4] = (delay >> 8) & 0xff;
buffer[5] = retry & 0xff;
buffer[6] = (retry >> 8) & 0xff;
buffer[3] = retry_count & 0xff;
buffer[4] = (retry_count >> 8) & 0xff;
buffer[5] = match_retry & 0xff;
buffer[6] = (match_retry >> 8) & 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7);
if (retval != ERROR_OK || buffer[1] != DAP_OK) {
@@ -479,101 +515,141 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
}
#endif
static int cmsis_dap_swd_read_reg(uint8_t cmd, uint32_t *value)
{
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
int retval;
uint32_t val;
DEBUG_IO("CMSIS-DAP: Read Reg 0x%02" PRIx8, cmd);
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_TFER;
buffer[2] = 0x00;
buffer[3] = 0x01;
buffer[4] = cmd;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 5);
/* TODO - need better response checking */
if (retval != ERROR_OK || buffer[1] != 0x01) {
LOG_ERROR("CMSIS-DAP: Read Error (0x%02" PRIx8 ")", buffer[2]);
return buffer[2];
}
val = le_to_h_u32(&buffer[3]);
DEBUG_IO("0x%08" PRIx32, val);
if (value)
*value = val;
return retval;
}
static int cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value)
static int cmsis_dap_swd_run_queue(struct adiv5_dap *dap)
{
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
DEBUG_IO("CMSIS-DAP: Write Reg 0x%02" PRIx8 " 0x%08" PRIx32, cmd, value);
LOG_DEBUG("Executing %d queued transactions", pending_transfer_count);
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_TFER;
buffer[2] = 0x00;
buffer[3] = 0x01;
buffer[4] = cmd;
buffer[5] = (value) & 0xff;
buffer[6] = (value >> 8) & 0xff;
buffer[7] = (value >> 16) & 0xff;
buffer[8] = (value >> 24) & 0xff;
int retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 9);
if (buffer[1] != 0x01) {
LOG_ERROR("CMSIS-DAP: Write Error (0x%02" PRIx8 ")", buffer[2]);
retval = buffer[2];
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
return retval;
}
if (!pending_transfer_count)
goto skip;
static int cmsis_dap_swd_read_block(uint8_t cmd, uint32_t blocksize, uint8_t *dest_buf)
{
uint8_t *buffer;
int tfer_sz;
int retval = ERROR_OK;
uint16_t read_count;
size_t idx = 0;
buffer[idx++] = 0; /* report number */
buffer[idx++] = CMD_DAP_TFER;
buffer[idx++] = 0x00; /* DAP Index */
buffer[idx++] = pending_transfer_count;
DEBUG_IO("CMSIS-DAP: Read Block 0x%02" PRIx8 " %" PRIu32, cmd, blocksize);
for (int i = 0; i < pending_transfer_count; i++) {
uint8_t cmd = pending_transfers[i].cmd;
uint32_t data = pending_transfers[i].data;
while (blocksize) {
LOG_DEBUG("%s %s reg %x %"PRIx32,
cmd & SWD_CMD_APnDP ? "AP" : "DP",
cmd & SWD_CMD_RnW ? "read" : "write",
(cmd & SWD_CMD_A32) >> 1, data);
buffer = cmsis_dap_handle->packet_buffer;
tfer_sz = blocksize;
if (tfer_sz > 15)
tfer_sz = 8;
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_TFER_BLOCK;
buffer[2] = 0x00;
buffer[3] = tfer_sz;
buffer[4] = 0x00;
buffer[5] = cmd;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 6);
read_count = le_to_h_u16(&buffer[1]);
if (read_count != tfer_sz) {
LOG_ERROR("CMSIS-DAP: Block Read Error (0x%02" PRIx8 ")", buffer[3]);
retval = buffer[3];
/* When proper WAIT handling is implemented in the
* common SWD framework, this kludge can be
* removed. However, this might lead to minor
* performance degradation as the adapter wouldn't be
* able to automatically retry anything (because ARM
* has forgotten to implement sticky error flags
* clearing). See also comments regarding
* cmsis_dap_cmd_DAP_TFER_Configure() and
* cmsis_dap_cmd_DAP_SWD_Configure() in
* cmsis_dap_init().
*/
if (!(cmd & SWD_CMD_RnW) &&
!(cmd & SWD_CMD_APnDP) &&
(cmd & SWD_CMD_A32) >> 1 == DP_CTRL_STAT &&
(data & CORUNDETECT)) {
LOG_DEBUG("refusing to enable sticky overrun detection");
data &= ~CORUNDETECT;
}
read_count *= 4;
memcpy(dest_buf, &buffer[4], read_count);
dest_buf += read_count;
blocksize -= tfer_sz;
buffer[idx++] = (cmd >> 1) & 0x0f;
if (!(cmd & SWD_CMD_RnW)) {
buffer[idx++] = (data) & 0xff;
buffer[idx++] = (data >> 8) & 0xff;
buffer[idx++] = (data >> 16) & 0xff;
buffer[idx++] = (data >> 24) & 0xff;
}
}
queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, idx);
if (queued_retval != ERROR_OK)
goto skip;
idx = 2;
uint8_t ack = buffer[idx] & 0x07;
if (ack != SWD_ACK_OK || (buffer[idx] & 0x08)) {
LOG_DEBUG("SWD ack not OK: %d %s", buffer[idx-1],
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
goto skip;
}
idx++;
if (pending_transfer_count != buffer[1])
LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d",
pending_transfer_count, buffer[1]);
for (int i = 0; i < buffer[1]; i++) {
if (pending_transfers[i].cmd & SWD_CMD_RnW) {
static uint32_t last_read;
uint32_t data = le_to_h_u32(&buffer[idx]);
uint32_t tmp = data;
idx += 4;
LOG_DEBUG("Read result: %"PRIx32, data);
/* Imitate posted AP reads */
if ((pending_transfers[i].cmd & SWD_CMD_APnDP) ||
((pending_transfers[i].cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) {
tmp = last_read;
last_read = data;
}
if (pending_transfers[i].buffer)
*(uint32_t *)pending_transfers[i].buffer = tmp;
}
}
skip:
pending_transfer_count = 0;
int retval = queued_retval;
queued_retval = ERROR_OK;
return retval;
}
static void cmsis_dap_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
{
if (pending_transfer_count == pending_queue_len) {
/* Not enough room in the queue. Run the queue. */
queued_retval = cmsis_dap_swd_run_queue(dap);
}
if (queued_retval != ERROR_OK)
return;
pending_transfers[pending_transfer_count].data = data;
pending_transfers[pending_transfer_count].cmd = cmd;
if (cmd & SWD_CMD_RnW) {
/* Queue a read transaction */
pending_transfers[pending_transfer_count].buffer = dst;
}
pending_transfer_count++;
}
static void cmsis_dap_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
{
assert(!(cmd & SWD_CMD_RnW));
cmsis_dap_swd_queue_cmd(dap, cmd, NULL, value);
}
static void cmsis_dap_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
{
assert(cmd & SWD_CMD_RnW);
cmsis_dap_swd_queue_cmd(dap, cmd, value, 0);
}
static int cmsis_dap_get_version_info(void)
{
uint8_t *data;
@@ -631,115 +707,82 @@ static int cmsis_dap_get_status(void)
return retval;
}
static int cmsis_dap_reset_link(void)
static int cmsis_dap_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
{
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
const uint8_t *s;
unsigned int s_len;
int retval;
LOG_DEBUG("CMSIS-DAP: cmsis_dap_reset_link");
LOG_INFO("DAP_SWJ Sequence (reset: 50+ '1' followed by 0)");
/* reset line with SWDIO high for >50 cycles */
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_SWJ_SEQ;
buffer[2] = 7 * 8;
buffer[3] = 0xff;
buffer[4] = 0xff;
buffer[5] = 0xff;
buffer[6] = 0xff;
buffer[7] = 0xff;
buffer[8] = 0xff;
buffer[9] = 0xff;
int retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 10);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
/* 16bit JTAG-SWD sequence */
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_SWJ_SEQ;
buffer[2] = 2 * 8;
buffer[3] = 0x9e;
buffer[4] = 0xe7;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 5);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
/* another reset just incase */
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_SWJ_SEQ;
buffer[2] = 7 * 8;
buffer[3] = 0xff;
buffer[4] = 0xff;
buffer[5] = 0xff;
buffer[6] = 0xff;
buffer[7] = 0xff;
buffer[8] = 0xff;
buffer[9] = 0xff;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 10);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
/* 16 cycle idle period */
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_SWJ_SEQ;
buffer[2] = 2 * 8;
buffer[3] = 0x00;
buffer[4] = 0x00;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 5);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
DEBUG_IO("DAP Read IDCODE");
/* read the id code is always the next sequence */
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_TFER;
buffer[2] = 0x00;
buffer[3] = 0x01;
buffer[4] = 0x02;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 5);
/* When we are reconnecting, DAP_Connect needs to be rerun, at
* least on Keil ULINK-ME */
retval = cmsis_dap_cmd_DAP_Connect(seq == LINE_RESET || seq == JTAG_TO_SWD ?
CONNECT_SWD : CONNECT_JTAG);
if (retval != ERROR_OK)
return retval;
if (buffer[1] == 0) {
LOG_DEBUG("Result 0x%02" PRIx8 " 0x%02" PRIx8, buffer[1], buffer[2]);
LOG_DEBUG("DAP Reset Target");
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_RESET_TARGET;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 2);
LOG_DEBUG("Result 0x%02" PRIx8 " 0x%02" PRIx8, buffer[1], buffer[2]);
LOG_DEBUG("DAP Write Abort");
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_WRITE_ABORT;
buffer[2] = 0x00;
buffer[3] = 0x1e/*0x1f*/;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x00;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7);
LOG_DEBUG("Result 0x%02" PRIx8, buffer[1]);
return 0x80 + buffer[1];
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
s = swd_seq_line_reset;
s_len = swd_seq_line_reset_len;
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
s = swd_seq_jtag_to_swd;
s_len = swd_seq_jtag_to_swd_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;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
LOG_DEBUG("DAP Write Abort");
buffer[0] = 0; /* report number */
buffer[1] = CMD_DAP_WRITE_ABORT;
buffer[2] = 0x00;
buffer[3] = 0x1e;
buffer[4] = 0x00;
buffer[5] = 0x00;
buffer[6] = 0x00;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, 7);
LOG_DEBUG("Result 0x%02" PRIx8, buffer[1]);
buffer[1] = CMD_DAP_SWJ_SEQ;
buffer[2] = s_len;
bit_copy(&buffer[3], 0, s, 0, s_len);
return retval;
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, DIV_ROUND_UP(s_len, 8) + 3);
if (retval != ERROR_OK || buffer[1] != DAP_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int cmsis_dap_swd_open(void)
{
int retval;
if (cmsis_dap_handle == NULL) {
/* SWD init */
retval = cmsis_dap_usb_open();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_caps_info();
if (retval != ERROR_OK)
return retval;
}
if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
LOG_ERROR("CMSIS-DAP: SWD not supported");
return ERROR_JTAG_DEVICE_ERROR;
}
retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
if (retval != ERROR_OK)
return retval;
/* Add more setup here.??... */
LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)");
return ERROR_OK;
}
static int cmsis_dap_init(void)
@@ -747,6 +790,12 @@ static int cmsis_dap_init(void)
int retval;
uint8_t *data;
if (swd_mode) {
retval = cmsis_dap_swd_open();
if (retval != ERROR_OK)
return retval;
}
if (cmsis_dap_handle == NULL) {
/* JTAG init */
@@ -783,6 +832,16 @@ static int cmsis_dap_init(void)
if (data[0] == 2) { /* short */
uint16_t pkt_sz = data[1] + (data[2] << 8);
/* 4 bytes of command header + 5 bytes per register
* write. For bulk read sequences just 4 bytes are
* needed per transfer, so this is suboptimal. */
pending_queue_len = (pkt_sz - 4) / 5;
pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers));
if (!pending_transfers) {
LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
return ERROR_FAIL;
}
if (cmsis_dap_handle->packet_size != pkt_sz + 1) {
/* reallocate buffer */
cmsis_dap_handle->packet_size = pkt_sz + 1;
@@ -814,14 +873,19 @@ 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(100); /* 100kHz */
retval = cmsis_dap_cmd_DAP_SWJ_Clock(jtag_get_speed_khz());
if (retval != ERROR_OK)
return ERROR_FAIL;
/* Ask CMSIS-DAP to automatically retry on receiving WAIT for
* up to 64 times. This must be changed to 0 if sticky
* overrun detection is enabled. */
retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0);
if (retval != ERROR_OK)
return ERROR_FAIL;
retval = cmsis_dap_cmd_DAP_SWD_Configure(0x00);
/* Data Phase (bit 2) must be set to 1 if sticky overrun
* detection is enabled */
retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */
if (retval != ERROR_OK)
return ERROR_FAIL;
@@ -841,47 +905,16 @@ static int cmsis_dap_init(void)
}
}
retval = cmsis_dap_reset_link();
if (retval != ERROR_OK)
return ERROR_FAIL;
cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
cmsis_dap_cmd_DAP_LED(0x00); /* Both LEDs off */
LOG_INFO("CMSIS-DAP: Interface ready");
return ERROR_OK;
}
static int cmsis_dap_swd_init(uint8_t trn)
static int cmsis_dap_swd_init(void)
{
int retval;
DEBUG_IO("CMSIS-DAP: cmsis_dap_swd_init");
if (cmsis_dap_handle == NULL) {
/* SWD init */
retval = cmsis_dap_usb_open();
if (retval != ERROR_OK)
return retval;
retval = cmsis_dap_get_caps_info();
if (retval != ERROR_OK)
return retval;
}
if (!(cmsis_dap_handle->caps & INFO_CAPS_SWD)) {
LOG_ERROR("CMSIS-DAP: SWD not supported");
return ERROR_JTAG_DEVICE_ERROR;
}
retval = cmsis_dap_cmd_DAP_Connect(CONNECT_SWD);
if (retval != ERROR_OK)
return retval;
/* Add more setup here.??... */
LOG_INFO("CMSIS-DAP: Interface Initialised (SWD)");
swd_mode = true;
return ERROR_OK;
}
@@ -966,6 +999,14 @@ static int cmsis_dap_khz(int khz, int *jtag_speed)
return ERROR_OK;
}
static int_least32_t cmsis_dap_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
{
if (hz > 0)
cmsis_dap_speed(hz / 1000);
return hz;
}
COMMAND_HANDLER(cmsis_dap_handle_info_command)
{
if (cmsis_dap_get_version_info() == ERROR_OK)
@@ -1004,6 +1045,27 @@ COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
return ERROR_OK;
}
COMMAND_HANDLER(cmsis_dap_handle_serial_command)
{
if (CMD_ARGC == 1) {
size_t len = mbstowcs(NULL, CMD_ARGV[0], 0);
cmsis_dap_serial = calloc(len + 1, sizeof(wchar_t));
if (cmsis_dap_serial == NULL) {
LOG_ERROR("unable to allocate memory");
return ERROR_OK;
}
if (mbstowcs(cmsis_dap_serial, CMD_ARGV[0], len + 1) == (size_t)-1) {
free(cmsis_dap_serial);
cmsis_dap_serial = NULL;
LOG_ERROR("unable to convert serial");
}
} else {
LOG_ERROR("expected exactly one argument to cmsis_dap_serial <serial-number>");
}
return ERROR_OK;
}
static const struct command_registration cmsis_dap_subcommand_handlers[] = {
{
.name = "info",
@@ -1015,73 +1077,6 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = {
COMMAND_REGISTRATION_DONE
};
COMMAND_HANDLER(cmsis_dap_reset_command)
{
LOG_DEBUG("cmsis_dap_reset_command");
return ERROR_OK;
}
COMMAND_HANDLER(cmsis_dap_jtag_command)
{
LOG_DEBUG("cmsis_dap_jtag_command");
return ERROR_OK;
}
static const struct command_registration cmsis_dap_jtag_subcommand_handlers[] = {
{
.name = "init",
.mode = COMMAND_ANY,
.handler = cmsis_dap_jtag_command,
.usage = ""
},
{
.name = "arp_init",
.mode = COMMAND_ANY,
.handler = cmsis_dap_jtag_command,
.usage = ""
},
{
.name = "arp_init-reset",
.mode = COMMAND_ANY,
.handler = cmsis_dap_reset_command,
.usage = ""
},
{
.name = "tapisenabled",
.mode = COMMAND_EXEC,
.jim_handler = jim_jtag_tap_enabler,
},
{
.name = "tapenable",
.mode = COMMAND_EXEC,
.jim_handler = jim_jtag_tap_enabler,
},
{
.name = "tapdisable",
.mode = COMMAND_EXEC,
.handler = cmsis_dap_jtag_command,
.usage = "",
},
{
.name = "configure",
.mode = COMMAND_EXEC,
.handler = cmsis_dap_jtag_command,
.usage = "",
},
{
.name = "cget",
.mode = COMMAND_EXEC,
.jim_handler = jim_jtag_configure,
},
{
.name = "names",
.mode = COMMAND_ANY,
.handler = cmsis_dap_jtag_command,
.usage = "",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration cmsis_dap_command_handlers[] = {
{
.name = "cmsis-dap",
@@ -1098,24 +1093,25 @@ static const struct command_registration cmsis_dap_command_handlers[] = {
.usage = "(vid pid)* ",
},
{
/* this is currently a nasty hack so we get
* reset working with non jtag interfaces */
.name = "jtag",
.mode = COMMAND_ANY,
.usage = "",
.chain = cmsis_dap_jtag_subcommand_handlers,
.name = "cmsis_dap_serial",
.handler = &cmsis_dap_handle_serial_command,
.mode = COMMAND_CONFIG,
.help = "set the serial number of the adapter",
.usage = "serial_string",
},
COMMAND_REGISTRATION_DONE
};
static const struct swd_driver cmsis_dap_swd_driver = {
.init = cmsis_dap_swd_init,
.read_reg = cmsis_dap_swd_read_reg,
.write_reg = cmsis_dap_swd_write_reg,
.read_block = cmsis_dap_swd_read_block
.init = cmsis_dap_swd_init,
.frequency = cmsis_dap_swd_frequency,
.switch_seq = cmsis_dap_swd_switch_seq,
.read_reg = cmsis_dap_swd_read_reg,
.write_reg = cmsis_dap_swd_write_reg,
.run = cmsis_dap_swd_run_queue,
};
const char *cmsis_dap_transport[] = {"cmsis-dap", NULL};
static const char * const cmsis_dap_transport[] = { "swd", NULL };
struct jtag_interface cmsis_dap_interface = {
.name = "cmsis-dap",

View File

@@ -164,7 +164,7 @@ static uint16_t ft2232_vid[MAX_USB_IDS + 1] = { 0x0403, 0 };
static uint16_t ft2232_pid[MAX_USB_IDS + 1] = { 0x6010, 0 };
struct ft2232_layout {
char *name;
const char *name;
int (*init)(void);
void (*reset)(int trst, int srst);
void (*blink)(void);

View File

@@ -72,6 +72,7 @@
/* project specific includes */
#include <jtag/interface.h>
#include <jtag/swd.h>
#include <transport/transport.h>
#include <helper/time_support.h>
@@ -85,11 +86,14 @@
#include "mpsse.h"
#define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT)
#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 bool swd_mode;
#define MAX_USB_IDS 8
/* vid = pid = 0 marks the end of the list */
static uint16_t ftdi_vid[MAX_USB_IDS + 1] = { 0 };
@@ -108,8 +112,23 @@ struct signal {
static struct signal *signals;
/* FIXME: Where to store per-instance data? We need an SWD context. */
static struct swd_cmd_queue_entry {
uint8_t cmd;
uint32_t *dst;
uint8_t trn_ack_data_parity_trn[DIV_ROUND_UP(4 + 3 + 32 + 1 + 4, 8)];
} *swd_cmd_queue;
static size_t swd_cmd_queue_length;
static size_t swd_cmd_queue_alloced;
static int queued_retval;
static int freq;
static uint16_t output;
static uint16_t direction;
static uint16_t jtag_output_init;
static uint16_t jtag_direction_init;
static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
static struct signal *find_signal_by_name(const char *name)
{
@@ -174,14 +193,19 @@ static int ftdi_set_signal(const struct signal *s, char value)
return ERROR_FAIL;
}
uint16_t old_output = output;
uint16_t old_direction = direction;
output = data ? output | s->data_mask : output & ~s->data_mask;
if (s->oe_mask == s->data_mask)
direction = oe ? direction | s->oe_mask : direction & ~s->oe_mask;
else
output = oe ? output | s->oe_mask : output & ~s->oe_mask;
mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8);
if ((output & 0xff) != (old_output & 0xff) || (direction & 0xff) != (old_direction & 0xff))
mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
if ((output >> 8 != old_output >> 8) || (direction >> 8 != old_direction >> 8))
mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8);
return ERROR_OK;
}
@@ -477,7 +501,8 @@ static void ftdi_execute_reset(struct jtag_command *cmd)
ftdi_set_signal(trst, '0');
else
LOG_ERROR("Can't assert TRST: nTRST signal is not defined");
} else if (trst && cmd->cmd.reset->trst == 0) {
} else if (trst && jtag_get_reset_config() & RESET_HAS_TRST &&
cmd->cmd.reset->trst == 0) {
if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN)
ftdi_set_signal(trst, 'z');
else
@@ -490,7 +515,8 @@ static void ftdi_execute_reset(struct jtag_command *cmd)
ftdi_set_signal(srst, '0');
else
LOG_ERROR("Can't assert SRST: nSRST signal is not defined");
} else if (srst && cmd->cmd.reset->srst == 0) {
} else if (srst && jtag_get_reset_config() & RESET_HAS_SRST &&
cmd->cmd.reset->srst == 0) {
if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL)
ftdi_set_signal(srst, '1');
else
@@ -608,11 +634,27 @@ static int ftdi_initialize(void)
if (!mpsse_ctx)
return ERROR_JTAG_INIT_FAILED;
output = jtag_output_init;
direction = jtag_direction_init;
if (swd_mode) {
struct signal *sig = find_signal_by_name("SWD_EN");
if (!sig) {
LOG_ERROR("SWD mode is active but SWD_EN signal is not defined");
return ERROR_JTAG_INIT_FAILED;
}
/* A dummy SWD_EN would have zero mask */
if (sig->data_mask)
ftdi_set_signal(sig, '1');
}
mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff);
mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8);
mpsse_loopback_config(mpsse_ctx, false);
freq = mpsse_set_frequency(mpsse_ctx, jtag_get_speed_khz() * 1000);
return mpsse_flush(mpsse_ctx);
}
@@ -620,6 +662,8 @@ static int ftdi_quit(void)
{
mpsse_close(mpsse_ctx);
free(swd_cmd_queue);
return ERROR_OK;
}
@@ -664,8 +708,8 @@ COMMAND_HANDLER(ftdi_handle_layout_init_command)
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], output);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], direction);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], jtag_output_init);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], jtag_direction_init);
return ERROR_OK;
}
@@ -692,6 +736,19 @@ COMMAND_HANDLER(ftdi_handle_layout_signal_command)
} else if (strcmp("-noe", CMD_ARGV[i]) == 0) {
invert_oe = true;
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask);
} else if (!strcmp("-alias", CMD_ARGV[i]) ||
!strcmp("-nalias", CMD_ARGV[i])) {
if (!strcmp("-nalias", CMD_ARGV[i]))
invert_data = true;
struct signal *sig = find_signal_by_name(CMD_ARGV[i + 1]);
if (!sig) {
LOG_ERROR("signal %s is not defined", CMD_ARGV[i + 1]);
return ERROR_FAIL;
}
data_mask = sig->data_mask;
oe_mask = sig->oe_mask;
invert_oe = sig->invert_oe;
invert_data ^= sig->invert_data;
} else {
LOG_ERROR("unknown option '%s'", CMD_ARGV[i]);
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -811,7 +868,7 @@ static const struct command_registration ftdi_command_handlers[] = {
.mode = COMMAND_ANY,
.help = "define a signal controlled by one or more FTDI GPIO as data "
"and/or output enable",
.usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask]",
.usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask] [-alias|-nalias name]",
},
{
.name = "ftdi_set_signal",
@@ -830,11 +887,240 @@ static const struct command_registration ftdi_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static int create_default_signal(const char *name, uint16_t data_mask)
{
struct signal *sig = create_signal(name);
if (!sig) {
LOG_ERROR("failed to create signal %s", name);
return ERROR_FAIL;
}
sig->invert_data = false;
sig->data_mask = data_mask;
sig->invert_oe = false;
sig->oe_mask = 0;
return ERROR_OK;
}
static int create_signals(void)
{
if (create_default_signal("TCK", 0x01) != ERROR_OK)
return ERROR_FAIL;
if (create_default_signal("TDI", 0x02) != ERROR_OK)
return ERROR_FAIL;
if (create_default_signal("TDO", 0x04) != ERROR_OK)
return ERROR_FAIL;
if (create_default_signal("TMS", 0x08) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
static int ftdi_swd_init(void)
{
LOG_INFO("FTDI SWD mode enabled");
swd_mode = true;
if (create_signals() != ERROR_OK)
return ERROR_FAIL;
swd_cmd_queue_alloced = 10;
swd_cmd_queue = malloc(swd_cmd_queue_alloced * sizeof(*swd_cmd_queue));
return swd_cmd_queue != NULL ? ERROR_OK : ERROR_FAIL;
}
static void ftdi_swd_swdio_en(bool enable)
{
struct signal *oe = find_signal_by_name("SWDIO_OE");
if (oe)
ftdi_set_signal(oe, enable ? '1' : '0');
}
/**
* Flush the MPSSE queue and process the SWD transaction queue
* @param dap
* @return
*/
static int ftdi_swd_run_queue(struct adiv5_dap *dap)
{
LOG_DEBUG("Executing %zu queued transactions", swd_cmd_queue_length);
int retval;
struct signal *led = find_signal_by_name("LED");
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
/* A transaction must be followed by another transaction or at least 8 idle cycles to
* ensure that data is clocked through the AP. */
mpsse_clock_data_out(mpsse_ctx, NULL, 0, 8, SWD_MODE);
/* Terminate the "blink", if the current layout has that feature */
if (led)
ftdi_set_signal(led, '0');
queued_retval = mpsse_flush(mpsse_ctx);
if (queued_retval != ERROR_OK) {
LOG_ERROR("MPSSE failed");
goto skip;
}
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("%s %s %s reg %X = %08"PRIx32,
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",
(swd_cmd_queue[i].cmd & SWD_CMD_A32) >> 1,
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;
goto skip;
} else if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) {
uint32_t data = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3, 32);
int parity = buf_get_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 32, 1);
if (parity != parity_u32(data)) {
LOG_ERROR("SWD Read data parity mismatch");
queued_retval = ERROR_FAIL;
goto skip;
}
if (swd_cmd_queue[i].dst != NULL)
*swd_cmd_queue[i].dst = data;
}
}
skip:
swd_cmd_queue_length = 0;
retval = queued_retval;
queued_retval = ERROR_OK;
/* Queue a new "blink" */
if (led && retval == ERROR_OK)
ftdi_set_signal(led, '1');
return retval;
}
static void ftdi_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
{
if (swd_cmd_queue_length >= swd_cmd_queue_alloced) {
/* Not enough room in the queue. Run the queue and increase its size for next time.
* Note that it's not possible to avoid running the queue here, because mpsse contains
* pointers into the queue which may be invalid after the realloc. */
queued_retval = ftdi_swd_run_queue(dap);
struct swd_cmd_queue_entry *q = realloc(swd_cmd_queue, swd_cmd_queue_alloced * 2 * sizeof(*swd_cmd_queue));
if (q != NULL) {
swd_cmd_queue = q;
swd_cmd_queue_alloced *= 2;
LOG_DEBUG("Increased SWD command queue to %zu elements", swd_cmd_queue_alloced);
}
}
if (queued_retval != ERROR_OK)
return;
size_t i = swd_cmd_queue_length++;
swd_cmd_queue[i].cmd = cmd | SWD_CMD_START | SWD_CMD_PARK;
mpsse_clock_data_out(mpsse_ctx, &swd_cmd_queue[i].cmd, 0, 8, SWD_MODE);
if (swd_cmd_queue[i].cmd & SWD_CMD_RnW) {
/* Queue a read transaction */
swd_cmd_queue[i].dst = dst;
ftdi_swd_swdio_en(false);
mpsse_clock_data_in(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn,
0, 1 + 3 + 32 + 1 + 1, SWD_MODE);
ftdi_swd_swdio_en(true);
} else {
/* Queue a write transaction */
ftdi_swd_swdio_en(false);
mpsse_clock_data_in(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn,
0, 1 + 3 + 1, SWD_MODE);
ftdi_swd_swdio_en(true);
buf_set_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 1, 32, data);
buf_set_u32(swd_cmd_queue[i].trn_ack_data_parity_trn, 1 + 3 + 1 + 32, 1, parity_u32(data));
mpsse_clock_data_out(mpsse_ctx, swd_cmd_queue[i].trn_ack_data_parity_trn,
1 + 3 + 1, 32 + 1, SWD_MODE);
}
/* Insert idle cycles after AP accesses to avoid WAIT */
if (cmd & SWD_CMD_APnDP)
mpsse_clock_data_out(mpsse_ctx, NULL, 0, dap->memaccess_tck, SWD_MODE);
}
static void ftdi_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
{
assert(cmd & SWD_CMD_RnW);
ftdi_swd_queue_cmd(dap, cmd, value, 0);
}
static void ftdi_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
{
assert(!(cmd & SWD_CMD_RnW));
ftdi_swd_queue_cmd(dap, cmd, NULL, value);
}
static int_least32_t ftdi_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
{
if (hz > 0)
freq = mpsse_set_frequency(mpsse_ctx, hz);
return freq;
}
static int ftdi_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
{
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
mpsse_clock_data_out(mpsse_ctx, swd_seq_line_reset, 0, swd_seq_line_reset_len, SWD_MODE);
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE);
break;
case SWD_TO_JTAG:
LOG_DEBUG("SWD-to-JTAG");
mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE);
break;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
return ERROR_OK;
}
static const struct swd_driver ftdi_swd = {
.init = ftdi_swd_init,
.frequency = ftdi_swd_frequency,
.switch_seq = ftdi_swd_switch_seq,
.read_reg = ftdi_swd_read_reg,
.write_reg = ftdi_swd_write_reg,
.run = ftdi_swd_run_queue,
};
static const char * const ftdi_transports[] = { "jtag", "swd", NULL };
struct jtag_interface ftdi_interface = {
.name = "ftdi",
.supported = DEBUG_CAP_TMS_SEQ,
.commands = ftdi_command_handlers,
.transports = jtag_only,
.transports = ftdi_transports,
.swd = &ftdi_swd,
.init = ftdi_initialize,
.quit = ftdi_quit,

View File

@@ -29,6 +29,7 @@
#endif
#include <jtag/interface.h>
#include <jtag/swd.h>
#include <jtag/commands.h>
#include "libusb_common.h"
@@ -46,16 +47,12 @@
* pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address)
*/
#define JLINK_OB_PID 0x0105
#define JLINK_USB_INTERFACE_CLASS 0xff
#define JLINK_USB_INTERFACE_SUBCLASS 0xff
#define JLINK_USB_INTERFACE_PROTOCOL 0xff
#define JLINK_WRITE_ENDPOINT 0x02
#define JLINK_READ_ENDPOINT 0x81
#define JLINK_OB_WRITE_ENDPOINT 0x06
#define JLINK_OB_READ_ENDPOINT 0x85
static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT;
static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT;
static unsigned int jlink_write_ep;
static unsigned int jlink_read_ep;
static unsigned int jlink_hw_jtag_version = 2;
#define JLINK_USB_TIMEOUT 1000
@@ -80,6 +77,7 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE];
#define EMU_CMD_SET_SPEED 0x05
#define EMU_CMD_GET_STATE 0x07
#define EMU_CMD_SET_KS_POWER 0x08
#define EMU_CMD_REGISTER 0x09
#define EMU_CMD_GET_SPEEDS 0xc0
#define EMU_CMD_GET_HW_INFO 0xc1
#define EMU_CMD_GET_COUNTERS 0xc2
@@ -115,6 +113,10 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE];
#define EMU_CMD_WRITE_MEM_ARM79 0xf7
#define EMU_CMD_READ_MEM_ARM79 0xf8
/* Register subcommands */
#define REG_CMD_REGISTER 100
#define REG_CMD_UNREGISTER 101
/* bits return from EMU_CMD_GET_CAPS */
#define EMU_CAP_RESERVED_1 0
#define EMU_CAP_GET_HW_VERSION 1
@@ -149,7 +151,7 @@ static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE];
#define EMU_CAP_RAWTRACE 30
#define EMU_CAP_RESERVED_3 31
static char *jlink_cap_str[] = {
static const char * const jlink_cap_str[] = {
"Always 1.",
"Supports command EMU_CMD_GET_HARDWARE_VERSION",
"Supports command EMU_CMD_WRITE_DCC",
@@ -188,18 +190,20 @@ static char *jlink_cap_str[] = {
#define JLINK_MAX_SPEED 12000
/* J-Link hardware versions */
#define JLINK_HW_TYPE_JLINK 0
#define JLINK_HW_TYPE_JTRACE 1
#define JLINK_HW_TYPE_FLASHER 2
#define JLINK_HW_TYPE_JLINK_PRO 3
#define JLINK_HW_TYPE_MAX 4
#define JLINK_HW_TYPE_JLINK 0
#define JLINK_HW_TYPE_JTRACE 1
#define JLINK_HW_TYPE_FLASHER 2
#define JLINK_HW_TYPE_JLINK_PRO 3
#define JLINK_HW_TYPE_JLINK_LITE_ADI 5
#define JLINK_HW_TYPE_JLINK_LITE_XMC4000 16
#define JLINK_HW_TYPE_JLINK_LITE_XMC4200 17
#define JLINK_HW_TYPE_LPCLINK2 18
static char *jlink_hw_type_str[] = {
"J-Link",
"J-Trace",
"Flasher",
"J-Link Pro",
};
/* Interface selection */
#define JLINK_TIF_JTAG 0
#define JLINK_TIF_SWD 1
#define JLINK_SWD_DIR_IN 0
#define JLINK_SWD_DIR_OUT 1
/* Queue command functions */
static void jlink_end_state(tap_state_t state);
@@ -211,6 +215,9 @@ static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,
static void jlink_reset(int trst, int srst);
static void jlink_simple_command(uint8_t command);
static int jlink_get_status(void);
static int jlink_swd_run_queue(struct adiv5_dap *dap);
static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data);
static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq);
/* J-Link tap buffer functions */
static void jlink_tap_init(void);
@@ -251,9 +258,14 @@ static struct jlink *jlink_handle;
static uint16_t vids[] = { 0x1366, 0x1366, 0x1366, 0x1366, 0x1366, 0 };
static uint16_t pids[] = { 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0 };
static char *jlink_serial;
static uint32_t jlink_caps;
static uint32_t jlink_hw_type;
static int queued_retval;
static bool swd_mode;
/* 256 byte non-volatile memory */
struct jlink_config {
uint8_t usb_address;
@@ -422,6 +434,41 @@ static int jlink_khz(int khz, int *jtag_speed)
return ERROR_OK;
}
static int jlink_register(void)
{
int result;
usb_out_buffer[0] = EMU_CMD_REGISTER;
usb_out_buffer[1] = REG_CMD_REGISTER;
/* 2 - 11 is "additional parameter",
* 12 - 13 is connection handle, zero initially */
memset(&usb_out_buffer[2], 0, 10 + 2);
result = jlink_usb_write(jlink_handle, 14);
if (result != 14) {
LOG_ERROR("J-Link register write failed (%d)", result);
return ERROR_JTAG_DEVICE_ERROR;
}
/* Returns:
* 0 - 1 connection handle,
* 2 - 3 number of information entities,
* 4 - 5 size of a single information struct,
* 6 - 7 number of additional bytes,
* 8 - ... reply data
*
* Try to read the whole USB bulk packet
*/
result = jtag_libusb_bulk_read(jlink_handle->usb_handle, jlink_read_ep,
(char *)usb_in_buffer, sizeof(usb_in_buffer),
JLINK_USB_TIMEOUT);
if (!result) {
LOG_ERROR("J-Link register read failed (0 bytes received)");
return ERROR_JTAG_DEVICE_ERROR;
}
return ERROR_OK;
}
/*
* select transport interface
*
@@ -495,28 +542,6 @@ static int jlink_init(void)
return ERROR_JTAG_INIT_FAILED;
}
/*
* The next three instructions were added after discovering a problem
* while using an oscilloscope.
* For the V8 SAM-ICE dongle (and likely other j-link device variants),
* the reset line to the target microprocessor was found to cycle only
* intermittently during emulator startup (even after encountering the
* downstream reset instruction later in the code).
* This was found to create two issues:
* 1) In general it is a bad practice to not reset a CPU to a known
* state when starting an emulator and
* 2) something critical happens inside the dongle when it does the
* first read following a new USB session.
* Keeping the processor in reset during the first read collecting
* version information seems to prevent errant
* "J-Link command EMU_CMD_VERSION failed" issues.
*/
LOG_INFO("J-Link initialization started / target CPU reset initiated");
jlink_simple_command(EMU_CMD_HW_TRST0);
jlink_simple_command(EMU_CMD_HW_RESET0);
usleep(1000);
jlink_hw_jtag_version = 2;
if (jlink_get_version_info() == ERROR_OK) {
@@ -524,16 +549,26 @@ static int jlink_init(void)
jlink_get_status();
}
/* Registration is sometimes necessary for SWD to work */
if (jlink_caps & (1<<EMU_CAP_REGISTER))
jlink_register();
/*
* Some versions of Segger's software do not select JTAG interface by default.
*
* Segger recommends to select interface necessarily as a part of init process,
* in case any previous session leaves improper interface selected.
*
* Until SWD implemented, select only JTAG interface here.
*/
int retval;
if (jlink_caps & (1<<EMU_CAP_SELECT_IF))
jlink_select_interface(0);
retval = jlink_select_interface(swd_mode ? JLINK_TIF_SWD : JLINK_TIF_JTAG);
else
retval = swd_mode ? ERROR_JTAG_DEVICE_ERROR : ERROR_OK;
if (retval != ERROR_OK) {
LOG_ERROR("Selected transport mode is not supported.");
return ERROR_JTAG_INIT_FAILED;
}
LOG_INFO("J-Link JTAG Interface ready");
@@ -541,11 +576,15 @@ static int jlink_init(void)
jtag_sleep(3000);
jlink_tap_init();
/* v5/6 jlink seems to have an issue if the first tap move
* is not divisible by 8, so we send a TLR on first power up */
for (i = 0; i < 8; i++)
jlink_tap_append_step(1, 0);
jlink_tap_execute();
jlink_speed(jtag_get_speed_khz());
if (!swd_mode) {
/* v5/6 jlink seems to have an issue if the first tap move
* is not divisible by 8, so we send a TLR on first power up */
for (i = 0; i < 8; i++)
jlink_tap_append_step(1, 0);
jlink_tap_execute();
}
return ERROR_OK;
}
@@ -921,10 +960,35 @@ static int jlink_get_version_info(void)
LOG_INFO("J-Link hw version %i", (int)jlink_hw_version);
if (jlink_hw_type >= JLINK_HW_TYPE_MAX)
LOG_INFO("J-Link hw type uknown 0x%" PRIx32, jlink_hw_type);
else
LOG_INFO("J-Link hw type %s", jlink_hw_type_str[jlink_hw_type]);
switch (jlink_hw_type) {
case JLINK_HW_TYPE_JLINK:
LOG_INFO("J-Link hw type J-Link");
break;
case JLINK_HW_TYPE_JTRACE:
LOG_INFO("J-Link hw type J-Trace");
break;
case JLINK_HW_TYPE_FLASHER:
LOG_INFO("J-Link hw type Flasher");
break;
case JLINK_HW_TYPE_JLINK_PRO:
LOG_INFO("J-Link hw type J-Link Pro");
break;
case JLINK_HW_TYPE_JLINK_LITE_ADI:
LOG_INFO("J-Link hw type J-Link Lite-ADI");
break;
case JLINK_HW_TYPE_JLINK_LITE_XMC4000:
LOG_INFO("J-Link hw type J-Link Lite-XMC4000");
break;
case JLINK_HW_TYPE_JLINK_LITE_XMC4200:
LOG_INFO("J-Link hw type J-Link Lite-XMC4200");
break;
case JLINK_HW_TYPE_LPCLINK2:
LOG_INFO("J-Link hw type J-Link on LPC-Link2");
break;
default:
LOG_INFO("J-Link hw type unknown 0x%" PRIx32, jlink_hw_type);
break;
}
}
if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) {
@@ -965,6 +1029,19 @@ COMMAND_HANDLER(jlink_pid_command)
return ERROR_OK;
}
COMMAND_HANDLER(jlink_serial_command)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Need exactly one argument to jlink_serial");
return ERROR_FAIL;
}
if (jlink_serial)
free(jlink_serial);
jlink_serial = strdup(CMD_ARGV[0]);
return ERROR_OK;
}
COMMAND_HANDLER(jlink_handle_jlink_info_command)
{
if (jlink_get_version_info() == ERROR_OK) {
@@ -1281,6 +1358,12 @@ static const struct command_registration jlink_subcommand_handlers[] = {
.mode = COMMAND_CONFIG,
.help = "set the pid of the interface we want to use",
},
{
.name = "serial",
.handler = &jlink_serial_command,
.mode = COMMAND_CONFIG,
.help = "set the serial number of the J-Link adapter we want to use"
},
COMMAND_REGISTRATION_DONE
};
@@ -1294,10 +1377,50 @@ static const struct command_registration jlink_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static int jlink_swd_init(void)
{
LOG_INFO("JLink SWD mode enabled");
swd_mode = true;
return ERROR_OK;
}
static void jlink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t value)
{
assert(!(cmd & SWD_CMD_RnW));
jlink_swd_queue_cmd(dap, cmd, NULL, value);
}
static void jlink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value)
{
assert(cmd & SWD_CMD_RnW);
jlink_swd_queue_cmd(dap, cmd, value, 0);
}
static int_least32_t jlink_swd_frequency(struct adiv5_dap *dap, int_least32_t hz)
{
if (hz > 0)
jlink_speed(hz / 1000);
return hz;
}
static const struct swd_driver jlink_swd = {
.init = jlink_swd_init,
.frequency = jlink_swd_frequency,
.switch_seq = jlink_swd_switch_seq,
.read_reg = jlink_swd_read_reg,
.write_reg = jlink_swd_write_reg,
.run = jlink_swd_run_queue,
};
static const char * const jlink_transports[] = { "jtag", "swd", NULL };
struct jtag_interface jlink_interface = {
.name = "jlink",
.commands = jlink_command_handlers,
.transports = jtag_only,
.transports = jlink_transports,
.swd = &jlink_swd,
.execute_queue = jlink_execute_queue,
.speed = jlink_speed,
@@ -1312,6 +1435,7 @@ struct jtag_interface jlink_interface = {
static unsigned tap_length;
/* In SWD mode use tms buffer for direction control */
static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE];
static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE];
static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE];
@@ -1320,7 +1444,7 @@ struct pending_scan_result {
int first; /* First bit position in tdo_buffer to read */
int length; /* Number of bits to read */
struct scan_command *command; /* Corresponding scan command */
uint8_t *buffer;
void *buffer;
};
#define MAX_PENDING_SCAN_RESULTS 256
@@ -1430,7 +1554,8 @@ static int jlink_tap_execute(void)
result = use_jtag3 ? usb_in_buffer[byte_length] : 0;
if (result != 0) {
LOG_ERROR("jlink_tap_execute failed, result %d", result);
LOG_ERROR("jlink_tap_execute failed, result %d (%s)", result,
result == 1 ? "adaptive clocking timeout" : "unknown");
jlink_tap_init();
return ERROR_JTAG_QUEUE_FAILED;
}
@@ -1464,13 +1589,191 @@ static int jlink_tap_execute(void)
return ERROR_OK;
}
static void fill_buffer(uint8_t *buf, uint32_t val, uint32_t len)
{
unsigned int tap_pos = tap_length;
while (len > 32) {
buf_set_u32(buf, tap_pos, 32, val);
len -= 32;
tap_pos += 32;
}
if (len)
buf_set_u32(buf, tap_pos, len, val);
}
static void jlink_queue_data_out(const uint8_t *data, uint32_t len)
{
const uint32_t dir_out = 0xffffffff;
if (data)
bit_copy(tdi_buffer, tap_length, data, 0, len);
else
fill_buffer(tdi_buffer, 0, len);
fill_buffer(tms_buffer, dir_out, len);
tap_length += len;
}
static void jlink_queue_data_in(uint32_t len)
{
const uint32_t dir_in = 0;
fill_buffer(tms_buffer, dir_in, len);
tap_length += len;
}
static int jlink_swd_switch_seq(struct adiv5_dap *dap, enum swd_special_seq seq)
{
const uint8_t *s;
unsigned int s_len;
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
s = swd_seq_line_reset;
s_len = swd_seq_line_reset_len;
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
s = swd_seq_jtag_to_swd;
s_len = swd_seq_jtag_to_swd_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;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
jlink_queue_data_out(s, s_len);
return ERROR_OK;
}
static int jlink_swd_run_queue(struct adiv5_dap *dap)
{
LOG_DEBUG("Executing %d queued transactions", pending_scan_results_length);
int retval;
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
/* A transaction must be followed by another transaction or at least 8 idle cycles to
* ensure that data is clocked through the AP. */
jlink_queue_data_out(NULL, 8);
size_t byte_length = DIV_ROUND_UP(tap_length, 8);
/* There's a comment in jlink_tap_execute saying JLink returns
* an extra NULL in packet when size of incoming message is a
* multiple of 64. Someone should verify if that's still the
* case with the current jlink firmware */
usb_out_buffer[0] = EMU_CMD_HW_JTAG3;
usb_out_buffer[1] = 0;
usb_out_buffer[2] = (tap_length >> 0) & 0xff;
usb_out_buffer[3] = (tap_length >> 8) & 0xff;
memcpy(usb_out_buffer + 4, tms_buffer, byte_length);
memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length);
retval = jlink_usb_message(jlink_handle, 4 + 2 * byte_length,
byte_length + 1);
if (retval != ERROR_OK) {
LOG_ERROR("jlink_swd_run_queue failed USB io (%d)", retval);
goto skip;
}
retval = usb_in_buffer[byte_length];
if (retval) {
LOG_ERROR("jlink_swd_run_queue failed, result %d", retval);
goto skip;
}
for (int i = 0; i < pending_scan_results_length; i++) {
int ack = buf_get_u32(usb_in_buffer, pending_scan_results_buffer[i].first, 3);
if (ack != SWD_ACK_OK) {
LOG_DEBUG("SWD ack not OK: %d %s", ack,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
goto skip;
} else if (pending_scan_results_buffer[i].length) {
uint32_t data = buf_get_u32(usb_in_buffer, 3 + pending_scan_results_buffer[i].first, 32);
int parity = buf_get_u32(usb_in_buffer, 3 + 32 + pending_scan_results_buffer[i].first, 1);
if (parity != parity_u32(data)) {
LOG_ERROR("SWD Read data parity mismatch");
queued_retval = ERROR_FAIL;
goto skip;
}
if (pending_scan_results_buffer[i].buffer)
*(uint32_t *)pending_scan_results_buffer[i].buffer = data;
}
}
skip:
jlink_tap_init();
retval = queued_retval;
queued_retval = ERROR_OK;
return retval;
}
static void jlink_swd_queue_cmd(struct adiv5_dap *dap, uint8_t cmd, uint32_t *dst, uint32_t data)
{
uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
if (tap_length + 46 + 8 + dap->memaccess_tck >= sizeof(tdi_buffer) * 8 ||
pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) {
/* Not enough room in the queue. Run the queue. */
queued_retval = jlink_swd_run_queue(dap);
}
if (queued_retval != ERROR_OK)
return;
cmd |= SWD_CMD_START | SWD_CMD_PARK;
jlink_queue_data_out(&cmd, 8);
pending_scan_results_buffer[pending_scan_results_length].first = tap_length;
if (cmd & SWD_CMD_RnW) {
/* Queue a read transaction */
pending_scan_results_buffer[pending_scan_results_length].length = 32;
pending_scan_results_buffer[pending_scan_results_length].buffer = dst;
jlink_queue_data_in(1 + 3 + 32 + 1 + 1);
} else {
/* Queue a write transaction */
pending_scan_results_buffer[pending_scan_results_length].length = 0;
jlink_queue_data_in(1 + 3 + 1);
buf_set_u32(data_parity_trn, 0, 32, data);
buf_set_u32(data_parity_trn, 32, 1, parity_u32(data));
jlink_queue_data_out(data_parity_trn, 32 + 1);
}
pending_scan_results_length++;
/* Insert idle cycles after AP accesses to avoid WAIT */
if (cmd & SWD_CMD_APnDP)
jlink_queue_data_out(NULL, dap->memaccess_tck);
}
/*****************************************************************************/
/* JLink USB low-level functions */
static struct jlink *jlink_usb_open()
{
struct jtag_libusb_device_handle *devh;
if (jtag_libusb_open(vids, pids, &devh) != ERROR_OK)
if (jtag_libusb_open(vids, pids, jlink_serial, &devh) != ERROR_OK)
return NULL;
/* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS
@@ -1484,7 +1787,15 @@ static struct jlink *jlink_usb_open()
* committing them!
*/
#if IS_WIN32 == 0
/* This entire block can probably be removed. It was a workaround for
* libusb0.1 and old JLink firmware. It has already be removed for
* windows and causing problems (LPC Link-2 with JLink firmware) on
* Linux with libusb1.0.
*
* However, for now the behavior will be left unchanged for non-windows
* platforms using libusb0.1 due to lack of testing.
*/
#if IS_WIN32 == 0 && HAVE_LIBUSB1 == 0
jtag_libusb_reset_device(devh);
@@ -1494,7 +1805,7 @@ static struct jlink *jlink_usb_open()
/* 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, &devh)) != ERROR_OK) {
while ((retval = jtag_libusb_open(vids, pids, jlink_serial, &devh)) != ERROR_OK) {
usleep(1000);
timeout--;
if (!timeout)
@@ -1506,29 +1817,15 @@ static struct jlink *jlink_usb_open()
#endif
/* usb_set_configuration required under win32 */
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
/* usb_set_configuration is only required under win32
* with libusb 0.1 and libusb0.sys. For libusb 1.0 it is a no-op
* since the configuration is already set. */
jtag_libusb_set_configuration(devh, 0);
jtag_libusb_claim_interface(devh, 0);
#if 0
/*
* This makes problems under Mac OS X. And is not needed
* under Windows. Hopefully this will not break a linux build
*/
usb_set_altinterface(result->usb_handle, 0);
#endif
/* Use the OB endpoints if the JLink we matched is a Jlink-OB adapter */
uint16_t matched_pid;
if (jtag_libusb_get_pid(udev, &matched_pid) == ERROR_OK) {
if (matched_pid == JLINK_OB_PID) {
jlink_read_ep = JLINK_OB_WRITE_ENDPOINT;
jlink_write_ep = JLINK_OB_READ_ENDPOINT;
}
}
jtag_libusb_get_endpoints(udev, &jlink_read_ep, &jlink_write_ep);
jtag_libusb_choose_interface(devh, &jlink_read_ep, &jlink_write_ep,
JLINK_USB_INTERFACE_CLASS,
JLINK_USB_INTERFACE_SUBCLASS,
JLINK_USB_INTERFACE_PROTOCOL);
struct jlink *result = malloc(sizeof(struct jlink));
result->usb_handle = devh;

View File

@@ -37,9 +37,40 @@ static bool jtag_libusb_match(struct jtag_libusb_device *dev,
return false;
}
/* Returns true if the string descriptor indexed by str_index in device matches string */
static bool string_descriptor_equal(usb_dev_handle *device, uint8_t str_index,
const char *string)
{
int retval;
bool matched;
char desc_string[256+1]; /* Max size of string descriptor */
if (str_index == 0)
return false;
retval = usb_get_string_simple(device, str_index,
desc_string, sizeof(desc_string)-1);
if (retval < 0) {
LOG_ERROR("usb_get_string_simple() failed with %d", retval);
return false;
}
/* Null terminate descriptor string in case it needs to be logged. */
desc_string[sizeof(desc_string)-1] = '\0';
matched = strncmp(string, desc_string, sizeof(desc_string)) == 0;
if (!matched)
LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
desc_string, string);
return matched;
}
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
struct jtag_libusb_device_handle **out)
{
int retval = -ENODEV;
struct jtag_libusb_device_handle *libusb_handle;
usb_init();
usb_find_busses();
@@ -52,13 +83,24 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
if (!jtag_libusb_match(dev, vids, pids))
continue;
*out = usb_open(dev);
if (NULL == *out)
return -errno;
return 0;
libusb_handle = usb_open(dev);
if (NULL == libusb_handle) {
retval = -errno;
continue;
}
/* Device must be open to use libusb_get_string_descriptor_ascii. */
if (serial != NULL &&
!string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) {
usb_close(libusb_handle);
continue;
}
*out = libusb_handle;
retval = 0;
break;
}
}
return -ENODEV;
return retval;
}
void jtag_libusb_close(jtag_libusb_device_handle *dev)
@@ -103,14 +145,23 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
udev->config[configuration].bConfigurationValue);
}
int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep)
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol)
{
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
struct usb_interface *iface = udev->config->interface;
struct usb_interface_descriptor *desc = iface->altsetting;
*usb_read_ep = *usb_write_ep = 0;
for (int i = 0; i < desc->bNumEndpoints; i++) {
if ((bclass > 0 && desc->bInterfaceClass != bclass) ||
(subclass > 0 && desc->bInterfaceSubClass != subclass) ||
(protocol > 0 && desc->bInterfaceProtocol != protocol))
continue;
uint8_t epnum = desc->endpoint[i].bEndpointAddress;
bool is_input = epnum & 0x80;
LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum);
@@ -118,20 +169,22 @@ int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
*usb_read_ep = epnum;
else
*usb_write_ep = epnum;
if (*usb_read_ep && *usb_write_ep) {
LOG_DEBUG("Claiming interface %d", (int)desc->bInterfaceNumber);
usb_claim_interface(devh, (int)desc->bInterfaceNumber);
return ERROR_OK;
}
}
return 0;
return ERROR_FAIL;
}
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
{
struct libusb_device_descriptor dev_desc;
if (!dev)
return ERROR_FAIL;
if (libusb_get_device_descriptor(dev, &dev_desc) == 0) {
*pid = dev_desc.idProduct;
return 0;
}
return -ENODEV;
*pid = dev->descriptor.idProduct;
return ERROR_OK;
}

View File

@@ -54,6 +54,7 @@ static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
}
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
struct jtag_libusb_device_handle **out);
void jtag_libusb_close(jtag_libusb_device_handle *dev);
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
@@ -65,9 +66,10 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration);
int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep);
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol);
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
#endif /* JTAG_USB_COMMON_H */

View File

@@ -28,25 +28,53 @@
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
static libusb_device **devs; /**< The usb device list **/
static bool jtag_libusb_match(struct jtag_libusb_device *dev,
static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[])
{
struct libusb_device_descriptor dev_desc;
for (unsigned i = 0; vids[i]; i++) {
if (libusb_get_device_descriptor(dev, &dev_desc) == 0) {
if (dev_desc.idVendor == vids[i] &&
dev_desc.idProduct == pids[i])
return true;
if (dev_desc->idVendor == vids[i] &&
dev_desc->idProduct == pids[i]) {
return true;
}
}
return false;
}
/* Returns true if the string descriptor indexed by str_index in device matches string */
static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index,
const char *string)
{
int retval;
bool matched;
char desc_string[256+1]; /* Max size of string descriptor */
if (str_index == 0)
return false;
retval = libusb_get_string_descriptor_ascii(device, str_index,
(unsigned char *)desc_string, sizeof(desc_string)-1);
if (retval < 0) {
LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval);
return false;
}
/* Null terminate descriptor string in case it needs to be logged. */
desc_string[sizeof(desc_string)-1] = '\0';
matched = strncmp(string, desc_string, sizeof(desc_string)) == 0;
if (!matched)
LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'",
desc_string, string);
return matched;
}
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
struct jtag_libusb_device_handle **out)
{
int cnt, idx, errCode;
int retval = -ENODEV;
struct jtag_libusb_device_handle *libusb_handle = NULL;
if (libusb_init(&jtag_libusb_context) < 0)
return -ENODEV;
@@ -54,22 +82,37 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
cnt = libusb_get_device_list(jtag_libusb_context, &devs);
for (idx = 0; idx < cnt; idx++) {
if (!jtag_libusb_match(devs[idx], vids, pids))
struct libusb_device_descriptor dev_desc;
if (libusb_get_device_descriptor(devs[idx], &dev_desc) != 0)
continue;
errCode = libusb_open(devs[idx], out);
if (!jtag_libusb_match(&dev_desc, vids, pids))
continue;
/** Free the device list **/
libusb_free_device_list(devs, 1);
errCode = libusb_open(devs[idx], &libusb_handle);
if (errCode) {
LOG_ERROR("libusb_open() failed with %s",
libusb_error_name(errCode));
return errCode;
continue;
}
return 0;
/* Device must be open to use libusb_get_string_descriptor_ascii. */
if (serial != NULL &&
!string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) {
libusb_close(libusb_handle);
continue;
}
/* Success. */
*out = libusb_handle;
retval = 0;
break;
}
return -ENODEV;
if (cnt >= 0)
libusb_free_device_list(devs, 1);
return retval;
}
void jtag_libusb_close(jtag_libusb_device_handle *dev)
@@ -122,49 +165,75 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int retCode = -99;
struct libusb_config_descriptor *config = NULL;
int current_config = -1;
libusb_get_config_descriptor(udev, configuration, &config);
retCode = libusb_set_configuration(devh, config->bConfigurationValue);
retCode = libusb_get_configuration(devh, &current_config);
if (retCode != 0)
return retCode;
retCode = libusb_get_config_descriptor(udev, configuration, &config);
if (retCode != 0 || config == NULL)
return retCode;
/* Only change the configuration if it is not already set to the
same one. Otherwise this issues a lightweight reset and hangs
LPC-Link2 with JLink firmware. */
if (current_config != config->bConfigurationValue)
retCode = libusb_set_configuration(devh, config->bConfigurationValue);
libusb_free_config_descriptor(config);
return retCode;
}
int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep)
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol)
{
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
const struct libusb_interface *inter;
const struct libusb_interface_descriptor *interdesc;
const struct libusb_endpoint_descriptor *epdesc;
struct libusb_config_descriptor *config;
*usb_read_ep = *usb_write_ep = 0;
libusb_get_config_descriptor(udev, 0, &config);
for (int i = 0; i < (int)config->bNumInterfaces; i++) {
inter = &config->interface[i];
for (int j = 0; j < inter->num_altsetting; j++) {
interdesc = &inter->altsetting[j];
for (int k = 0;
k < (int)interdesc->bNumEndpoints; k++) {
epdesc = &interdesc->endpoint[k];
interdesc = &inter->altsetting[0];
for (int k = 0;
k < (int)interdesc->bNumEndpoints; k++) {
if ((bclass > 0 && interdesc->bInterfaceClass != bclass) ||
(subclass > 0 && interdesc->bInterfaceSubClass != subclass) ||
(protocol > 0 && interdesc->bInterfaceProtocol != protocol))
continue;
uint8_t epnum = epdesc->bEndpointAddress;
bool is_input = epnum & 0x80;
LOG_DEBUG("usb ep %s %02x",
is_input ? "in" : "out", epnum);
epdesc = &interdesc->endpoint[k];
if (is_input)
*usb_read_ep = epnum;
else
*usb_write_ep = epnum;
uint8_t epnum = epdesc->bEndpointAddress;
bool is_input = epnum & 0x80;
LOG_DEBUG("usb ep %s %02x",
is_input ? "in" : "out", epnum);
if (is_input)
*usb_read_ep = epnum;
else
*usb_write_ep = epnum;
if (*usb_read_ep && *usb_write_ep) {
LOG_DEBUG("Claiming interface %d", (int)interdesc->bInterfaceNumber);
libusb_claim_interface(devh, (int)interdesc->bInterfaceNumber);
libusb_free_config_descriptor(config);
return ERROR_OK;
}
}
}
libusb_free_config_descriptor(config);
return 0;
return ERROR_FAIL;
}
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
@@ -174,8 +243,8 @@ int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
if (libusb_get_device_descriptor(dev, &dev_desc) == 0) {
*pid = dev_desc.idProduct;
return 0;
return ERROR_OK;
}
return -ENODEV;
return ERROR_FAIL;
}

View File

@@ -48,6 +48,7 @@ static inline int jtag_libusb_release_interface(jtag_libusb_device_handle *devh,
}
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial,
struct jtag_libusb_device_handle **out);
void jtag_libusb_close(jtag_libusb_device_handle *dev);
int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev,
@@ -59,9 +60,23 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration);
int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
/**
* Find the first interface optionally matching class, subclass and
* protocol and claim it.
* @param devh _libusb_ device handle.
* @param usb_read_ep A pointer to a variable where the _IN_ endpoint
* number will be stored.
* @param usb_write_ep A pointer to a variable where the _OUT_ endpoint
* number will be stored.
* @param bclass `bInterfaceClass` to match, or -1 to ignore this field.
* @param subclass `bInterfaceSubClass` to match, or -1 to ignore this field.
* @param protocol `bInterfaceProtocol` to match, or -1 to ignore this field.
* @returns Returns ERROR_OK on success, ERROR_FAIL otherwise.
*/
int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
unsigned int *usb_read_ep,
unsigned int *usb_write_ep);
unsigned int *usb_write_ep,
int bclass, int subclass, int protocol);
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
#endif /* JTAG_USB_COMMON_H */

View File

@@ -98,7 +98,7 @@ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_in
retval = libusb_get_string_descriptor_ascii(device, str_index, (unsigned char *)desc_string,
sizeof(desc_string));
if (retval < 0) {
LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval);
LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %s", libusb_error_name(retval));
return false;
}
return strncmp(string, desc_string, sizeof(desc_string)) == 0;
@@ -118,14 +118,14 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
bool found = false;
ssize_t cnt = libusb_get_device_list(ctx->usb_ctx, &list);
if (cnt < 0)
LOG_ERROR("libusb_get_device_list() failed with %zi", cnt);
LOG_ERROR("libusb_get_device_list() failed with %s", libusb_error_name(cnt));
for (ssize_t i = 0; i < cnt; i++) {
libusb_device *device = list[i];
err = libusb_get_device_descriptor(device, &desc);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_get_device_descriptor() failed with %d", err);
LOG_ERROR("libusb_get_device_descriptor() failed with %s", libusb_error_name(err));
continue;
}
@@ -164,7 +164,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
err = libusb_get_config_descriptor(libusb_get_device(ctx->usb_dev), 0, &config0);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_get_config_descriptor() failed with %d", err);
LOG_ERROR("libusb_get_config_descriptor() failed with %s", libusb_error_name(err));
libusb_close(ctx->usb_dev);
return false;
}
@@ -173,14 +173,14 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
int cfg;
err = libusb_get_configuration(ctx->usb_dev, &cfg);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_get_configuration() failed with %d", err);
LOG_ERROR("libusb_get_configuration() failed with %s", libusb_error_name(err));
goto error;
}
if (desc.bNumConfigurations > 0 && cfg != config0->bConfigurationValue) {
err = libusb_set_configuration(ctx->usb_dev, config0->bConfigurationValue);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_set_configuration() failed with %d", err);
LOG_ERROR("libusb_set_configuration() failed with %s", libusb_error_name(err));
goto error;
}
}
@@ -189,13 +189,13 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
err = libusb_detach_kernel_driver(ctx->usb_dev, ctx->interface);
if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_NOT_FOUND
&& err != LIBUSB_ERROR_NOT_SUPPORTED) {
LOG_ERROR("libusb_detach_kernel_driver() failed with %d", err);
LOG_ERROR("libusb_detach_kernel_driver() failed with %s", libusb_error_name(err));
goto error;
}
err = libusb_claim_interface(ctx->usb_dev, ctx->interface);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_claim_interface() failed with %d", err);
LOG_ERROR("libusb_claim_interface() failed with %s", libusb_error_name(err));
goto error;
}
@@ -204,7 +204,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
SIO_RESET_REQUEST, SIO_RESET_SIO,
ctx->index, NULL, 0, ctx->usb_write_timeout);
if (err < 0) {
LOG_ERROR("failed to reset FTDI device: %d", err);
LOG_ERROR("failed to reset FTDI device: %s", libusb_error_name(err));
goto error;
}
@@ -288,7 +288,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
err = libusb_init(&ctx->usb_ctx);
if (err != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_init() failed with %d", err);
LOG_ERROR("libusb_init() failed with %s", libusb_error_name(err));
goto error;
}
@@ -310,7 +310,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
SIO_SET_LATENCY_TIMER_REQUEST, 255, ctx->index, NULL, 0,
ctx->usb_write_timeout);
if (err < 0) {
LOG_ERROR("unable to set latency timer: %d", err);
LOG_ERROR("unable to set latency timer: %s", libusb_error_name(err));
goto error;
}
@@ -323,7 +323,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
0,
ctx->usb_write_timeout);
if (err < 0) {
LOG_ERROR("unable to set MPSSE bitmode: %d", err);
LOG_ERROR("unable to set MPSSE bitmode: %s", libusb_error_name(err));
goto error;
}
@@ -368,14 +368,14 @@ void mpsse_purge(struct mpsse_ctx *ctx)
err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_RX, ctx->index, NULL, 0, ctx->usb_write_timeout);
if (err < 0) {
LOG_ERROR("unable to purge ftdi rx buffers: %d", err);
LOG_ERROR("unable to purge ftdi rx buffers: %s", libusb_error_name(err));
return;
}
err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_PURGE_TX, ctx->index, NULL, 0, ctx->usb_write_timeout);
if (err < 0) {
LOG_ERROR("unable to purge ftdi tx buffers: %d", err);
LOG_ERROR("unable to purge ftdi tx buffers: %s", libusb_error_name(err));
return;
}
}
@@ -837,7 +837,7 @@ int mpsse_flush(struct mpsse_ctx *ctx)
}
if (retval != LIBUSB_SUCCESS) {
LOG_ERROR("libusb_handle_events() failed with %d", retval);
LOG_ERROR("libusb_handle_events() failed with %s", libusb_error_name(retval));
retval = ERROR_FAIL;
} else if (write_result.transferred < ctx->write_count) {
LOG_ERROR("ftdi device did not accept all data: %d, tried %d",

View File

@@ -36,13 +36,12 @@
#include <jtag/commands.h>
#include "libusb_common.h"
#include <string.h>
#include <sys/timeb.h>
#include <time.h>
#define OPENDOUS_MAX_VIDS_PIDS 4
/* define some probes with similar interface */
struct opendous_probe {
char *name;
const char *name;
uint16_t VID[OPENDOUS_MAX_VIDS_PIDS];
uint16_t PID[OPENDOUS_MAX_VIDS_PIDS];
uint8_t READ_EP;
@@ -51,7 +50,7 @@ struct opendous_probe {
int BUFFERSIZE;
};
static struct opendous_probe opendous_probes[] = {
static const struct opendous_probe opendous_probes[] = {
{"usbprog-jtag", {0x1781, 0}, {0x0C63, 0}, 0x82, 0x02, 0x00, 510 },
{"opendous", {0x1781, 0x03EB, 0}, {0xC0C0, 0x204F, 0}, 0x81, 0x02, 0x00, 360 },
{"usbvlab", {0x16C0, 0}, {0x05DC, 0}, 0x81, 0x02, 0x01, 360 },
@@ -110,7 +109,7 @@ static struct pending_scan_result *pending_scan_results_buffer;
#define FUNC_READ_DATA 0x51
static char *opendous_type;
static struct opendous_probe *opendous_probe;
static const struct opendous_probe *opendous_probe;
/* External interface functions */
static int opendous_execute_queue(void);
@@ -150,9 +149,7 @@ static int opendous_usb_read(struct opendous_jtag *opendous_jtag);
int opendous_get_version_info(void);
#ifdef _DEBUG_USB_COMMS_
char time_str[50];
static void opendous_debug_buffer(uint8_t *buffer, int length);
char *opendous_get_time(char *);
#endif
static struct opendous_jtag *opendous_jtag_handle;
@@ -324,7 +321,7 @@ static int opendous_execute_queue(void)
static int opendous_init(void)
{
int check_cnt;
struct opendous_probe *cur_opendous_probe;
const struct opendous_probe *cur_opendous_probe;
cur_opendous_probe = opendous_probes;
@@ -712,7 +709,7 @@ struct opendous_jtag *opendous_usb_open(void)
struct opendous_jtag *result;
struct jtag_libusb_device_handle *devh;
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh) != ERROR_OK)
if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh) != ERROR_OK)
return NULL;
jtag_libusb_set_configuration(devh, 0);
@@ -760,7 +757,7 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("%s: USB write begin", opendous_get_time(time_str));
LOG_DEBUG("USB write begin");
#endif
if (opendous_probe->CONTROL_TRANSFER) {
result = jtag_libusb_control_transfer(opendous_jtag->usb_handle,
@@ -771,7 +768,7 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
(char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("%s: USB write end: %d bytes", opendous_get_time(time_str), result);
LOG_DEBUG("USB write end: %d bytes", result);
#endif
DEBUG_JTAG_IO("opendous_usb_write, out_length = %d, result = %d", out_length, result);
@@ -786,7 +783,7 @@ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length)
int opendous_usb_read(struct opendous_jtag *opendous_jtag)
{
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("%s: USB read begin", opendous_get_time(time_str));
LOG_DEBUG("USB read begin");
#endif
int result;
if (opendous_probe->CONTROL_TRANSFER) {
@@ -798,7 +795,7 @@ int opendous_usb_read(struct opendous_jtag *opendous_jtag)
(char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT);
}
#ifdef _DEBUG_USB_COMMS_
LOG_DEBUG("%s: USB read end: %d bytes", opendous_get_time(time_str), result);
LOG_DEBUG("USB read end: %d bytes", result);
#endif
DEBUG_JTAG_IO("opendous_usb_read, result = %d", result);
@@ -827,15 +824,4 @@ void opendous_debug_buffer(uint8_t *buffer, int length)
LOG_DEBUG("%s", line);
}
}
char *opendous_get_time(char *str)
{
struct timeb timebuffer;
char *timeline;
ftime(&timebuffer);
timeline = ctime(&(timebuffer.time));
snprintf(str, 49, "%.8s.%hu", &timeline[11], timebuffer.millitm);
return str;
}
#endif

View File

@@ -107,7 +107,7 @@ static struct queue *queue_alloc(void)
return queue;
}
/* Size of usb communnication buffer */
/* Size of usb communication buffer */
#define OSBDM_USB_BUFSIZE 64
/* Timeout for USB transfer, ms */
#define OSBDM_USB_TIMEOUT 1000
@@ -150,7 +150,7 @@ static int osbdm_send_and_recv(struct osbdm *osbdm)
(char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT);
if (count != osbdm->count) {
LOG_ERROR("OSBDM communnication error: can't write");
LOG_ERROR("OSBDM communication error: can't write");
return ERROR_FAIL;
}
@@ -165,22 +165,22 @@ static int osbdm_send_and_recv(struct osbdm *osbdm)
*/
if (osbdm->count < 0) {
LOG_ERROR("OSBDM communnication error: can't read");
LOG_ERROR("OSBDM communication error: can't read");
return ERROR_FAIL;
}
if (osbdm->count < 2) {
LOG_ERROR("OSBDM communnication error: answer too small");
LOG_ERROR("OSBDM communication error: reply too small");
return ERROR_FAIL;
}
if (osbdm->count != osbdm->buffer[1]) {
LOG_ERROR("OSBDM communnication error: answer size mismatch");
LOG_ERROR("OSBDM communication error: reply size mismatch");
return ERROR_FAIL;
}
if (cmd_saved != osbdm->buffer[0]) {
LOG_ERROR("OSBDM communnication error: answer command mismatch");
LOG_ERROR("OSBDM communication error: reply command mismatch");
return ERROR_FAIL;
}
@@ -219,7 +219,7 @@ static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi,
}
if (length <= 0) {
LOG_ERROR("BUG: bit sequence equal or less to 0");
LOG_ERROR("BUG: bit sequence equal or less than 0");
return ERROR_FAIL;
}
@@ -271,7 +271,7 @@ static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi,
/* Extra check
*/
if (((osbdm->buffer[2] << 8) | osbdm->buffer[3]) != 2 * swap_count) {
LOG_ERROR("OSBDM communnication error: not proper answer to swap command");
LOG_ERROR("OSBDM communication error: invalid swap command reply");
return ERROR_FAIL;
}
@@ -375,7 +375,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, &osbdm->devh) != ERROR_OK)
if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh) != ERROR_OK)
return ERROR_FAIL;
if (jtag_libusb_claim_interface(osbdm->devh, 0) != ERROR_OK)
@@ -678,7 +678,7 @@ static int osbdm_init(void)
return ERROR_FAIL;
} else {
/* Device successfully opened */
LOG_INFO("OSBDM has opened");
LOG_DEBUG("OSBDM init");
}
/* Perform initialize command */

View File

@@ -60,7 +60,7 @@
/* parallel port cable description
*/
struct cable {
char *name;
const char *name;
uint8_t TDO_MASK; /* status port bit containing current TDO value */
uint8_t TRST_MASK; /* data port bit for TRST */
uint8_t TMS_MASK; /* data port bit for TMS */
@@ -74,7 +74,7 @@ struct cable {
uint8_t LED_MASK; /* data port bit for LED */
};
static struct cable cables[] = {
static const struct cable cables[] = {
/* name tdo trst tms tck tdi srst o_inv i_inv init exit led */
{ "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
{ "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
@@ -108,7 +108,7 @@ static int wait_states;
/* interface variables
*/
static struct cable *cable;
static const struct cable *cable;
static uint8_t dataport_value;
#if PARPORT_USE_PPDEV == 1
@@ -262,7 +262,7 @@ static struct bitbang_interface parport_bitbang = {
static int parport_init(void)
{
struct cable *cur_cable;
const struct cable *cur_cable;
#if PARPORT_USE_PPDEV == 1
char buffer[256];
#endif

View File

@@ -66,6 +66,11 @@
* 8bit read/writes to max 64 bytes. */
#define STLINK_MAX_RW8 (64)
/* "WAIT" responses will be retried (with exponential backoff) at
* most this many times before failing to caller.
*/
#define MAX_WAIT_RETRIES 8
enum stlink_jtag_api_version {
STLINK_JTAG_API_V1 = 1,
STLINK_JTAG_API_V2,
@@ -119,18 +124,19 @@ struct stlink_usb_handle_s {
struct {
/** whether SWO tracing is enabled or not */
bool enabled;
/** trace data destination file */
FILE *output_f;
/** trace module source clock (for prescaler) */
/** trace module source clock */
uint32_t source_hz;
/** trace module clock prescaler */
uint32_t prescale;
} trace;
/** reconnect is needed next time we try to query the
* status */
bool reconnect_pending;
};
#define STLINK_DEBUG_ERR_OK 0x80
#define STLINK_DEBUG_ERR_FAULT 0x81
#define STLINK_SWD_AP_WAIT 0x10
#define STLINK_JTAG_WRITE_ERROR 0x0c
#define STLINK_JTAG_WRITE_VERIF_ERROR 0x0d
#define STLINK_SWD_DP_WAIT 0x14
#define STLINK_CORE_RUNNING 0x80
@@ -196,6 +202,7 @@ struct stlink_usb_handle_s {
#define STLINK_DEBUG_APIV2_START_TRACE_RX 0x40
#define STLINK_DEBUG_APIV2_STOP_TRACE_RX 0x41
#define STLINK_DEBUG_APIV2_GET_TRACE_NB 0x42
#define STLINK_DEBUG_APIV2_SWD_SET_FREQ 0x43
#define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00
#define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01
@@ -218,6 +225,24 @@ enum stlink_mode {
#define REQUEST_SENSE 0x03
#define REQUEST_SENSE_LENGTH 18
static const struct {
int speed;
int speed_divisor;
} stlink_khz_to_speed_map[] = {
{4000, 0},
{1800, 1}, /* default */
{1200, 2},
{950, 3},
{480, 7},
{240, 15},
{125, 31},
{100, 40},
{50, 79},
{25, 158},
{15, 265},
{5, 798}
};
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
/** */
@@ -340,6 +365,70 @@ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size)
return ERROR_OK;
}
/**
Converts an STLINK status code held in the first byte of a response
to an openocd error, logs any error/wait status as debug output.
*/
static int stlink_usb_error_check(void *handle)
{
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
/* TODO: no error checking yet on api V1 */
if (h->jtag_api == STLINK_JTAG_API_V1)
h->databuf[0] = STLINK_DEBUG_ERR_OK;
switch (h->databuf[0]) {
case STLINK_DEBUG_ERR_OK:
return ERROR_OK;
case STLINK_DEBUG_ERR_FAULT:
LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT);
return ERROR_FAIL;
case STLINK_SWD_AP_WAIT:
LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT);
return ERROR_WAIT;
case STLINK_SWD_DP_WAIT:
LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_AP_WAIT);
return ERROR_WAIT;
case STLINK_JTAG_WRITE_ERROR:
LOG_DEBUG("Write error");
return ERROR_FAIL;
case STLINK_JTAG_WRITE_VERIF_ERROR:
LOG_DEBUG("Verify error");
return ERROR_FAIL;
default:
LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]);
return ERROR_FAIL;
}
}
/** Issue an STLINK command via USB transfer, with retries on any wait status responses.
Works for commands where the STLINK_DEBUG status is returned in the first
byte of the response packet.
Returns an openocd result code.
*/
static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
{
int retries = 0;
int res;
while (1) {
res = stlink_usb_xfer(handle, buf, size);
if (res != ERROR_OK)
return res;
res = stlink_usb_error_check(handle);
if (res == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
return res;
}
}
/** */
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
{
@@ -391,40 +480,6 @@ static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t siz
stlink_usb_xfer_v1_create_cmd(handle, direction, size);
}
static const char * const stlink_usb_error_msg[] = {
"unknown"
};
/** */
static int stlink_usb_error_check(void *handle)
{
int res;
const char *err_msg = 0;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
/* TODO: no error checking yet on api V1 */
if (h->jtag_api == STLINK_JTAG_API_V1)
h->databuf[0] = STLINK_DEBUG_ERR_OK;
switch (h->databuf[0]) {
case STLINK_DEBUG_ERR_OK:
res = ERROR_OK;
break;
case STLINK_DEBUG_ERR_FAULT:
default:
err_msg = stlink_usb_error_msg[0];
res = ERROR_FAIL;
break;
}
if (res != ERROR_OK)
LOG_DEBUG("status error: %d ('%s')", h->databuf[0], err_msg);
return res;
}
/** */
static int stlink_usb_version(void *handle)
{
@@ -502,6 +557,31 @@ static int stlink_usb_check_voltage(void *handle, float *target_voltage)
return ERROR_OK;
}
static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
{
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
/* only supported by stlink/v2 and for firmware >= 22 */
if (h->version.stlink == 1 || h->version.jtag < 22)
return ERROR_COMMAND_NOTFOUND;
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
h_u16_to_le(h->cmdbuf+h->cmdidx, clk_divisor);
h->cmdidx += 2;
int result = stlink_cmd_allow_retry(handle, h->databuf, 2);
if (result != ERROR_OK)
return result;
return ERROR_OK;
}
/** */
static int stlink_usb_current_mode(void *handle, uint8_t *mode)
{
@@ -527,7 +607,6 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode)
/** */
static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
{
int res;
int rx_size = 0;
struct stlink_usb_handle_s *h = handle;
@@ -569,14 +648,7 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
return ERROR_FAIL;
}
res = stlink_usb_xfer(handle, h->databuf, rx_size);
if (res != ERROR_OK)
return res;
res = stlink_usb_error_check(h);
return res;
return stlink_cmd_allow_retry(handle, h->databuf, rx_size);
}
/** */
@@ -618,6 +690,20 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
static int stlink_usb_assert_srst(void *handle, int srst);
static enum stlink_mode stlink_get_mode(enum hl_transports t)
{
switch (t) {
case HL_TRANSPORT_SWD:
return STLINK_MODE_DEBUG_SWD;
case HL_TRANSPORT_JTAG:
return STLINK_MODE_DEBUG_JTAG;
case HL_TRANSPORT_SWIM:
return STLINK_MODE_DEBUG_SWIM;
default:
return STLINK_MODE_UNKNOWN;
}
}
/** */
static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
{
@@ -691,20 +777,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset)
LOG_DEBUG("MODE: 0x%02X", mode);
/* set selected mode */
switch (h->transport) {
case HL_TRANSPORT_SWD:
emode = STLINK_MODE_DEBUG_SWD;
break;
case HL_TRANSPORT_JTAG:
emode = STLINK_MODE_DEBUG_JTAG;
break;
case HL_TRANSPORT_SWIM:
emode = STLINK_MODE_DEBUG_SWIM;
break;
default:
emode = STLINK_MODE_UNKNOWN;
break;
}
emode = stlink_get_mode(h->transport);
if (emode == STLINK_MODE_UNKNOWN) {
LOG_ERROR("selected mode (transport) not supported");
@@ -771,19 +844,16 @@ static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *v
h_u32_to_le(h->cmdbuf+h->cmdidx, addr);
h->cmdidx += 4;
res = stlink_usb_xfer(handle, h->databuf, 8);
res = stlink_cmd_allow_retry(handle, h->databuf, 8);
if (res != ERROR_OK)
return res;
*val = le_to_h_u32(h->databuf + 4);
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return ERROR_OK;
}
static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
@@ -800,16 +870,11 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
h_u32_to_le(h->cmdbuf+h->cmdidx, val);
h->cmdidx += 4;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
/** */
static void stlink_usb_trace_read(void *handle)
static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
{
struct stlink_usb_handle_s *h = handle;
@@ -824,29 +889,20 @@ static void stlink_usb_trace_read(void *handle)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GET_TRACE_NB;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res == ERROR_OK) {
uint8_t buf[STLINK_TRACE_SIZE];
size_t size = le_to_h_u16(h->databuf);
if (res != ERROR_OK)
return res;
if (size > 0) {
size = size < sizeof(buf) ? size : sizeof(buf) - 1;
size_t bytes_avail = le_to_h_u16(h->databuf);
*size = bytes_avail < *size ? bytes_avail : *size - 1;
res = stlink_usb_read_trace(handle, buf, size);
if (res == ERROR_OK) {
if (h->trace.output_f) {
/* Log retrieved trace output */
if (fwrite(buf, 1, size, h->trace.output_f) > 0)
fflush(h->trace.output_f);
}
}
}
if (*size > 0) {
res = stlink_usb_read_trace(handle, buf, *size);
if (res != ERROR_OK)
return res;
return ERROR_OK;
}
}
}
static int stlink_usb_trace_read_callback(void *handle)
{
stlink_usb_trace_read(handle);
*size = 0;
return ERROR_OK;
}
@@ -864,8 +920,6 @@ static enum target_state stlink_usb_v2_get_status(void *handle)
else if (status & S_RESET_ST)
return TARGET_RESET;
stlink_usb_trace_read(handle);
return TARGET_RUNNING;
}
@@ -877,8 +931,22 @@ static enum target_state stlink_usb_state(void *handle)
assert(handle != NULL);
if (h->jtag_api == STLINK_JTAG_API_V2)
return stlink_usb_v2_get_status(handle);
if (h->reconnect_pending) {
LOG_INFO("Previous state query failed, trying to reconnect");
res = stlink_usb_mode_enter(handle, stlink_get_mode(h->transport));
if (res != ERROR_OK)
return TARGET_UNKNOWN;
h->reconnect_pending = false;
}
if (h->jtag_api == STLINK_JTAG_API_V2) {
res = stlink_usb_v2_get_status(handle);
if (res == TARGET_UNKNOWN)
h->reconnect_pending = true;
return res;
}
stlink_usb_init_buffer(handle, h->rx_ep, 2);
@@ -895,48 +963,18 @@ static enum target_state stlink_usb_state(void *handle)
if (h->databuf[0] == STLINK_CORE_HALTED)
return TARGET_HALTED;
h->reconnect_pending = true;
return TARGET_UNKNOWN;
}
/** */
static int stlink_usb_reset(void *handle)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
if (h->jtag_api == STLINK_JTAG_API_V1)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
LOG_DEBUG("RESET: 0x%08X", h->databuf[0]);
/* the following is not a error under swd (using hardware srst), so return success */
if (h->databuf[0] == STLINK_SWD_AP_WAIT || h->databuf[0] == STLINK_SWD_DP_WAIT)
return ERROR_OK;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
}
static int stlink_usb_assert_srst(void *handle, int srst)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
if (h->jtag_api == STLINK_JTAG_API_V1)
if (h->version.stlink == 1)
return ERROR_COMMAND_NOTFOUND;
stlink_usb_init_buffer(handle, h->rx_ep, 2);
@@ -945,68 +983,7 @@ static int stlink_usb_assert_srst(void *handle, int srst)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_DRIVE_NRST;
h->cmdbuf[h->cmdidx++] = srst;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
}
/** */
static int stlink_configure_target_trace_port(void *handle)
{
int res;
uint32_t reg;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
/* configure the TPI */
/* enable the trace subsystem */
res = stlink_usb_v2_read_debug_reg(handle, DCB_DEMCR, &reg);
if (res != ERROR_OK)
goto out;
res = stlink_usb_write_debug_reg(handle, DCB_DEMCR, TRCENA|reg);
if (res != ERROR_OK)
goto out;
/* set the TPI clock prescaler */
res = stlink_usb_write_debug_reg(handle, TPI_ACPR, h->trace.prescale);
if (res != ERROR_OK)
goto out;
/* select the pin protocol. The STLinkv2 only supports asynchronous
* UART emulation (NRZ) mode, so that's what we pick. */
res = stlink_usb_write_debug_reg(handle, TPI_SPPR, 0x02);
if (res != ERROR_OK)
goto out;
/* disable continuous formatting */
res = stlink_usb_write_debug_reg(handle, TPI_FFCR, (1<<8));
if (res != ERROR_OK)
goto out;
/* configure the ITM */
/* unlock access to the ITM registers */
res = stlink_usb_write_debug_reg(handle, ITM_LAR, 0xC5ACCE55);
if (res != ERROR_OK)
goto out;
/* enable trace with ATB ID 1 */
res = stlink_usb_write_debug_reg(handle, ITM_TCR, (1<<16)|(1<<0)|(1<<2));
if (res != ERROR_OK)
goto out;
/* trace privilege */
res = stlink_usb_write_debug_reg(handle, ITM_TPR, 1);
if (res != ERROR_OK)
goto out;
/* trace port enable (port 0) */
res = stlink_usb_write_debug_reg(handle, ITM_TER, (1<<0));
if (res != ERROR_OK)
goto out;
res = ERROR_OK;
out:
return res;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
/** */
@@ -1019,17 +996,15 @@ static void stlink_usb_trace_disable(void *handle)
assert(h->version.jtag >= STLINK_TRACE_MIN_VERSION);
LOG_DEBUG("Tracing: disable\n");
LOG_DEBUG("Tracing: disable");
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res == ERROR_OK) {
if (res == ERROR_OK)
h->trace.enabled = false;
target_unregister_timer_callback(stlink_usb_trace_read_callback, handle);
}
}
@@ -1042,38 +1017,20 @@ static int stlink_usb_trace_enable(void *handle)
assert(handle != NULL);
if (h->version.jtag >= STLINK_TRACE_MIN_VERSION) {
uint32_t trace_hz;
res = stlink_configure_target_trace_port(handle);
if (res != ERROR_OK)
LOG_ERROR("Unable to configure tracing on target\n");
trace_hz = h->trace.prescale > 0 ?
h->trace.source_hz / (h->trace.prescale + 1) :
h->trace.source_hz;
stlink_usb_init_buffer(handle, h->rx_ep, 10);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_START_TRACE_RX;
h_u16_to_le(h->cmdbuf+h->cmdidx, (uint16_t)STLINK_TRACE_SIZE);
h->cmdidx += 2;
h_u32_to_le(h->cmdbuf+h->cmdidx, trace_hz);
h_u32_to_le(h->cmdbuf+h->cmdidx, h->trace.source_hz);
h->cmdidx += 4;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res == ERROR_OK) {
h->trace.enabled = true;
LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz\n", trace_hz);
/* We need the trace read function to be called at a
* high-enough frequency to ensure reasonable
* "timeliness" in processing ITM/DWT data.
* TODO: An alternative could be using the asynchronous
* features of the libusb-1.0 API to queue up one or more
* reads in advance and requeue them once they are
* completed. */
target_register_timer_callback(stlink_usb_trace_read_callback, 1, 1, handle);
LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", h->trace.source_hz);
}
} else {
LOG_ERROR("Tracing is not supported by this version.");
@@ -1083,6 +1040,35 @@ static int stlink_usb_trace_enable(void *handle)
return res;
}
/** */
static int stlink_usb_reset(void *handle)
{
struct stlink_usb_handle_s *h = handle;
int retval;
assert(handle != NULL);
stlink_usb_init_buffer(handle, h->rx_ep, 2);
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
if (h->jtag_api == STLINK_JTAG_API_V1)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS;
else
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS;
retval = stlink_cmd_allow_retry(handle, h->databuf, 2);
if (retval != ERROR_OK)
return retval;
if (h->trace.enabled) {
stlink_usb_trace_disable(h);
return stlink_usb_trace_enable(h);
}
return ERROR_OK;
}
/** */
static int stlink_usb_run(void *handle)
{
@@ -1094,14 +1080,6 @@ static int stlink_usb_run(void *handle)
if (h->jtag_api == STLINK_JTAG_API_V2) {
res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN);
/* Try to start tracing, if requested */
if (res == ERROR_OK && h->trace.source_hz && !h->trace.enabled) {
if (stlink_usb_trace_enable(handle) == ERROR_OK)
LOG_DEBUG("Tracing: enabled\n");
else
LOG_ERROR("Tracing: enable failed\n");
}
return res;
}
@@ -1110,12 +1088,7 @@ static int stlink_usb_run(void *handle)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_RUNCORE;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
/** */
@@ -1129,9 +1102,6 @@ static int stlink_usb_halt(void *handle)
if (h->jtag_api == STLINK_JTAG_API_V2) {
res = stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN);
if (res == ERROR_OK && h->trace.enabled)
stlink_usb_trace_disable(handle);
return res;
}
@@ -1140,18 +1110,12 @@ static int stlink_usb_halt(void *handle)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_FORCEDEBUG;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
/** */
static int stlink_usb_step(void *handle)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
@@ -1169,12 +1133,7 @@ static int stlink_usb_step(void *handle)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_STEPCORE;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
/** */
@@ -1218,25 +1177,24 @@ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val)
h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG;
h->cmdbuf[h->cmdidx++] = num;
res = stlink_usb_xfer(handle, h->databuf, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8);
if (res != ERROR_OK)
return res;
if (h->jtag_api == STLINK_JTAG_API_V1)
if (h->jtag_api == STLINK_JTAG_API_V1) {
res = stlink_usb_xfer(handle, h->databuf, 4);
if (res != ERROR_OK)
return res;
*val = le_to_h_u32(h->databuf);
else {
return ERROR_OK;
} else {
res = stlink_cmd_allow_retry(handle, h->databuf, 8);
if (res != ERROR_OK)
return res;
*val = le_to_h_u32(h->databuf + 4);
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return ERROR_OK;
}
return ERROR_OK;
}
/** */
static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
{
int res;
struct stlink_usb_handle_s *h = handle;
assert(handle != NULL);
@@ -1252,12 +1210,7 @@ static int stlink_usb_write_reg(void *handle, int num, uint32_t val)
h_u32_to_le(h->cmdbuf+h->cmdidx, val);
h->cmdidx += 4;
res = stlink_usb_xfer(handle, h->databuf, 2);
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL;
return stlink_cmd_allow_retry(handle, h->databuf, 2);
}
static int stlink_usb_get_rw_status(void *handle)
@@ -1280,7 +1233,7 @@ static int stlink_usb_get_rw_status(void *handle)
if (res != ERROR_OK)
return res;
return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : res;
return stlink_usb_error_check(h);
}
/** */
@@ -1433,6 +1386,7 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
{
int retval = ERROR_OK;
uint32_t bytes_remaining;
int retries = 0;
struct stlink_usb_handle_s *h = handle;
/* calculate byte count */
@@ -1463,6 +1417,10 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t head_bytes = 4 - (addr % 4);
retval = stlink_usb_read_mem8(handle, addr, head_bytes, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
return retval;
buffer += head_bytes;
@@ -1478,6 +1436,10 @@ static int stlink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
} else
retval = stlink_usb_read_mem8(handle, addr, bytes_remaining, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
return retval;
@@ -1494,6 +1456,7 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
{
int retval = ERROR_OK;
uint32_t bytes_remaining;
int retries = 0;
struct stlink_usb_handle_s *h = handle;
/* calculate byte count */
@@ -1524,6 +1487,10 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t head_bytes = 4 - (addr % 4);
retval = stlink_usb_write_mem8(handle, addr, head_bytes, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
return retval;
buffer += head_bytes;
@@ -1539,6 +1506,10 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
} else
retval = stlink_usb_write_mem8(handle, addr, bytes_remaining, buffer);
if (retval == ERROR_WAIT && retries < MAX_WAIT_RETRIES) {
usleep((1<<retries++) * 1000);
continue;
}
if (retval != ERROR_OK)
return retval;
@@ -1551,14 +1522,72 @@ static int stlink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
}
/** */
static int stlink_usb_close(void *fd)
static int stlink_usb_override_target(const char *targetname)
{
struct stlink_usb_handle_s *h = fd;
return !strcmp(targetname, "cortex_m");
}
if (h->fd)
static int stlink_speed(void *handle, int khz, bool query)
{
unsigned i;
int speed_index = -1;
int speed_diff = INT_MAX;
struct stlink_usb_handle_s *h = handle;
/* only supported by stlink/v2 and for firmware >= 22 */
if (h && (h->version.stlink == 1 || h->version.jtag < 22))
return khz;
for (i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++) {
if (khz == stlink_khz_to_speed_map[i].speed) {
speed_index = i;
break;
} else {
int current_diff = khz - stlink_khz_to_speed_map[i].speed;
/* get abs value for comparison */
current_diff = (current_diff > 0) ? current_diff : -current_diff;
if ((current_diff < speed_diff) && khz >= stlink_khz_to_speed_map[i].speed) {
speed_diff = current_diff;
speed_index = i;
}
}
}
bool match = true;
if (speed_index == -1) {
/* this will only be here if we cannot match the slow speed.
* use the slowest speed we support.*/
speed_index = ARRAY_SIZE(stlink_khz_to_speed_map) - 1;
match = false;
} else if (i == ARRAY_SIZE(stlink_khz_to_speed_map))
match = false;
if (!match && query) {
LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \
khz, stlink_khz_to_speed_map[speed_index].speed);
}
if (h && !query) {
int result = stlink_usb_set_swdclk(h, stlink_khz_to_speed_map[speed_index].speed_divisor);
if (result != ERROR_OK) {
LOG_ERROR("Unable to set adapter speed");
return khz;
}
}
return stlink_khz_to_speed_map[speed_index].speed;
}
/** */
static int stlink_usb_close(void *handle)
{
struct stlink_usb_handle_s *h = handle;
if (h && h->fd)
jtag_libusb_close(h->fd);
free(fd);
free(h);
return ERROR_OK;
}
@@ -1583,9 +1612,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
const uint16_t vids[] = { param->vid, 0 };
const uint16_t pids[] = { param->pid, 0 };
const char *serial = param->serial;
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
param->vid, param->pid);
LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
param->transport, param->vid, param->pid,
param->serial ? param->serial : "");
/*
On certain host USB configurations(e.g. MacBook Air)
@@ -1597,7 +1628,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
in order to become operational.
*/
do {
if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) {
if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) {
LOG_ERROR("open failed");
goto error_open;
}
@@ -1701,25 +1732,24 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
/* set the used jtag api, this will default to the newest supported version */
h->jtag_api = api;
if (h->jtag_api >= 2 && param->trace_source_hz > 0) {
uint32_t prescale;
prescale = param->trace_source_hz > STLINK_TRACE_MAX_HZ ?
(param->trace_source_hz / STLINK_TRACE_MAX_HZ) - 1 : 0;
h->trace.output_f = param->trace_f;
h->trace.source_hz = param->trace_source_hz;
h->trace.prescale = prescale;
}
/* initialize the debug hardware */
err = stlink_usb_init_mode(h, param->connect_under_reset);
if (err != ERROR_OK) {
LOG_ERROR("init mode failed");
LOG_ERROR("init mode failed (unable to connect to the target)");
goto error_open;
}
/* clock speed only supported by stlink/v2 and for firmware >= 22 */
if (h->version.stlink >= 2 && h->version.jtag >= 22) {
LOG_DEBUG("Supported clock speeds are:");
for (unsigned i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++)
LOG_DEBUG("%d kHz", stlink_khz_to_speed_map[i].speed);
stlink_speed(h, param->initial_interface_speed, false);
}
/* get cpuid, so we can determine the max page size
* start with a safe default */
h->max_mem_packet = (1 << 10);
@@ -1747,6 +1777,36 @@ error_open:
return ERROR_FAIL;
}
int stlink_config_trace(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
struct stlink_usb_handle_s *h = handle;
if (enabled && (h->jtag_api < 2 || pin_protocol != ASYNC_UART)) {
LOG_ERROR("The attached ST-LINK version doesn't support this trace mode");
return ERROR_FAIL;
}
if (!enabled) {
stlink_usb_trace_disable(h);
return ERROR_OK;
}
if (*trace_freq > STLINK_TRACE_MAX_HZ) {
LOG_ERROR("ST-LINK doesn't support SWO frequency higher than %u",
STLINK_TRACE_MAX_HZ);
return ERROR_FAIL;
}
stlink_usb_trace_disable(h);
if (!*trace_freq)
*trace_freq = STLINK_TRACE_MAX_HZ;
h->trace.source_hz = *trace_freq;
return stlink_usb_trace_enable(h);
}
/** */
struct hl_layout_api_s stlink_usb_layout_api = {
/** */
@@ -1778,5 +1838,13 @@ struct hl_layout_api_s stlink_usb_layout_api = {
/** */
.write_mem = stlink_usb_write_mem,
/** */
.write_debug_reg = stlink_usb_write_debug_reg
.write_debug_reg = stlink_usb_write_debug_reg,
/** */
.override_target = stlink_usb_override_target,
/** */
.speed = stlink_speed,
/** */
.config_trace = stlink_config_trace,
/** */
.poll_trace = stlink_usb_trace_read,
};

View File

@@ -16,6 +16,10 @@
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
/* 2014-12: Addition of the SWD protocol support is based on the initial work
* on bcm2835gpio.c by Paul Fertser and modifications by Jean-Christian de Rivaz. */
/**
* @file
* This driver implements a bitbang jtag interface using gpio lines via
@@ -139,17 +143,26 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
}
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
if (is_output)
ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC);
else
ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC);
if (ret < 0)
ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
if (ret < 0) {
LOG_ERROR("Couldn't open value for gpio %d", gpio);
perror("sysfsgpio: ");
unexport_sysfs_gpio(gpio);
}
return ret;
}
/* gpio numbers for each gpio. Negative values are invalid */
static int tck_gpio = -1;
static int tms_gpio = -1;
static int tdi_gpio = -1;
static int tdo_gpio = -1;
static int trst_gpio = -1;
static int srst_gpio = -1;
static int swclk_gpio = -1;
static int swdio_gpio = -1;
/*
* file descriptors for /sys/class/gpio/gpioXX/value
* Set up during init.
@@ -160,6 +173,72 @@ static int tdi_fd = -1;
static int tdo_fd = -1;
static int trst_fd = -1;
static int srst_fd = -1;
static int swclk_fd = -1;
static int swdio_fd = -1;
static int last_swclk;
static int last_swdio;
static bool last_stored;
static bool swdio_input;
static void sysfsgpio_swdio_drive(bool is_output)
{
char buf[40];
int ret;
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", swdio_gpio);
ret = open_write_close(buf, is_output ? "high" : "in");
if (ret < 0) {
LOG_ERROR("Couldn't set direction for gpio %d", swdio_gpio);
perror("sysfsgpio: ");
}
last_stored = false;
swdio_input = !is_output;
}
static int sysfsgpio_swdio_read(void)
{
char buf[1];
/* important to seek to signal sysfs of new read */
lseek(swdio_fd, 0, SEEK_SET);
int ret = read(swdio_fd, &buf, sizeof(buf));
if (ret < 0) {
LOG_WARNING("reading swdio failed");
return 0;
}
return buf[0] == '1';
}
static void sysfsgpio_swdio_write(int swclk, int swdio)
{
const char one[] = "1";
const char zero[] = "0";
size_t bytes_written;
if (!swdio_input) {
if (!last_stored || (swdio != last_swdio)) {
bytes_written = write(swdio_fd, swdio ? &one : &zero, 1);
if (bytes_written != 1)
LOG_WARNING("writing swdio failed");
}
}
/* write swclk last */
if (!last_stored || (swclk != last_swclk)) {
bytes_written = write(swclk_fd, swclk ? &one : &zero, 1);
if (bytes_written != 1)
LOG_WARNING("writing swclk failed");
}
last_swdio = swdio;
last_swclk = swclk;
last_stored = true;
}
/*
* Bitbang interface read of TDO
@@ -191,6 +270,11 @@ static int sysfsgpio_read(void)
*/
static void sysfsgpio_write(int tck, int tms, int tdi)
{
if (swd_mode) {
sysfsgpio_swdio_write(tck, tdi);
return;
}
const char one[] = "1";
const char zero[] = "0";
@@ -239,6 +323,7 @@ static void sysfsgpio_write(int tck, int tms, int tdi)
*/
static void sysfsgpio_reset(int trst, int srst)
{
LOG_DEBUG("sysfsgpio_reset");
const char one[] = "1";
const char zero[] = "0";
size_t bytes_written;
@@ -258,14 +343,6 @@ static void sysfsgpio_reset(int trst, int srst)
}
}
/* gpio numbers for each gpio. Negative values are invalid */
static int tck_gpio = -1;
static int tms_gpio = -1;
static int tdi_gpio = -1;
static int tdo_gpio = -1;
static int trst_gpio = -1;
static int srst_gpio = -1;
COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums)
{
if (CMD_ARGC == 4) {
@@ -338,6 +415,40 @@ COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst)
return ERROR_OK;
}
COMMAND_HANDLER(sysfsgpio_handle_swd_gpionums)
{
if (CMD_ARGC == 2) {
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], swdio_gpio);
} else if (CMD_ARGC != 0) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
command_print(CMD_CTX,
"SysfsGPIO nums: swclk = %d, swdio = %d",
swclk_gpio, swdio_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swclk)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swclk_gpio);
command_print(CMD_CTX, "SysfsGPIO num: swclk = %d", swclk_gpio);
return ERROR_OK;
}
COMMAND_HANDLER(sysfsgpio_handle_swd_gpionum_swdio)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], swdio_gpio);
command_print(CMD_CTX, "SysfsGPIO num: swdio = %d", swdio_gpio);
return ERROR_OK;
}
static const struct command_registration sysfsgpio_command_handlers[] = {
{
.name = "sysfsgpio_jtag_nums",
@@ -382,17 +493,39 @@ static const struct command_registration sysfsgpio_command_handlers[] = {
.mode = COMMAND_CONFIG,
.help = "gpio number for trst.",
},
{
.name = "sysfsgpio_swd_nums",
.handler = &sysfsgpio_handle_swd_gpionums,
.mode = COMMAND_CONFIG,
.help = "gpio numbers for swclk, swdio. (in that order)",
.usage = "(swclk swdio)* ",
},
{
.name = "sysfsgpio_swclk_num",
.handler = &sysfsgpio_handle_swd_gpionum_swclk,
.mode = COMMAND_CONFIG,
.help = "gpio number for swclk.",
},
{
.name = "sysfsgpio_swdio_num",
.handler = &sysfsgpio_handle_swd_gpionum_swdio,
.mode = COMMAND_CONFIG,
.help = "gpio number for swdio.",
},
COMMAND_REGISTRATION_DONE
};
static int sysfsgpio_init(void);
static int sysfsgpio_quit(void);
static const char * const sysfsgpio_transports[] = { "jtag", "swd", NULL };
struct jtag_interface sysfsgpio_interface = {
.name = "sysfsgpio",
.supported = DEBUG_CAP_TMS_SEQ,
.execute_queue = bitbang_execute_queue,
.transports = jtag_only,
.transports = sysfsgpio_transports,
.swd = &bitbang_swd,
.commands = sysfsgpio_command_handlers,
.init = sysfsgpio_init,
.quit = sysfsgpio_quit,
@@ -402,6 +535,8 @@ static struct bitbang_interface sysfsgpio_bitbang = {
.read = sysfsgpio_read,
.write = sysfsgpio_write,
.reset = sysfsgpio_reset,
.swdio_read = sysfsgpio_swdio_read,
.swdio_drive = sysfsgpio_swdio_drive,
.blink = 0
};
@@ -426,68 +561,113 @@ static void cleanup_all_fds(void)
cleanup_fd(srst_fd, srst_gpio);
}
static bool sysfsgpio_jtag_mode_possible(void)
{
if (!is_gpio_valid(tck_gpio))
return 0;
if (!is_gpio_valid(tms_gpio))
return 0;
if (!is_gpio_valid(tdi_gpio))
return 0;
if (!is_gpio_valid(tdo_gpio))
return 0;
return 1;
}
static bool sysfsgpio_swd_mode_possible(void)
{
if (!is_gpio_valid(swclk_gpio))
return 0;
if (!is_gpio_valid(swdio_gpio))
return 0;
return 1;
}
static int sysfsgpio_init(void)
{
bitbang_interface = &sysfsgpio_bitbang;
LOG_INFO("SysfsGPIO JTAG bitbang driver");
LOG_INFO("SysfsGPIO JTAG/SWD bitbang driver");
if (!(is_gpio_valid(tck_gpio)
&& is_gpio_valid(tms_gpio)
&& is_gpio_valid(tdi_gpio)
&& is_gpio_valid(tdo_gpio))) {
if (!is_gpio_valid(tck_gpio))
LOG_ERROR("gpio num for tck is invalid");
if (!is_gpio_valid(tms_gpio))
LOG_ERROR("gpio num for tms is invalid");
if (!is_gpio_valid(tdo_gpio))
LOG_ERROR("gpio num for tdo is invalid");
if (!is_gpio_valid(tdi_gpio))
LOG_ERROR("gpio num for tdi is invalid");
LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified");
if (sysfsgpio_jtag_mode_possible()) {
if (sysfsgpio_swd_mode_possible())
LOG_INFO("JTAG and SWD modes enabled");
else
LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) {
LOG_ERROR("Require at least one of trst or srst gpios to be specified");
return ERROR_JTAG_INIT_FAILED;
}
} else if (sysfsgpio_swd_mode_possible()) {
LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
} else {
LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
return ERROR_JTAG_INIT_FAILED;
}
if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) {
LOG_ERROR("Require at least one of trst or srst gpios to be specified");
return ERROR_JTAG_INIT_FAILED;
}
/*
* Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST
* as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high.
* For SWD, SWCLK and SWDIO are configures as output high.
*/
tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0);
if (tck_fd < 0)
goto out_error;
if (tck_gpio >= 0) {
tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0);
if (tck_fd < 0)
goto out_error;
}
tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
if (tms_fd < 0)
goto out_error;
if (tms_gpio >= 0) {
tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1);
if (tms_fd < 0)
goto out_error;
}
tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
if (tdi_fd < 0)
goto out_error;
if (tdi_gpio >= 0) {
tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0);
if (tdi_fd < 0)
goto out_error;
}
tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
if (tdo_fd < 0)
goto out_error;
if (tdo_gpio >= 0) {
tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0);
if (tdo_fd < 0)
goto out_error;
}
/* assume active low*/
if (trst_gpio > 0) {
if (trst_gpio >= 0) {
trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1);
if (trst_fd < 0)
goto out_error;
}
/* assume active low*/
if (srst_gpio > 0) {
if (srst_gpio >= 0) {
srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1);
if (srst_fd < 0)
goto out_error;
}
if (swclk_gpio >= 0) {
swclk_fd = setup_sysfs_gpio(swclk_gpio, 1, 0);
if (swclk_fd < 0)
goto out_error;
}
if (swdio_gpio >= 0) {
swdio_fd = setup_sysfs_gpio(swdio_gpio, 1, 0);
if (swdio_fd < 0)
goto out_error;
}
if (sysfsgpio_swd_mode_possible()) {
if (swd_mode)
bitbang_swd_switch_seq(NULL, JTAG_TO_SWD);
else
bitbang_swd_switch_seq(NULL, SWD_TO_JTAG);
}
return ERROR_OK;
out_error:

View File

@@ -645,10 +645,18 @@ static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
return retval;
}
static int icdi_usb_override_target(const char *targetname)
{
return !strcmp(targetname, "cortex_m");
}
static int icdi_usb_close(void *handle)
{
struct icdi_usb_handle_s *h = handle;
if (!h)
return ERROR_OK;
if (h->usb_dev)
libusb_close(h->usb_dev);
@@ -770,5 +778,7 @@ struct hl_layout_api_s icdi_usb_layout_api = {
.write_reg = icdi_usb_write_reg,
.read_mem = icdi_usb_read_mem,
.write_mem = icdi_usb_write_mem,
.write_debug_reg = icdi_usb_write_debug_reg
.write_debug_reg = icdi_usb_write_debug_reg,
.override_target = icdi_usb_override_target,
.custom_command = icdi_send_remote_cmd,
};

View File

@@ -461,9 +461,6 @@ int ulink_write_firmware_section(struct ulink *device,
LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr,
size);
if (data == NULL)
return ERROR_FAIL;
/* Copy section contents to local buffer */
ret = image_read_section(firmware_image, section_index, 0, size, data,
&size_read);

View File

@@ -74,9 +74,6 @@ static int ublast2_write_firmware_section(struct jtag_libusb_device_handle *libu
LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr,
size);
if (data == NULL)
return ERROR_FAIL;
/* Copy section contents to local buffer */
int ret = image_read_section(firmware_image, section_index, 0, size, data,
&size_read);
@@ -186,7 +183,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low)
bool renumeration = false;
int ret;
if (jtag_libusb_open(vids, pids, &temp) == ERROR_OK) {
if (jtag_libusb_open(vids, pids, NULL, &temp) == ERROR_OK) {
LOG_INFO("Altera USB-Blaster II (uninitialized) found");
LOG_INFO("Loading firmware...");
ret = load_usb_blaster_firmware(temp, low);
@@ -200,13 +197,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, &low->libusb_dev) != ERROR_OK) {
if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != 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, &low->libusb_dev) != ERROR_OK && retry--) {
while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev) != ERROR_OK && retry--) {
usleep(1000000);
LOG_INFO("Waiting for renumerate...");
}

View File

@@ -756,11 +756,41 @@ static void ublast_usleep(int us)
jtag_sleep(us);
}
static void ublast_initial_wipeout(void)
{
static uint8_t tms_reset = 0xff;
uint8_t out_value;
uint32_t retlen;
int i;
out_value = ublast_build_out(SCAN_OUT);
for (i = 0; i < BUF_LEN; i++)
info.buf[i] = out_value | ((i % 2) ? TCK : 0);
/*
* Flush USB-Blaster queue fifos
* - empty the write FIFO (128 bytes)
* - empty the read FIFO (384 bytes)
*/
ublast_buf_write(info.buf, BUF_LEN, &retlen);
/*
* Put JTAG in RESET state (five 1 on TMS)
*/
ublast_tms_seq(&tms_reset, 5);
tap_set_state(TAP_RESET);
}
static int ublast_execute_queue(void)
{
struct jtag_command *cmd;
static int first_call = 1;
int ret = ERROR_OK;
if (first_call) {
first_call--;
ublast_initial_wipeout();
}
for (cmd = jtag_command_queue; ret == ERROR_OK && cmd != NULL;
cmd = cmd->next) {
switch (cmd->type) {
@@ -801,14 +831,12 @@ static int ublast_execute_queue(void)
*
* Initialize the device :
* - open the USB device
* - empty the write FIFO (128 bytes)
* - empty the read FIFO (384 bytes)
* - pretend it's initialized while actual init is delayed until first jtag command
*
* Returns ERROR_OK if USB device found, error if not.
*/
static int ublast_init(void)
{
static uint8_t tms_reset = 0xff;
int ret, i;
if (info.lowlevel_name) {
@@ -846,18 +874,13 @@ static int ublast_init(void)
info.flags |= info.drv->flags;
ret = info.drv->open(info.drv);
if (ret == ERROR_OK) {
/*
* Flush USB-Blaster queue fifos
*/
uint32_t retlen;
ublast_buf_write(info.buf, BUF_LEN, &retlen);
/*
* Put JTAG in RESET state (five 1 on TMS)
*/
ublast_tms_seq(&tms_reset, 5);
tap_set_state(TAP_RESET);
}
/*
* Let lie here : the TAP is in an unknown state, but the first
* execute_queue() will trigger a ublast_initial_wipeout(), which will
* put the TAP in RESET.
*/
tap_set_state(TAP_RESET);
return ret;
}

View File

@@ -30,7 +30,7 @@
#include "usbtoxxx.h"
#include "usbtoxxx_internal.h"
RESULT usbtoswd_callback(void *p, uint8_t *src, uint8_t *processed)
RESULT usbtoswd_read_callback(void *p, uint8_t *src, uint8_t *processed)
{
struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p;
@@ -40,6 +40,18 @@ RESULT usbtoswd_callback(void *p, uint8_t *src, uint8_t *processed)
return ERROR_OK;
}
RESULT usbtoswd_write_callback(void *p, uint8_t *src, uint8_t *processed)
{
struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p;
if (pending->extra_data != NULL)
*((uint8_t *)pending->extra_data) = src[0];
/* mark it processed to ignore other input data */
*processed = 1;
return ERROR_OK;
}
RESULT usbtoswd_init(uint8_t interface_index)
{
return usbtoxxx_init_command(USB_TO_SWD, interface_index);
@@ -69,7 +81,8 @@ RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry,
return usbtoxxx_conf_command(USB_TO_SWD, interface_index, cfg_buf, 5);
}
RESULT usbtoswd_seqout(uint8_t interface_index, uint8_t *data, uint16_t bitlen)
RESULT usbtoswd_seqout(uint8_t interface_index, const uint8_t *data,
uint16_t bitlen)
{
uint16_t bytelen = (bitlen + 7) >> 3;
@@ -130,14 +143,16 @@ RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request,
memset(buff + 1, 0, 4);
versaloon_set_extra_data(ack);
versaloon_set_callback(usbtoswd_callback);
if (request & 0x04) {
/* read */
return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5,
(uint8_t *)data, 1, 4, 0);
versaloon_set_callback(usbtoswd_read_callback);
} else {
/* write */
return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5,
NULL, 0, 0, 0);
versaloon_set_callback(usbtoswd_write_callback);
}
/* Input buffer must be passed even for write operations. Otherwise
* the callback function is not called and ack value is not set. */
return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5,
(uint8_t *)data, 1, 4, 0);
}

View File

@@ -183,7 +183,8 @@ RESULT usbtoswd_init(uint8_t interface_index);
RESULT usbtoswd_fini(uint8_t interface_index);
RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry,
uint16_t dly);
RESULT usbtoswd_seqout(uint8_t interface_index, uint8_t *data, uint16_t bitlen);
RESULT usbtoswd_seqout(uint8_t interface_index, const uint8_t *data,
uint16_t bitlen);
RESULT usbtoswd_seqin(uint8_t interface_index, uint8_t *data, uint16_t bitlen);
RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request,
uint32_t *data, uint8_t *ack);

View File

@@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
#include <libusb.h>
#include "versaloon_include.h"
#include "versaloon.h"
@@ -36,7 +37,7 @@ uint16_t versaloon_buf_size;
struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
uint16_t versaloon_pending_idx;
usb_dev_handle *versaloon_usb_device_handle;
libusb_device_handle *versaloon_usb_device_handle;
static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
RESULT versaloon_init(void);
@@ -196,6 +197,7 @@ RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
{
int ret;
int transferred;
#if PARAM_CHECK
if (NULL == versaloon_buf) {
@@ -208,25 +210,24 @@ RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
}
#endif
ret = usb_bulk_write(versaloon_usb_device_handle,
versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf,
out_len, versaloon_usb_to);
if (ret != out_len) {
LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data",
usb_strerror());
ret = libusb_bulk_transfer(versaloon_usb_device_handle,
versaloon_interface.usb_setting.ep_out,
versaloon_buf, out_len, &transferred, versaloon_usb_to);
if (0 != ret || transferred != out_len) {
LOG_ERROR(ERRMSG_FAILURE_OPERATION, "send usb data");
return ERRCODE_FAILURE_OPERATION;
}
if (inlen != NULL) {
ret = usb_bulk_read(versaloon_usb_device_handle,
versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf,
versaloon_interface.usb_setting.buf_size, versaloon_usb_to);
if (ret > 0) {
*inlen = (uint16_t)ret;
ret = libusb_bulk_transfer(versaloon_usb_device_handle,
versaloon_interface.usb_setting.ep_in,
versaloon_buf, versaloon_interface.usb_setting.buf_size,
&transferred, versaloon_usb_to);
if (0 == ret) {
*inlen = (uint16_t)transferred;
return ERROR_OK;
} else {
LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data",
usb_strerror());
LOG_ERROR(ERRMSG_FAILURE_OPERATION, "receive usb data");
return ERROR_FAIL;
}
} else

View File

@@ -20,6 +20,8 @@
#ifndef __VERSALOON_H_INCLUDED__
#define __VERSALOON_H_INCLUDED__
#include <libusb.h>
struct usart_status_t {
uint32_t tx_buff_avail;
uint32_t tx_buff_size;
@@ -59,7 +61,8 @@ struct interface_swd_t {
RESULT(*fini)(uint8_t interface_index);
RESULT(*config)(uint8_t interface_index, uint8_t trn, uint16_t retry,
uint16_t dly);
RESULT(*seqout)(uint8_t interface_index, uint8_t *data, uint16_t bitlen);
RESULT(*seqout)(uint8_t interface_index, const uint8_t *data,
uint16_t bitlen);
RESULT(*seqin)(uint8_t interface_index, uint8_t *data, uint16_t bitlen);
RESULT(*transact)(uint8_t interface_index, uint8_t request,
uint32_t *data, uint8_t *ack);
@@ -106,7 +109,7 @@ struct versaloon_interface_t {
};
extern struct versaloon_interface_t versaloon_interface;
extern usb_dev_handle *versaloon_usb_device_handle;
extern libusb_device_handle *versaloon_usb_device_handle;
#endif /* __VERSALOON_H_INCLUDED__ */

View File

@@ -21,7 +21,6 @@
/* according to different platform */
#include <jtag/interface.h>
#include <jtag/commands.h>
#include "usb_common.h"
#define PARAM_CHECK 1
@@ -49,7 +48,6 @@
#define ERRMSG_NOT_SUPPORT_BY "%s is not supported by %s."
#define ERRMSG_FAILURE_OPERATION "Fail to %s."
#define ERRMSG_FAILURE_OPERATION_ERRSTRING "Fail to %s, error string is %s."
#define ERRMSG_FAILURE_OPERATION_MESSAGE "Fail to %s, %s"
#define ERRCODE_FAILURE_OPERATION ERROR_FAIL

View File

@@ -28,7 +28,8 @@
#include <jtag/interface.h>
#include <jtag/commands.h>
#include "usb_common.h"
#include <jtag/swd.h>
#include <libusb.h>
#include "versaloon/versaloon_include.h"
#include "versaloon/versaloon.h"
@@ -70,12 +71,19 @@ static void vsllink_tap_ensure_pending(int scans);
static void vsllink_tap_append_scan(int length, uint8_t *buffer,
struct scan_command *command);
/* VSLLink SWD functions */
static int_least32_t vsllink_swd_frequency(struct adiv5_dap *dap,
int_least32_t hz);
static int vsllink_swd_switch_seq(struct adiv5_dap *dap,
enum swd_special_seq seq);
/* VSLLink lowlevel functions */
struct vsllink {
struct usb_dev_handle *usb_handle;
struct libusb_context *libusb_ctx;
struct libusb_device_handle *usb_device_handle;
};
static struct vsllink *vsllink_usb_open(void);
static int vsllink_usb_open(struct vsllink *vsllink);
static void vsllink_usb_close(struct vsllink *vsllink);
#if defined _DEBUG_JTAG_IO_
@@ -88,7 +96,9 @@ static uint8_t *tms_buffer;
static uint8_t *tdi_buffer;
static uint8_t *tdo_buffer;
struct vsllink *vsllink_handle;
static bool swd_mode;
static struct vsllink *vsllink_handle;
static int vsllink_execute_queue(void)
{
@@ -232,6 +242,11 @@ static int vsllink_execute_queue(void)
static int vsllink_speed(int speed)
{
if (swd_mode) {
vsllink_swd_frequency(NULL, speed * 1000);
return ERROR_OK;
}
versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed);
return versaloon_interface.adaptors.peripheral_commit();
}
@@ -271,20 +286,34 @@ static int vsllink_quit(void)
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
0, 0, GPIO_SRST | GPIO_TRST);
versaloon_interface.adaptors.gpio.fini(0);
versaloon_interface.adaptors.jtag_raw.fini(0);
if (swd_mode)
versaloon_interface.adaptors.swd.fini(0);
else
versaloon_interface.adaptors.jtag_raw.fini(0);
versaloon_interface.adaptors.peripheral_commit();
versaloon_interface.fini();
vsllink_free_buffer();
vsllink_usb_close(vsllink_handle);
free(vsllink_handle);
return ERROR_OK;
}
static int vsllink_init(void)
static int vsllink_interface_init(void)
{
vsllink_handle = vsllink_usb_open();
if (vsllink_handle == 0) {
vsllink_handle = malloc(sizeof(struct vsllink));
if (NULL == vsllink_handle) {
LOG_ERROR("unable to allocate memory");
return ERROR_FAIL;
}
libusb_init(&vsllink_handle->libusb_ctx);
if (ERROR_OK != vsllink_usb_open(vsllink_handle)) {
LOG_ERROR("Can't find USB JTAG Interface!" \
"Please check connection and permissions.");
return ERROR_JTAG_INIT_FAILED;
@@ -292,7 +321,7 @@ static int vsllink_init(void)
LOG_DEBUG("vsllink found on %04X:%04X",
versaloon_interface.usb_setting.vid,
versaloon_interface.usb_setting.pid);
versaloon_usb_device_handle = vsllink_handle->usb_handle;
versaloon_usb_device_handle = vsllink_handle->usb_device_handle;
if (ERROR_OK != versaloon_interface.init())
return ERROR_FAIL;
@@ -301,22 +330,46 @@ static int vsllink_init(void)
return ERROR_FAIL;
}
/* malloc buffer size for tap */
tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32;
vsllink_free_buffer();
tdi_buffer = malloc(tap_buffer_size);
tdo_buffer = malloc(tap_buffer_size);
tms_buffer = malloc(tap_buffer_size);
if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) {
vsllink_quit();
return ERROR_FAIL;
return ERROR_OK;
}
static int vsllink_init(void)
{
int retval = vsllink_interface_init();
if (ERROR_OK != retval)
return retval;
versaloon_interface.adaptors.gpio.init(0);
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST,
GPIO_SRST);
versaloon_interface.adaptors.delay.delayms(100);
versaloon_interface.adaptors.peripheral_commit();
if (swd_mode) {
versaloon_interface.adaptors.gpio.config(0, GPIO_TRST, 0,
GPIO_TRST, GPIO_TRST);
versaloon_interface.adaptors.swd.init(0);
vsllink_swd_frequency(NULL, jtag_get_speed_khz() * 1000);
vsllink_swd_switch_seq(NULL, JTAG_TO_SWD);
} else {
/* malloc buffer size for tap */
tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32;
vsllink_free_buffer();
tdi_buffer = malloc(tap_buffer_size);
tdo_buffer = malloc(tap_buffer_size);
tms_buffer = malloc(tap_buffer_size);
if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) {
vsllink_quit();
return ERROR_FAIL;
}
versaloon_interface.adaptors.jtag_raw.init(0);
versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz());
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
GPIO_TRST, GPIO_SRST, GPIO_SRST);
}
versaloon_interface.adaptors.jtag_raw.init(0);
versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz());
versaloon_interface.adaptors.gpio.init(0);
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST,
GPIO_TRST, GPIO_SRST, GPIO_SRST);
if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit())
return ERROR_FAIL;
@@ -442,10 +495,13 @@ static void vsllink_reset(int trst, int srst)
else
versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, GPIO_SRST, 0, 0);
if (!trst)
versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST);
else
versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0);
if (!swd_mode) {
if (!trst)
versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST);
else
versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0);
}
versaloon_interface.adaptors.peripheral_commit();
}
@@ -660,138 +716,189 @@ static int vsllink_jtag_execute(void)
static int vsllink_tap_execute(void)
{
if (swd_mode)
return ERROR_OK;
return vsllink_jtag_execute();
}
static int vsllink_swd_init(void)
{
LOG_INFO("VSLLink SWD mode enabled");
swd_mode = true;
return ERROR_OK;
}
static int_least32_t vsllink_swd_frequency(struct adiv5_dap *dap,
int_least32_t hz)
{
const int_least32_t delay2hz[] = {
1850000, 235000, 130000, 102000, 85000, 72000
};
if (hz > 0) {
uint16_t delay = UINT16_MAX;
for (uint16_t i = 0; i < ARRAY_SIZE(delay2hz); i++) {
if (hz >= delay2hz[i]) {
hz = delay2hz[i];
delay = i;
break;
}
}
if (delay == UINT16_MAX)
delay = (500000 / hz) - 1;
/* Calculate retry count after a WAIT response. This will give
* a retry timeout at about ~250 ms. 54 is the number of bits
* found in a transaction. */
uint16_t retry_count = 250 * hz / 1000 / 54;
LOG_DEBUG("SWD delay: %d, retry count: %d", delay, retry_count);
versaloon_interface.adaptors.swd.config(0, 2, retry_count, delay);
}
return hz;
}
static int vsllink_swd_switch_seq(struct adiv5_dap *dap,
enum swd_special_seq seq)
{
switch (seq) {
case LINE_RESET:
LOG_DEBUG("SWD line reset");
versaloon_interface.adaptors.swd.seqout(0, swd_seq_line_reset,
swd_seq_line_reset_len);
break;
case JTAG_TO_SWD:
LOG_DEBUG("JTAG-to-SWD");
versaloon_interface.adaptors.swd.seqout(0, swd_seq_jtag_to_swd,
swd_seq_jtag_to_swd_len);
break;
case SWD_TO_JTAG:
LOG_DEBUG("SWD-to-JTAG");
versaloon_interface.adaptors.swd.seqout(0, swd_seq_swd_to_jtag,
swd_seq_swd_to_jtag_len);
break;
default:
LOG_ERROR("Sequence %d not supported", seq);
return ERROR_FAIL;
}
return ERROR_OK;
}
static void vsllink_swd_read_reg(struct adiv5_dap *dap, uint8_t cmd,
uint32_t *value)
{
versaloon_interface.adaptors.swd.transact(0, cmd, value, NULL);
}
static void vsllink_swd_write_reg(struct adiv5_dap *dap, uint8_t cmd,
uint32_t value)
{
versaloon_interface.adaptors.swd.transact(0, cmd, &value, NULL);
}
static int vsllink_swd_run_queue(struct adiv5_dap *dap)
{
return versaloon_interface.adaptors.peripheral_commit();
}
/****************************************************************************
* VSLLink USB low-level functions */
static uint8_t usb_check_string(usb_dev_handle *usb, uint8_t stringidx,
char *string, char *buff, uint16_t buf_size)
static int vsllink_check_usb_strings(
struct libusb_device_handle *usb_device_handle,
struct libusb_device_descriptor *usb_desc)
{
int len;
uint8_t alloced = 0;
uint8_t ret = 1;
char desc_string[256];
int retval;
if (NULL == buff) {
buf_size = 256;
buff = malloc(buf_size);
if (NULL == buff) {
ret = 0;
goto free_and_return;
}
alloced = 1;
if (NULL != versaloon_interface.usb_setting.serialstring) {
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,
sizeof(desc_string)))
return ERROR_FAIL;
}
strcpy(buff, "");
len = usb_get_string_simple(usb, stringidx, buff, buf_size);
if ((len < 0) || ((size_t)len != strlen(buff))) {
ret = 0;
goto free_and_return;
}
retval = libusb_get_string_descriptor_ascii(usb_device_handle,
usb_desc->iProduct, (unsigned char *)desc_string,
sizeof(desc_string));
if (retval < 0)
return ERROR_FAIL;
buff[len] = '\0';
if ((string != NULL) && strcmp(buff, string)) {
ret = 0;
goto free_and_return;
}
if (strstr(desc_string, "Versaloon") == NULL)
return ERROR_FAIL;
free_and_return:
if (alloced && (buff != NULL)) {
free(buff);
buff = NULL;
}
return ret;
return ERROR_OK;
}
static usb_dev_handle *find_usb_device(uint16_t VID, uint16_t PID, uint8_t interface,
char *serialstring, char *productstring)
static int vsllink_usb_open(struct vsllink *vsllink)
{
usb_dev_handle *dev_handle = NULL;
struct usb_bus *busses;
struct usb_bus *bus;
struct usb_device *dev;
ssize_t num_devices, i;
libusb_device **usb_devices;
struct libusb_device_descriptor usb_desc;
struct libusb_device_handle *usb_device_handle;
int retval;
usb_init();
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
num_devices = libusb_get_device_list(vsllink->libusb_ctx, &usb_devices);
for (bus = busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idVendor == VID)
&& (dev->descriptor.idProduct == PID)) {
dev_handle = usb_open(dev);
if (NULL == dev_handle) {
LOG_ERROR("failed to open %04X:%04X, %s", VID, PID,
usb_strerror());
continue;
}
if (num_devices <= 0)
return ERROR_FAIL;
/* check description string */
if ((productstring != NULL && !usb_check_string(dev_handle,
dev->descriptor.iProduct, productstring, NULL, 0))
|| (serialstring != NULL && !usb_check_string(dev_handle,
dev->descriptor.iSerialNumber, serialstring, NULL, 0))) {
usb_close(dev_handle);
dev_handle = NULL;
continue;
}
for (i = 0; i < num_devices; i++) {
libusb_device *device = usb_devices[i];
if (usb_claim_interface(dev_handle, interface) != 0) {
LOG_ERROR(ERRMSG_FAILURE_OPERATION_MESSAGE,
"claim interface", usb_strerror());
usb_close(dev_handle);
dev_handle = NULL;
continue;
}
retval = libusb_get_device_descriptor(device, &usb_desc);
if (retval != 0)
continue;
if (dev_handle != NULL)
return dev_handle;
}
}
if (usb_desc.idVendor != versaloon_interface.usb_setting.vid ||
usb_desc.idProduct != versaloon_interface.usb_setting.pid)
continue;
retval = libusb_open(device, &usb_device_handle);
if (retval != 0)
continue;
retval = vsllink_check_usb_strings(usb_device_handle, &usb_desc);
if (ERROR_OK == retval)
break;
libusb_close(usb_device_handle);
}
return dev_handle;
}
libusb_free_device_list(usb_devices, 1);
static struct vsllink *vsllink_usb_open(void)
{
usb_init();
if (i == num_devices)
return ERROR_FAIL;
struct usb_dev_handle *dev;
retval = libusb_claim_interface(usb_device_handle,
versaloon_interface.usb_setting.interface);
if (retval != 0) {
LOG_ERROR("unable to claim interface");
libusb_close(usb_device_handle);
return ERROR_FAIL;
}
dev = find_usb_device(versaloon_interface.usb_setting.vid,
versaloon_interface.usb_setting.pid,
versaloon_interface.usb_setting.interface,
versaloon_interface.usb_setting.serialstring, "Versaloon");
if (NULL == dev)
return NULL;
struct vsllink *result = malloc(sizeof(struct vsllink));
result->usb_handle = dev;
return result;
vsllink->usb_device_handle = usb_device_handle;
return ERROR_OK;
}
static void vsllink_usb_close(struct vsllink *vsllink)
{
int ret;
ret = usb_release_interface(vsllink->usb_handle,
versaloon_interface.usb_setting.interface);
if (ret != 0) {
LOG_ERROR("fail to release interface %d, %d returned",
versaloon_interface.usb_setting.interface, ret);
exit(-1);
}
ret = usb_close(vsllink->usb_handle);
if (ret != 0) {
LOG_ERROR("fail to close usb, %d returned", ret);
exit(-1);
}
free(vsllink);
libusb_release_interface(vsllink->usb_device_handle,
versaloon_interface.usb_setting.interface);
libusb_close(vsllink->usb_device_handle);
}
#define BYTES_PER_LINE 16
@@ -849,13 +956,23 @@ static const struct command_registration vsllink_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
static const char *vsllink_transports[] = {"jtag", "swd", NULL};
static const char * const vsllink_transports[] = {"jtag", "swd", NULL};
static const struct swd_driver vsllink_swd_driver = {
.init = vsllink_swd_init,
.frequency = vsllink_swd_frequency,
.switch_seq = vsllink_swd_switch_seq,
.read_reg = vsllink_swd_read_reg,
.write_reg = vsllink_swd_write_reg,
.run = vsllink_swd_run_queue,
};
struct jtag_interface vsllink_interface = {
.name = "vsllink",
.supported = DEBUG_CAP_TMS_SEQ,
.commands = vsllink_command_handlers,
.transports = vsllink_transports,
.swd = &vsllink_swd_driver,
.init = vsllink_init,
.quit = vsllink_quit,

View File

@@ -37,7 +37,7 @@
#include <target/target.h>
static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, NULL, 0}, 0, 0 };
static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 };
int hl_interface_open(enum hl_transports tr)
{
@@ -92,8 +92,11 @@ int hl_interface_init_target(struct target *t)
}
if (found == 0) {
LOG_ERROR("hl_interface_init_target: target not found: idcode: 0x%08" PRIx32,
t->tap->idcode);
LOG_WARNING("UNEXPECTED idcode: 0x%08" PRIx32, t->tap->idcode);
for (ii = 0; ii < limit; ii++)
LOG_ERROR("expected %u of %u: 0x%08" PRIx32, ii + 1, limit,
t->tap->expected_ids[ii]);
return ERROR_FAIL;
}
@@ -115,11 +118,8 @@ static int hl_interface_quit(void)
{
LOG_DEBUG("hl_interface_quit");
if (hl_if.param.trace_f) {
fclose(hl_if.param.trace_f);
hl_if.param.trace_f = NULL;
}
hl_if.param.trace_source_hz = 0;
if (hl_if.layout->api->close)
hl_if.layout->api->close(hl_if.handle);
return ERROR_OK;
}
@@ -145,6 +145,71 @@ int hl_interface_init_reset(void)
return ERROR_OK;
}
static int hl_interface_khz(int khz, int *jtag_speed)
{
if (hl_if.layout->api->speed == NULL)
return ERROR_OK;
*jtag_speed = hl_if.layout->api->speed(hl_if.handle, khz, true);
return ERROR_OK;
}
static int hl_interface_speed_div(int speed, int *khz)
{
*khz = speed;
return ERROR_OK;
}
static int hl_interface_speed(int speed)
{
if (hl_if.layout->api->speed == NULL)
return ERROR_OK;
if (hl_if.handle == NULL) {
/* pass speed as initial param as interface not open yet */
hl_if.param.initial_interface_speed = speed;
return ERROR_OK;
}
hl_if.layout->api->speed(hl_if.handle, speed, false);
return ERROR_OK;
}
int hl_interface_override_target(const char **targetname)
{
if (hl_if.layout->api->override_target) {
if (hl_if.layout->api->override_target(*targetname)) {
*targetname = "hla_target";
return ERROR_OK;
} else
return ERROR_FAIL;
}
return ERROR_FAIL;
}
int hl_interface_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq)
{
if (hl_if.layout->api->config_trace)
return hl_if.layout->api->config_trace(hl_if.handle, enabled, pin_protocol,
port_size, trace_freq);
else if (enabled) {
LOG_ERROR("The selected interface does not support tracing");
return ERROR_FAIL;
}
return ERROR_OK;
}
int hl_interface_poll_trace(uint8_t *buf, size_t *size)
{
if (hl_if.layout->api->poll_trace)
return hl_if.layout->api->poll_trace(hl_if.handle, buf, size);
return ERROR_FAIL;
}
COMMAND_HANDLER(hl_interface_handle_device_desc_command)
{
LOG_DEBUG("hl_interface_handle_device_desc_command");
@@ -214,27 +279,17 @@ COMMAND_HANDLER(hl_interface_handle_vid_pid_command)
return ERROR_OK;
}
COMMAND_HANDLER(interface_handle_trace_command)
COMMAND_HANDLER(interface_handle_hla_command)
{
FILE *f = NULL;
unsigned source_hz;
if ((CMD_ARGC < 1) || (CMD_ARGC > 2))
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], source_hz);
if (source_hz == 0) {
return ERROR_COMMAND_SYNTAX_ERROR;
if (!hl_if.layout->api->custom_command) {
LOG_ERROR("The selected adapter doesn't support custom commands");
return ERROR_FAIL;
}
if (CMD_ARGC == 2) {
f = fopen(CMD_ARGV[1], "a");
if (!f)
return ERROR_COMMAND_SYNTAX_ERROR;
}
hl_if.param.trace_f = f;
hl_if.param.trace_source_hz = source_hz;
hl_if.layout->api->custom_command(hl_if.handle, CMD_ARGV[0]);
return ERROR_OK;
}
@@ -269,11 +324,11 @@ static const struct command_registration hl_interface_command_handlers[] = {
.usage = "(vid pid)* ",
},
{
.name = "trace",
.handler = &interface_handle_trace_command,
.mode = COMMAND_CONFIG,
.help = "configure trace reception",
.usage = "source_lock_hz [destination_path]",
.name = "hla_command",
.handler = &interface_handle_hla_command,
.mode = COMMAND_EXEC,
.help = "execute a custom adapter-specific command",
.usage = "hla_command <command>",
},
COMMAND_REGISTRATION_DONE
};
@@ -286,4 +341,9 @@ struct jtag_interface hl_interface = {
.init = hl_interface_init,
.quit = hl_interface_quit,
.execute_queue = hl_interface_execute_queue,
.speed = &hl_interface_speed,
.khz = &hl_interface_khz,
.speed_div = &hl_interface_speed_div,
.config_trace = &hl_interface_config_trace,
.poll_trace = &hl_interface_poll_trace,
};

View File

@@ -33,9 +33,9 @@ extern const char *hl_transports[];
struct hl_interface_param_s {
/** */
char *device_desc;
const char *device_desc;
/** */
char *serial;
const char *serial;
/** */
uint16_t vid;
/** */
@@ -46,10 +46,8 @@ struct hl_interface_param_s {
enum hl_transports transport;
/** */
bool connect_under_reset;
/** Output file for trace data (if any) */
FILE *trace_f;
/** Trace module source clock rate */
uint32_t trace_source_hz;
/** Initial interface clock clock speed */
int initial_interface_speed;
};
struct hl_interface_s {
@@ -67,5 +65,6 @@ int hl_interface_open(enum hl_transports tr);
int hl_interface_init_target(struct target *t);
int hl_interface_init_reset(void);
int hl_interface_override_target(const char **targetname);
#endif /* _HL_INTERFACE */

View File

@@ -24,6 +24,8 @@
#ifndef _HL_LAYOUT_H
#define _HL_LAYOUT_H
#include <target/armv7m_trace.h>
/** */
struct hl_interface_s;
struct hl_interface_param_s;
@@ -74,7 +76,38 @@ struct hl_layout_api_s {
*/
int (*idcode) (void *handle, uint32_t *idcode);
/** */
enum target_state (*state) (void *handle);
int (*override_target) (const char *targetname);
/** */
int (*custom_command) (void *handle, const char *command);
/** */
int (*speed)(void *handle, int khz, bool query);
/**
* Configure trace parameters for the adapter
*
* @param handle A handle to adapter
* @param enabled Whether to enable trace
* @param pin_protocol Configured pin protocol
* @param port_size Trace port width for sync mode
* @param trace_freq A pointer to the configured trace
* frequency; if it points to 0, the adapter driver must write
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(void *handle, bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
* Poll for new trace data
*
* @param handle A handle to adapter
* @param buf A pointer to buffer to store received data
* @param size A pointer to buffer size; must be filled with
* the actual amount of bytes written
*
* @returns ERROR_OK on success, an error code on failure.
*/
int (*poll_trace)(void *handle, uint8_t *buf, size_t *size);
/** */
enum target_state (*state) (void *fd);
};
/** */

View File

@@ -59,7 +59,13 @@ static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi,
return JIM_OK;
}
#define NTAP_OPT_EXPECTED_ID 0
#define NTAP_OPT_IRLEN 0
#define NTAP_OPT_IRMASK 1
#define NTAP_OPT_IRCAPTURE 2
#define NTAP_OPT_ENABLED 3
#define NTAP_OPT_DISABLED 4
#define NTAP_OPT_EXPECTED_ID 5
#define NTAP_OPT_VERSION 6
static int jim_hl_newtap_cmd(Jim_GetOptInfo *goi)
{
@@ -69,8 +75,14 @@ static int jim_hl_newtap_cmd(Jim_GetOptInfo *goi)
Jim_Nvp *n;
char *cp;
const Jim_Nvp opts[] = {
{.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID},
{.name = NULL, .value = -1},
{ .name = "-irlen", .value = NTAP_OPT_IRLEN },
{ .name = "-irmask", .value = NTAP_OPT_IRMASK },
{ .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE },
{ .name = "-enable", .value = NTAP_OPT_ENABLED },
{ .name = "-disable", .value = NTAP_OPT_DISABLED },
{ .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID },
{ .name = "-ignore-version", .value = NTAP_OPT_VERSION },
{ .name = NULL, .value = -1},
};
pTap = calloc(1, sizeof(struct jtag_tap));
@@ -121,6 +133,12 @@ static int jim_hl_newtap_cmd(Jim_GetOptInfo *goi)
return e;
}
break;
case NTAP_OPT_IRLEN:
case NTAP_OPT_IRMASK:
case NTAP_OPT_IRCAPTURE:
/* dummy read to ignore the next argument */
Jim_GetOpt_Wide(goi, NULL);
break;
} /* switch (n->value) */
} /* while (goi->argc) */

View File

@@ -134,6 +134,12 @@ static const struct command_registration stlink_transport_command_handlers[] = {
.usage = "",
.chain = hl_transport_jtag_subcommand_handlers,
},
{
.name = "jtag_ntrst_delay",
.mode = COMMAND_ANY,
.handler = hl_transport_jtag_command,
.usage = "",
},
COMMAND_REGISTRATION_DONE
};
@@ -204,12 +210,14 @@ static struct transport hl_swd_transport = {
.name = "hla_swd",
.select = hl_transport_select,
.init = hl_transport_init,
.override_target = hl_interface_override_target,
};
static struct transport hl_jtag_transport = {
.name = "hla_jtag",
.select = hl_transport_select,
.init = hl_transport_init,
.override_target = hl_interface_override_target,
};
static struct transport stlink_swim_transport = {

View File

@@ -28,6 +28,7 @@
#define OPENOCD_JTAG_INTERFACE_H
#include <jtag/jtag.h>
#include <target/armv7m_trace.h>
/* @file
* The "Cable Helper API" is what the cable drivers can use to help
@@ -198,7 +199,7 @@ static inline tap_state_t jtag_debug_state_machine(const void *tms_buf,
*/
struct jtag_interface {
/** The name of the JTAG interface driver. */
char *name;
const char * const name;
/**
* Bit vector listing capabilities exposed by this driver.
@@ -207,7 +208,7 @@ struct jtag_interface {
#define DEBUG_CAP_TMS_SEQ (1 << 0)
/** transports supported in C code (NULL terminated vector) */
const char **transports;
const char * const *transports;
const struct swd_driver *swd;
@@ -298,11 +299,39 @@ struct jtag_interface {
* @returns ERROR_OK on success, or an error code on failure.
*/
int (*srst_asserted)(int *srst_asserted);
/**
* Configure trace parameters for the adapter
*
* @param enabled Whether to enable trace
* @param pin_protocol Configured pin protocol
* @param port_size Trace port width for sync mode
* @param trace_freq A pointer to the configured trace
* frequency; if it points to 0, the adapter driver must write
* its maximum supported rate there
* @returns ERROR_OK on success, an error code on failure.
*/
int (*config_trace)(bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
/**
* Poll for new trace data
*
* @param buf A pointer to buffer to store received data
* @param size A pointer to buffer size; must be filled with
* the actual amount of bytes written
*
* @returns ERROR_OK on success, an error code on failure.
*/
int (*poll_trace)(uint8_t *buf, size_t *size);
};
extern const char *jtag_only[];
extern const char * const jtag_only[];
void adapter_assert_reset(void);
void adapter_deassert_reset(void);
int adapter_config_trace(bool enabled, enum tpio_pin_protocol pin_protocol,
uint32_t port_size, unsigned int *trace_freq);
int adapter_poll_trace(uint8_t *buf, size_t *size);
#endif /* OPENOCD_JTAG_INTERFACE_H */

View File

@@ -21,7 +21,9 @@ proc jtag_init {} {
# startup (at OpenOCD server startup, when JTAG may not yet work); and
# potentially more (for reset types like cold, warm, etc)
proc init_reset { mode } {
jtag arp_init-reset
if {[using_jtag]} {
jtag arp_init-reset
}
}
#########
@@ -79,12 +81,38 @@ proc srst_asserted {} {
# measure actual JTAG clock
proc measure_clk {} {
set start_time [ms];
runtest 10000000;
echo "Running at more than [expr 10000.0 / ([ms]-$start_time)] kHz";
set iterations 10000000;
runtest $iterations;
echo "Running at more than [expr $iterations.0 / ([ms]-$start_time)] kHz";
}
add_help_text measure_clk "Runs a test to measure the JTAG clk. Useful with RCLK / RTCK."
proc default_to_jtag { f args } {
set current_transport [transport select]
if {[using_jtag]} {
eval $f $args
} {
error "session transport is \"$current_transport\" but your config requires JTAG"
}
}
proc jtag args {
eval default_to_jtag jtag $args
}
proc jtag_rclk args {
eval default_to_jtag jtag_rclk $args
}
proc jtag_ntrst_delay args {
eval default_to_jtag jtag_ntrst_delay $args
}
proc jtag_ntrst_assert_width args {
eval default_to_jtag jtag_ntrst_assert_width $args
}
# BEGIN MIGRATION AIDS ... these adapter operations originally had
# JTAG-specific names despite the fact that the operations were not
# specific to JTAG, or otherewise had troublesome/misleading names.

View File

@@ -20,6 +20,8 @@
#ifndef SWD_H
#define SWD_H
#include <target/arm_adi_v5.h>
/* Bits in SWD command packets, written from host to target
* first bit on the wire is START
*/
@@ -29,20 +31,9 @@
#define SWD_CMD_A32 (3 << 3) /* bits A[3:2] of register addr */
#define SWD_CMD_PARITY (1 << 5) /* parity of APnDP|RnW|A32 */
#define SWD_CMD_STOP (0 << 6) /* always clear for synch SWD */
#define SWD_CMD_PARK (0 << 7) /* not driven by host (pull high) */
#define SWD_CMD_PARK (1 << 7) /* driven high by host */
/* followed by TRN, 3-bits of ACK, TRN */
/* pbit16 holds precomputed parity bits for each nibble */
#define pbit(parity, nibble) (parity << nibble)
static const uint16_t pbit16 =
pbit(0, 0) | pbit(1, 1) | pbit(1, 2) | pbit(0, 3)
| pbit(1, 4) | pbit(0, 5) | pbit(0, 6) | pbit(1, 7)
| pbit(1, 8) | pbit(0, 9) | pbit(0, 0xa) | pbit(1, 0xb)
| pbit(0, 0xc) | pbit(1, 0xd) | pbit(1, 0xe) | pbit(0, 0xf);
#define nibble_parity(nibble) (pbit16 & pbit(1, nibble))
/**
* Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg()
* and swd_driver.write_reg() methods will use directly.
@@ -54,7 +45,7 @@ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum)
| ((regnum & 0xc) << 1);
/* 8 cmd bits 4:1 may be set */
if (nibble_parity(cmd >> 1))
if (parity_u32(cmd))
cmd |= SWD_CMD_PARITY;
/* driver handles START, STOP, and TRN */
@@ -64,63 +55,146 @@ 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> */
/*
* FOR NOW ... SWD driver ops are synchronous and return ACK
* status ... no quueueing.
/**
* Line reset.
*
* Individual ops are request/response, and fast-fail permits much
* better fault handling. Upper layers may queue if desired.
* Line reset is at least 50 SWCLK cycles with SWDIO driven high, followed
* by at least one idle (low) cycle.
*/
static const uint8_t swd_seq_line_reset[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03
};
static const unsigned swd_seq_line_reset_len = 51;
/**
* JTAG-to-SWD sequence.
*
* The JTAG-to-SWD sequence is at least 50 TCK/SWCLK cycles with TMS/SWDIO
* high, putting either interface logic into reset state, followed by a
* specific 16-bit sequence and finally a line reset in case the SWJ-DP was
* already in SWD mode.
*/
static const uint8_t swd_seq_jtag_to_swd[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x9e,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f,
};
static const unsigned swd_seq_jtag_to_swd_len = 118;
/**
* SWD-to-JTAG sequence.
*
* The SWD-to-JTAG sequence is at least 50 TCK/SWCLK cycles with TMS/SWDIO
* high, putting either interface logic into reset state, followed by a
* specific 16-bit sequence and finally at least 5 TCK cycles to put the
* JTAG TAP in TLR.
*/
static const uint8_t swd_seq_swd_to_jtag[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x9c, 0xff
};
static const unsigned swd_seq_swd_to_jtag_len = 71;
/**
* SWD-to-dormant sequence.
*
* This is at least 50 SWCLK cycles with SWDIO high to put the interface
* in reset state, followed by a specific 16-bit sequence.
*/
static const uint8_t swd_seq_swd_to_dormant[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x8e, 0x03
};
static const unsigned swd_seq_swd_to_dormant_len = 66;
/**
* Dormant-to-SWD sequence.
*
* This is at least 8 TCK/SWCLK cycles with TMS/SWDIO high to abort any ongoing
* selection alert sequence, followed by a specific 128-bit selection alert
* sequence, followed by 4 TCK/SWCLK cycles with TMS/SWDIO low, followed by
* a specific protocol-dependent activation code. For SWD the activation code
* is an 8-bit sequence. The sequence ends with a line reset.
*/
static const uint8_t swd_seq_dormant_to_swd[] = {
0xff,
0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86,
0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19,
0x10, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f
};
static const unsigned swd_seq_dormant_to_swd_len = 199;
enum swd_special_seq {
LINE_RESET,
JTAG_TO_SWD,
SWD_TO_JTAG,
SWD_TO_DORMANT,
DORMANT_TO_SWD,
};
struct swd_driver {
/**
* Initialize the debug link so it can perform
* synchronous SWD operations.
* @param trn value from WCR: how many clocks
* to not drive the SWDIO line at certain points in
* the SWD protocol (at least 1 clock).
* Initialize the debug link so it can perform SWD operations.
*
* As an example, this would switch a dual-mode debug adapter
* into SWD mode and out of JTAG mode.
*
* @return ERROR_OK on success, else a negative fault code.
*
* @return ERROR_OK on success, else a negative fault code.
*/
int (*init)(uint8_t trn);
int (*init)(void);
/**
* Set the SWCLK frequency of the SWD link.
*
* The driver should round the desired value, downwards if possible, to
* the nearest supported frequency. A negative value should be ignored
* and can be used to query the current setting. If the driver does not
* support a variable frequency a fixed, nominal, value should be
* returned.
*
* If the frequency is increased, it must not apply before the currently
* queued transactions are executed. If the frequency is lowered, it may
* apply immediately.
*
* @param dap The DAP controlled by the SWD link.
* @param hz The desired frequency in Hz.
* @return The actual resulting frequency after rounding.
*/
int_least32_t (*frequency)(struct adiv5_dap *dap, int_least32_t hz);
/**
* Synchronous read of an AP or DP register.
*
* @param cmd with APnDP/RnW/addr/parity bits
* @param where to store value to read from register
*
* @return SWD_ACK_* code for the transaction
* or (negative) fault code
*/
int (*read_reg)(uint8_t cmd, uint32_t *value);
/**
* Queue a special SWDIO sequence.
*
* @param dap The DAP controlled by the SWD link.
* @param seq The special sequence to generate.
* @return ERROR_OK if the sequence was queued, negative error if the
* sequence is unsupported.
*/
int (*switch_seq)(struct adiv5_dap *dap, enum swd_special_seq seq);
/**
* Synchronous write of an AP or DP register.
*
* @param cmd with APnDP/RnW/addr/parity bits
* @param value to be written to the register
*
* @return SWD_ACK_* code for the transaction
* or (negative) fault code
*/
int (*write_reg)(uint8_t cmd, uint32_t value);
/**
* Queued read of an AP or DP register.
*
* @param dap The DAP controlled by the SWD link.
* @param Command byte with APnDP/RnW/addr/parity bits
* @param Where to store value to read from register
*/
void (*read_reg)(struct adiv5_dap *dap, uint8_t cmd, uint32_t *value);
/**
* Synchronous block read of an AP or DP register.
*
* @param cmd with APnDP/RnW/addr/parity bits
* @param number of reads from register to be executed
* @param buffer to store data read from register
*
* @return SWD_ACK_* code for the transaction
* or (negative) fault code
*/
int (*read_block)(uint8_t cmd, uint32_t blocksize, uint8_t *buffer);
/**
* Queued write of an AP or DP register.
*
* @param dap The DAP controlled by the SWD link.
* @param Command byte with APnDP/RnW/addr/parity bits
* @param Value to be written to the register
*/
void (*write_reg)(struct adiv5_dap *dap, uint8_t cmd, uint32_t value);
/**
* Execute any queued transactions and collect the result.
*
* @param dap The DAP controlled by the SWD link.
* @return ERROR_OK on success, Ack response code on WAIT/FAULT
* or negative error code on other kinds of failure.
*/
int (*run)(struct adiv5_dap *dap);
/**
* Configures data collection from the Single-wire
@@ -131,16 +205,15 @@ struct swd_driver {
* is normally connected to a microcontroller's UART TX,
* but which may instead be connected to SWO for use in
* collecting ITM (and possibly ETM) trace data.
*
* @return ERROR_OK on success, else a negative fault code.
*
* @return ERROR_OK on success, else a negative fault code.
*/
int *(*trace)(bool swo);
int *(*trace)(struct adiv5_dap *dap, bool swo);
};
int swd_init_reset(struct command_context *cmd_ctx);
void swd_add_reset(int req_srst);
bool transport_is_swd(void);
bool transport_is_cmsis_dap(void);
#endif /* SWD_H */

Some files were not shown because too many files have changed in this diff Show More