Merge pull request #351 from riscv/from_upstream

From upstream
log_output
Tim Newsome 2019-02-14 12:53:58 -08:00 committed by GitHub
commit 8dd5d2a710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
147 changed files with 6454 additions and 1240 deletions

View File

@ -148,18 +148,22 @@ to instruct git locally how to send off the changes.
-# Add a new remote to git using Gerrit username: -# Add a new remote to git using Gerrit username:
@code @code
git remote add review ssh://USERNAME@openocd.zylin.com:29418/openocd.git git remote add review ssh://USERNAME@openocd.zylin.com:29418/openocd.git
git config remote.review.push HEAD:refs/publish/master git config remote.review.push HEAD:refs/for/master
@endcode @endcode
Or with http only: Or with http only:
@code @code
git remote add review http://USERNAME@openocd.zylin.com/p/openocd.git git remote add review http://USERNAME@openocd.zylin.com/p/openocd.git
git config remote.review.push HEAD:refs/publish/master git config remote.review.push HEAD:refs/for/master
@endcode @endcode
The http password is configured from your gerrit settings - http://openocd.zylin.com/#/settings/http-password. The http password is configured from your gerrit settings - http://openocd.zylin.com/#/settings/http-password.
\note If you want to simplify http access you can also add your http password to the url as follows: \note If you want to simplify http access you can also add your http password to the url as follows:
@code @code
git remote add review http://USERNAME:PASSWORD@openocd.zylin.com/p/openocd.git git remote add review http://USERNAME:PASSWORD@openocd.zylin.com/p/openocd.git
@endcode @endcode
\note All contributions should be pushed to @c refs/for/master on the
Gerrit server, even if you plan to use several local branches for different
topics. It is possible because @c for/master is not a traditional Git
branch.
-# You will need to install this hook, we will look into a better solution: -# You will need to install this hook, we will look into a better solution:
@code @code
scp -p -P 29418 USERNAME@openocd.zylin.com:hooks/commit-msg .git/hooks/ scp -p -P 29418 USERNAME@openocd.zylin.com:hooks/commit-msg .git/hooks/

12
README
View File

@ -123,12 +123,12 @@ EJTAG, NDS32, XScale, Intel Quark.
Flash drivers Flash drivers
------------- -------------
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC, FM3,
FM3, FM4, Freedom E SPI, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, FM4, Freedom E SPI, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900,
LPC2900, LPCSPIFI, Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, LPCSPIFI, Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP,
PSoC4, PSoC5LP, SiM3x, Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; SiM3x, Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of
NAND controllers of AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx,
Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx. S3C6400, XMC1xxx, XMC4xxx.
================== ==================

View File

@ -55,14 +55,21 @@ ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="660", GROUP="plugdev",
# TI ICDI # TI ICDI
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="660", GROUP="plugdev", TAG+="uaccess"
# STLink v1 # STMicroelectronics ST-LINK V1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", MODE="660", GROUP="plugdev", TAG+="uaccess"
# STLink v2 # STMicroelectronics ST-LINK/V2
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE="660", GROUP="plugdev", TAG+="uaccess"
# STLink v2-1 # STMicroelectronics ST-LINK/V2.1
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", MODE="660", GROUP="plugdev", TAG+="uaccess"
# STMicroelectronics STLINK-V3
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", MODE="660", GROUP="plugdev", TAG+="uaccess"
# Cypress KitProg in KitProg mode # Cypress KitProg in KitProg mode
ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="f139", MODE="660", GROUP="plugdev", TAG+="uaccess"

View File

@ -6,7 +6,7 @@ CC=$(CROSS_COMPILE)gcc
OBJCOPY=$(CROSS_COMPILE)objcopy OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump OBJDUMP=$(CROSS_COMPILE)objdump
CFLAGS = -march=rv32i -mabi=ilp32 -x assembler-with-cpp - -nostdlib -nostartfiles CFLAGS = -march=rv32i -mabi=ilp32 -x assembler-with-cpp -nostdlib -nostartfiles
all: fespi.inc all: fespi.inc

View File

@ -156,8 +156,8 @@ OpenOCD internally. @xref{Debug Adapter Hardware}.
@b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, @b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T,
ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3 ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3
(Stellaris LM3, ST STM32 and Energy Micro EFM32) and Intel Quark (x10xx) (Stellaris LM3, STMicroelectronics STM32 and Energy Micro EFM32) and
based cores to be debugged via the GDB protocol. Intel Quark (x10xx) based cores to be debugged via the GDB protocol.
@b{Flash Programming:} Flash writing is supported for external @b{Flash Programming:} Flash writing is supported for external
CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several
@ -477,8 +477,8 @@ SWD and not JTAG, thus not supported.
@end itemize @end itemize
@section USB ST-LINK based @section USB ST-LINK based
ST Micro has an adapter called @b{ST-LINK}. STMicroelectronics has an adapter called @b{ST-LINK}.
They only work with ST Micro chips, notably STM32 and STM8. They only work with STMicroelectronics chips, notably STM32 and STM8.
@itemize @bullet @itemize @bullet
@item @b{ST-LINK} @item @b{ST-LINK}
@ -487,6 +487,9 @@ They only work with ST Micro chips, notably STM32 and STM8.
@item @b{ST-LINK/V2} @item @b{ST-LINK/V2}
@* This is available standalone and as part of some kits, eg. STM32F4DISCOVERY. @* This is available standalone and as part of some kits, eg. STM32F4DISCOVERY.
@* Link: @url{http://www.st.com/internet/evalboard/product/251168.jsp} @* Link: @url{http://www.st.com/internet/evalboard/product/251168.jsp}
@item @b{STLINK-V3}
@* This is available standalone and as part of some kits.
@* Link: @url{http://www.st.com/stlink-v3}
@end itemize @end itemize
For info the original ST-LINK enumerates using the mass storage usb class; however, For info the original ST-LINK enumerates using the mass storage usb class; however,
@ -535,6 +538,12 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/
@item @b{TI XDS110 Debug Probe} @item @b{TI XDS110 Debug Probe}
@* The XDS110 is included as the embedded debug probe on many Texas Instruments @* The XDS110 is included as the embedded debug probe on many Texas Instruments
LaunchPad evaluation boards. LaunchPad evaluation boards.
@* The XDS110 is also available as a stand-alone USB debug probe. The XDS110
stand-alone probe has the additional ability to supply voltage to the target
board via its AUX FUNCTIONS port. Use the
@command{xds110_supply_voltage <millivolts>} command to set the voltage. 0 turns
off the supply. Otherwise, the supply can be set to any value in the range 1800
to 3600 millivolts.
@* Link: @url{http://processors.wiki.ti.com/index.php/XDS110} @* Link: @url{http://processors.wiki.ti.com/index.php/XDS110}
@* Link: @url{http://processors.wiki.ti.com/index.php/XDS_Emulation_Software_Package#XDS110_Support_Utilities} @* Link: @url{http://processors.wiki.ti.com/index.php/XDS_Emulation_Software_Package#XDS110_Support_Utilities}
@end itemize @end itemize
@ -2359,6 +2368,16 @@ the hardware can support.
Returns the name of the debug adapter driver being used. Returns the name of the debug adapter driver being used.
@end deffn @end deffn
@deffn Command {adapter usb location} <bus>:<port>[.<port>]...
Specifies the physical USB port of the adapter to use. The path
roots at @var{bus} and walks down the physical ports, with each
@var{port} option specifying a deeper level in the bus topology, the last
@var{port} denoting where the target adapter is actually plugged.
The USB bus topology can be queried with the command @emph{lsusb -t} or @emph{dmesg}.
This command is only available if your libusb1 is at least version 1.0.16.
@end deffn
@section Interface Drivers @section Interface Drivers
Each of the interface drivers listed here must be explicitly Each of the interface drivers listed here must be explicitly
@ -2578,10 +2597,11 @@ For example adapter definitions, see the configuration files shipped in the
@end deffn @end deffn
@deffn {Interface Driver} {ft232r} @deffn {Interface Driver} {ft232r}
This driver is implementing synchronous bitbang mode of an FTDI FT232R This driver is implementing synchronous bitbang mode of an FTDI FT232R,
USB UART bridge IC. FT230X, FT231X and similar USB UART bridge ICs by reusing RS232 signals as GPIO.
It currently doesn't support using CBUS pins as GPIO.
List of connections (pin numbers for SSOP): List of connections (default physical pin numbers for FT232R in 28-pin SSOP package):
@itemize @minus @itemize @minus
@item RXD(5) - TDI @item RXD(5) - TDI
@item TXD(1) - TCK @item TXD(1) - TCK
@ -2591,6 +2611,27 @@ List of connections (pin numbers for SSOP):
@item DCD(10) - SRST @item DCD(10) - SRST
@end itemize @end itemize
User can change default pinout by supplying configuration
commands with GPIO numbers or RS232 signal names.
GPIO numbers correspond to bit numbers in FTDI GPIO register.
They differ from physical pin numbers.
For details see actual FTDI chip datasheets.
Every JTAG line must be configured to unique GPIO number
different than any other JTAG line, even those lines
that are sometimes not used like TRST or SRST.
FT232R
@itemize @minus
@item bit 7 - RI
@item bit 6 - DCD
@item bit 5 - DSR
@item bit 4 - DTR
@item bit 3 - CTS
@item bit 2 - RTS
@item bit 1 - RXD
@item bit 0 - TXD
@end itemize
These interfaces have several commands, used to configure the driver These interfaces have several commands, used to configure the driver
before initializing the JTAG scan chain: before initializing the JTAG scan chain:
@ -2605,6 +2646,47 @@ vendor provides unique IDs and more than one adapter is connected to
the host. If not specified, serial numbers are not considered. the host. If not specified, serial numbers are not considered.
@end deffn @end deffn
@deffn {Config Command} {ft232r_jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo}
Set four JTAG GPIO numbers at once.
If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used.
@end deffn
@deffn {Config Command} {ft232r_tck_num} @var{tck}
Set TCK GPIO number. If not specified, default 0 or TXD is used.
@end deffn
@deffn {Config Command} {ft232r_tms_num} @var{tms}
Set TMS GPIO number. If not specified, default 3 or CTS is used.
@end deffn
@deffn {Config Command} {ft232r_tdi_num} @var{tdi}
Set TDI GPIO number. If not specified, default 1 or RXD is used.
@end deffn
@deffn {Config Command} {ft232r_tdo_num} @var{tdo}
Set TDO GPIO number. If not specified, default 2 or RTS is used.
@end deffn
@deffn {Config Command} {ft232r_trst_num} @var{trst}
Set TRST GPIO number. If not specified, default 4 or DTR is used.
@end deffn
@deffn {Config Command} {ft232r_srst_num} @var{srst}
Set SRST GPIO number. If not specified, default 6 or DCD is used.
@end deffn
@deffn {Config Command} {ft232r_restore_serial} @var{word}
Restore serial port after JTAG. This USB bitmode control word
(16-bit) will be sent before quit. Lower byte should
set GPIO direction register to a "sane" state:
0x15 for TXD RTS DTR as outputs (1), others as inputs (0). Higher
byte is usually 0 to disable bitbang mode.
When kernel driver reattaches, serial port should continue to work.
Value 0xFFFF disables sending control word and serial port,
then kernel driver will not reattach.
If not specified, default 0xFFFF is used.
@end deffn
@end deffn @end deffn
@deffn {Interface Driver} {remote_bitbang} @deffn {Interface Driver} {remote_bitbang}
@ -2981,7 +3063,7 @@ This is a driver that supports multiple High Level Adapters.
This type of adapter does not expose some of the lower level api's This type of adapter does not expose some of the lower level api's
that OpenOCD would normally use to access the target. that OpenOCD would normally use to access the target.
Currently supported adapters include the ST ST-LINK and TI ICDI. Currently supported adapters include the STMicroelectronics ST-LINK and TI ICDI.
ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier ST-LINK firmware version >= V2.J21.S4 recommended due to issues with earlier
versions of firmware where serial number is reset after first use. Suggest versions of firmware where serial number is reset after first use. Suggest
using ST firmware update utility to upgrade ST-LINK firmware even if current using ST firmware update utility to upgrade ST-LINK firmware even if current
@ -3392,6 +3474,7 @@ How long (in milliseconds) OpenOCD should wait after deasserting
nTRST (active-low JTAG TAP reset) before starting new JTAG operations. nTRST (active-low JTAG TAP reset) before starting new JTAG operations.
@end deffn @end deffn
@anchor {reset_config}
@deffn {Command} reset_config mode_flag ... @deffn {Command} reset_config mode_flag ...
This command displays or modifies the reset configuration This command displays or modifies the reset configuration
of your combination of JTAG board and target in target of your combination of JTAG board and target in target
@ -4026,13 +4109,13 @@ resources; then a @file{board.cfg} with off-chip resources, clocking,
and so forth. and so forth.
@anchor{dapdeclaration} @anchor{dapdeclaration}
@section DAP declaration (ARMv7 and ARMv8 targets) @section DAP declaration (ARMv6-M, ARMv7 and ARMv8 targets)
@cindex DAP declaration @cindex DAP declaration
Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is Since OpenOCD version 0.11.0, the Debug Access Port (DAP) is
no longer implicitly created together with the target. It must be no longer implicitly created together with the target. It must be
explicitly declared using the @command{dap create} command. For all explicitly declared using the @command{dap create} command. For all ARMv6-M, ARMv7
ARMv7 and ARMv8 targets, the option "@option{-dap} @var{dap_name}" has to be used and ARMv8 targets, the option "@option{-dap} @var{dap_name}" has to be used
instead of "@option{-chain-position} @var{dotted.name}" when the target is created. instead of "@option{-chain-position} @var{dotted.name}" when the target is created.
The @command{dap} command group supports the following sub-commands: The @command{dap} command group supports the following sub-commands:
@ -5280,12 +5363,12 @@ since the alternate function must be enabled on the GPIO pin
CS1/CS2 is routed to on the given SoC. CS1/CS2 is routed to on the given SoC.
@example @example
flash bank $_FLASHNAME ath79 0 0 0 0 $_TARGETNAME flash bank $_FLASHNAME ath79 0xbf000000 0 0 0 $_TARGETNAME
# When using multiple chipselects the base should be different for each, # When using multiple chipselects the base should be different for each,
# otherwise the write_image command is not able to distinguish the # otherwise the write_image command is not able to distinguish the
# banks. # banks.
flash bank flash0 ath79 0x00000000 0 0 0 $_TARGETNAME cs0 flash bank flash0 ath79 0xbf000000 0 0 0 $_TARGETNAME cs0
flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1 flash bank flash1 ath79 0x10000000 0 0 0 $_TARGETNAME cs1
flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2 flash bank flash2 ath79 0x20000000 0 0 0 $_TARGETNAME cs2
@end example @end example
@ -5367,9 +5450,16 @@ the flash.
@anchor{at91samd} @anchor{at91samd}
@deffn {Flash Driver} at91samd @deffn {Flash Driver} at91samd
@cindex at91samd @cindex at91samd
All members of the ATSAMD, ATSAMR, ATSAML and ATSAMC microcontroller All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller
families from Atmel include internal flash and use ARM's Cortex-M0+ core. families from Atmel include internal flash and use ARM's Cortex-M0+ core.
This driver uses the same command names/syntax as @xref{at91sam3}.
Do not use for ATSAM D51 and E5x: use @xref{atsame5} instead.
The devices have one flash bank:
@example
flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME
@end example
@deffn Command {at91samd chip-erase} @deffn Command {at91samd chip-erase}
Issues a complete Flash erase via the Device Service Unit (DSU). This can be Issues a complete Flash erase via the Device Service Unit (DSU). This can be
@ -5531,9 +5621,72 @@ Command is used internally in event event reset-deassert-post.
@end deffn @end deffn
@end deffn @end deffn
@anchor{atsame5}
@deffn {Flash Driver} atsame5
@cindex atsame5
All members of the SAM E54, E53, E51 and D51 microcontroller
families from Microchip (former Atmel) include internal flash
and use ARM's Cortex-M4 core.
The devices have two ECC flash banks with a swapping feature.
This driver handles both banks together as it were one.
Bank swapping is not supported yet.
@example
flash bank $_FLASHNAME atsame5 0x00000000 0 1 1 $_TARGETNAME
@end example
@deffn Command {atsame5 bootloader}
Shows or sets the bootloader size configuration, stored in the User Page of the
Flash. This is called the BOOTPROT region. When setting, the bootloader size
must be specified in bytes. The nearest bigger protection size is used.
Settings are written immediately but only take effect on MCU reset.
Setting the bootloader size to 0 disables bootloader protection.
@example
atsame5 bootloader
atsame5 bootloader 16384
@end example
@end deffn
@deffn Command {atsame5 chip-erase}
Issues a complete Flash erase via the Device Service Unit (DSU). This can be
used to erase a chip back to its factory state and does not require the
processor to be halted.
@end deffn
@deffn Command {atsame5 dsu_reset_deassert}
This command releases internal reset held by DSU
and prepares reset vector catch in case of reset halt.
Command is used internally in event event reset-deassert-post.
@end deffn
@deffn Command {atsame5 userpage}
Writes or reads the first 64 bits of NVM User Page which is located at
0x804000. This field includes various fuses.
Reading is done by invoking this command without any arguments.
Writing is possible by giving 1 or 2 hex values. The first argument
is the value to be written and the second one is an optional bit mask
(a zero bit in the mask means the bit stays unchanged).
The reserved fields are always masked out and cannot be changed.
@example
# Read
>atsame5 userpage
USER PAGE: 0xAEECFF80FE9A9239
# Write
>atsame5 userpage 0xAEECFF80FE9A9239
# Write 2 to SEESBLK and 4 to SEEPSZ fields but leave other bits unchanged
# (setup SmartEEPROM of virtual size 8192 bytes)
>atsame5 userpage 0x4200000000 0x7f00000000
@end example
@end deffn
@end deffn
@deffn {Flash Driver} atsamv @deffn {Flash Driver} atsamv
@cindex atsamv @cindex atsamv
All members of the ATSAMV, ATSAMS, and ATSAME families from All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from
Atmel include internal flash and use ARM's Cortex-M7 core. Atmel include internal flash and use ARM's Cortex-M7 core.
This driver uses the same command names/syntax as @xref{at91sam3}. This driver uses the same command names/syntax as @xref{at91sam3}.
@end deffn @end deffn
@ -5618,7 +5771,7 @@ Triggering a mass erase is also useful when users want to disable readout protec
All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas
Instruments include internal flash. The cc26xx flash driver supports both the Instruments include internal flash. The cc26xx flash driver supports both the
CC13xx and CC26xx family of devices. The driver automatically recognizes the CC13xx and CC26xx family of devices. The driver automatically recognizes the
specific version's flash parameters and autoconfigures itself. Flash bank 0 specific version's flash parameters and autoconfigures itself. The flash bank
starts at address 0. starts at address 0.
@example @example
@ -5668,16 +5821,17 @@ configuration register interface, @option{clock_hz} is the expected clock
frequency, and @option{wait_states} is the number of configured read wait states. frequency, and @option{wait_states} is the number of configured read wait states.
@example @example
flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 $_TARGETNAME cfg_address clock_hz wait_states flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 \
$_TARGETNAME cfg_address clock_hz wait_states
@end example @end example
@deffn Command {esirisc_flash mass_erase} (bank_id) @deffn Command {esirisc flash mass_erase} bank_id
Erases all pages in data memory for the bank identified by @option{bank_id}. Erase all pages in data memory for the bank identified by @option{bank_id}.
@end deffn @end deffn
@deffn Command {esirisc_flash ref_erase} (bank_id) @deffn Command {esirisc flash ref_erase} bank_id
Erases the reference cell for the bank identified by @option{bank_id}. This is Erase the reference cell for the bank identified by @option{bank_id}. @emph{This
an uncommon operation. is an uncommon operation.}
@end deffn @end deffn
@end deffn @end deffn
@ -5843,8 +5997,8 @@ Command disables watchdog timer.
@deffn {Flash Driver} lpc2000 @deffn {Flash Driver} lpc2000
This is the driver to support internal flash of all members of the This is the driver to support internal flash of all members of the
LPC11(x)00 and LPC1300 microcontroller families and most members of LPC11(x)00 and LPC1300 microcontroller families and most members of
the LPC800, LPC1500, LPC1700, LPC1800, LPC2000, LPC4000 and LPC54100 the LPC800, LPC1500, LPC1700, LPC1800, LPC2000, LPC4000, LPC54100,
microcontroller families from NXP. LPC8Nxx and NHS31xx microcontroller families from NXP.
@quotation Note @quotation Note
There are LPC2000 devices which are not supported by the @var{lpc2000} There are LPC2000 devices which are not supported by the @var{lpc2000}
@ -5853,7 +6007,7 @@ The LPC2888 is supported by the @var{lpc288x} driver.
The LPC29xx family is supported by the @var{lpc2900} driver. The LPC29xx family is supported by the @var{lpc2900} driver.
@end quotation @end quotation
The @var{lpc2000} driver defines two mandatory and one optional parameters, The @var{lpc2000} driver defines two mandatory and two optional parameters,
which must appear in the following order: which must appear in the following order:
@itemize @itemize
@ -5869,7 +6023,7 @@ LPC43x[2357])
@option{lpc54100} (LPC541xx) @option{lpc54100} (LPC541xx)
@option{lpc4000} (LPC40xx) @option{lpc4000} (LPC40xx)
or @option{auto} - automatically detects flash variant and size for LPC11(x)00, or @option{auto} - automatically detects flash variant and size for LPC11(x)00,
LPC8xx, LPC13xx, LPC17xx and LPC40xx LPC8xx, LPC13xx, LPC17xx, LPC40xx, LPC8Nxx and NHS31xx
@item @var{clock_kHz} ... the frequency, in kiloHertz, @item @var{clock_kHz} ... the frequency, in kiloHertz,
at which the core is running at which the core is running
@item @option{calc_checksum} ... optional (but you probably want to provide this!), @item @option{calc_checksum} ... optional (but you probably want to provide this!),
@ -5880,6 +6034,8 @@ table, the boot ROM will almost certainly ignore your flash image.
However, if you do provide it, However, if you do provide it,
with most tool chains @command{verify_image} will fail. with most tool chains @command{verify_image} will fail.
@end quotation @end quotation
@item @option{iap_entry} ... optional telling the driver to use a different
ROM IAP entry point.
@end itemize @end itemize
LPC flashes don't require the chip and bus width to be specified. LPC flashes don't require the chip and bus width to be specified.
@ -6415,7 +6571,7 @@ applied to all of them.
@deffn {Flash Driver} stm32f1x @deffn {Flash Driver} stm32f1x
All members of the STM32F0, STM32F1 and STM32F3 microcontroller families All members of the STM32F0, STM32F1 and STM32F3 microcontroller families
from ST Microelectronics include internal flash and use ARM Cortex-M0/M3/M4 cores. from STMicroelectronics include internal flash and use ARM Cortex-M0/M3/M4 cores.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -6461,9 +6617,10 @@ or upon executing the @command{stm32f1x options_load} command.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn Command {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) @deffn Command {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) (@option{USEROPT} user_data)
Writes the stm32 option byte with the specified values. Writes the stm32 option byte with the specified values.
The @var{num} parameter is a value shown by @command{flash banks}. The @var{num} parameter is a value shown by @command{flash banks}.
The @var{user_data} parameter is content of higher 16 bits of the option byte register (Data0 and Data1 as one 16bit number).
@end deffn @end deffn
@deffn Command {stm32f1x options_load} num @deffn Command {stm32f1x options_load} num
@ -6475,7 +6632,7 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn {Flash Driver} stm32f2x @deffn {Flash Driver} stm32f2x
All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from ST Microelectronics All members of the STM32F2, STM32F4 and STM32F7 microcontroller families from STMicroelectronics
include internal flash and use ARM Cortex-M3/M4/M7 cores. include internal flash and use ARM Cortex-M3/M4/M7 cores.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -6529,7 +6686,7 @@ The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2}
@end deffn @end deffn
@deffn {Flash Driver} stm32h7x @deffn {Flash Driver} stm32h7x
All members of the STM32H7 microcontroller families from ST Microelectronics All members of the STM32H7 microcontroller families from STMicroelectronics
include internal flash and use ARM Cortex-M7 core. include internal flash and use ARM Cortex-M7 core.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -6565,7 +6722,7 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn {Flash Driver} stm32lx @deffn {Flash Driver} stm32lx
All members of the STM32L microcontroller families from ST Microelectronics All members of the STM32L microcontroller families from STMicroelectronics
include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -6605,7 +6762,7 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn {Flash Driver} stm32l4x @deffn {Flash Driver} stm32l4x
All members of the STM32L4 microcontroller families from ST Microelectronics All members of the STM32L4 microcontroller families from STMicroelectronics
include internal flash and use ARM Cortex-M4 cores. include internal flash and use ARM Cortex-M4 cores.
The driver automatically recognizes a number of these chips using The driver automatically recognizes a number of these chips using
the chip identification register, and autoconfigures itself. the chip identification register, and autoconfigures itself.
@ -6677,7 +6834,7 @@ The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn @end deffn
@deffn {Flash Driver} str7x @deffn {Flash Driver} str7x
All members of the STR7 microcontroller family from ST Microelectronics All members of the STR7 microcontroller family from STMicroelectronics
include internal flash and use ARM7TDMI cores. include internal flash and use ARM7TDMI cores.
The @var{str7x} driver defines one mandatory parameter, @var{variant}, The @var{str7x} driver defines one mandatory parameter, @var{variant},
which is either @code{STR71x}, @code{STR73x} or @code{STR75x}. which is either @code{STR71x}, @code{STR73x} or @code{STR75x}.
@ -6694,7 +6851,7 @@ for the specified flash bank.
@end deffn @end deffn
@deffn {Flash Driver} str9x @deffn {Flash Driver} str9x
Most members of the STR9 microcontroller family from ST Microelectronics Most members of the STR9 microcontroller family from STMicroelectronics
include internal flash and use ARM966E cores. include internal flash and use ARM966E cores.
The str9 needs the flash controller to be configured using The str9 needs the flash controller to be configured using
the @command{str9x flash_config} command prior to Flash programming. the @command{str9x flash_config} command prior to Flash programming.
@ -6834,6 +6991,17 @@ the flash clock.
@end deffn @end deffn
@end deffn @end deffn
@deffn {Flash Driver} w600
W60x series Wi-Fi SoC from WinnerMicro
are designed with ARM Cortex-M3 and have 1M Byte QFLASH inside.
The @var{w600} driver uses the @var{target} parameter to select the
correct bank config.
@example
flash bank $_FLASHNAME w600 0x08000000 0 0 0 $_TARGETNAMEs
@end example
@end deffn
@deffn {Flash Driver} xmc1xxx @deffn {Flash Driver} xmc1xxx
All members of the XMC1xxx microcontroller family from Infineon. All members of the XMC1xxx microcontroller family from Infineon.
This driver does not require the chip and bus width to be specified. This driver does not require the chip and bus width to be specified.
@ -8938,19 +9106,23 @@ must also be explicitly enabled.
This finishes by listing the current vector catch configuration. This finishes by listing the current vector catch configuration.
@end deffn @end deffn
@deffn Command {cortex_m reset_config} (@option{srst}|@option{sysresetreq}|@option{vectreset}) @deffn Command {cortex_m reset_config} (@option{sysresetreq}|@option{vectreset})
Control reset handling. The default @option{srst} is to use srst if fitted, Control reset handling if hardware srst is not fitted
otherwise fallback to @option{vectreset}. @xref{reset_config,,reset_config}.
@itemize @minus @itemize @minus
@item @option{srst} use hardware srst if fitted otherwise fallback to @option{vectreset}. @item @option{sysresetreq} use AIRCR SYSRESETREQ to reset system.
@item @option{sysresetreq} use NVIC SYSRESETREQ to reset system. @item @option{vectreset} use AIRCR VECTRESET to reset system (default).
@item @option{vectreset} use NVIC VECTRESET to reset system.
@end itemize @end itemize
Using @option{vectreset} is a safe option for all current Cortex-M cores.
Using @option{vectreset} is a safe option for Cortex-M3, M4 and M7 cores.
This however has the disadvantage of only resetting the core, all peripherals This however has the disadvantage of only resetting the core, all peripherals
are unaffected. A solution would be to use a @code{reset-init} event handler to manually reset are unaffected. A solution would be to use a @code{reset-init} event handler
the peripherals. to manually reset the peripherals.
@xref{targetevents,,Target Events}. @xref{targetevents,,Target Events}.
Cortex-M0, M0+ and M1 do not support @option{vectreset}, use @option{sysresetreq}
instead.
@end deffn @end deffn
@subsection ARMv8-A specific commands @subsection ARMv8-A specific commands
@ -8986,17 +9158,13 @@ Selects whether interrupts will be processed when single stepping. The default c
eSi-RISC is a highly configurable microprocessor architecture for embedded systems eSi-RISC is a highly configurable microprocessor architecture for embedded systems
provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.) provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.)
@subsection esirisc specific commands @subsection eSi-RISC Configuration
@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann}) @deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann})
Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE} Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE}
option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed. option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed.
@end deffn @end deffn
@deffn Command {esirisc flush_caches}
Flush instruction and data caches. This command requires that the target is halted
when the command is issued and configured with an instruction or data cache.
@end deffn
@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...) @deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...)
Configure hardware debug control. The HWDC register controls which exceptions return Configure hardware debug control. The HWDC register controls which exceptions return
control back to the debugger. Possible masks are @option{all}, @option{none}, control back to the debugger. Possible masks are @option{all}, @option{none},
@ -9004,6 +9172,164 @@ control back to the debugger. Possible masks are @option{all}, @option{none},
By default, @option{reset}, @option{error}, and @option{debug} are enabled. By default, @option{reset}, @option{error}, and @option{debug} are enabled.
@end deffn @end deffn
@subsection eSi-RISC Operation
@deffn Command {esirisc flush_caches}
Flush instruction and data caches. This command requires that the target is halted
when the command is issued and configured with an instruction or data cache.
@end deffn
@subsection eSi-Trace Configuration
eSi-RISC targets may be configured with support for instruction tracing. Trace
data may be written to an in-memory buffer or FIFO. If a FIFO is configured, DMA
is typically employed to move trace data off-device using a high-speed
peripheral (eg. SPI). Collected trace data is encoded in one of three different
formats. At a minimum, @command{esirisc trace buffer} or @command{esirisc trace
fifo} must be issued along with @command{esirisc trace format} before trace data
can be collected.
OpenOCD provides rudimentary analysis of collected trace data. If more detail is
needed, collected trace data can be dumped to a file and processed by external
tooling.
@quotation Issues
OpenOCD is unable to process trace data sent to a FIFO. A potential workaround
for this issue is to configure DMA to copy trace data to an in-memory buffer,
which can then be passed to the @command{esirisc trace analyze} and
@command{esirisc trace dump} commands.
It is possible to corrupt trace data when using a FIFO if the peripheral
responsible for draining data from the FIFO is not fast enough. This can be
managed by enabling flow control, however this can impact timing-sensitive
software operation on the CPU.
@end quotation
@deffn Command {esirisc trace buffer} address size [@option{wrap}]
Configure trace buffer using the provided address and size. If the @option{wrap}
option is specified, trace collection will continue once the end of the buffer
is reached. By default, wrap is disabled.
@end deffn
@deffn Command {esirisc trace fifo} address
Configure trace FIFO using the provided address.
@end deffn
@deffn Command {esirisc trace flow_control} (@option{enable}|@option{disable})
Enable or disable stalling the CPU to collect trace data. By default, flow
control is disabled.
@end deffn
@deffn Command {esirisc trace format} (@option{full}|@option{branch}|@option{icache}) pc_bits
Configure trace format and number of PC bits to be captured. @option{pc_bits}
must be within 1 and 31 as the LSB is not collected. If external tooling is used
to analyze collected trace data, these values must match.
Supported trace formats:
@itemize
@item @option{full} capture full trace data, allowing execution history and
timing to be determined.
@item @option{branch} capture taken branch instructions and branch target
addresses.
@item @option{icache} capture instruction cache misses.
@end itemize
@end deffn
@deffn Command {esirisc trace trigger start} (@option{condition}) [start_data start_mask]
Configure trigger start condition using the provided start data and mask. A
brief description of each condition is provided below; for more detail on how
these values are used, see the eSi-RISC Architecture Manual.
Supported conditions:
@itemize
@item @option{none} manual tracing (see @command{esirisc trace start}).
@item @option{pc} start tracing if the PC matches start data and mask.
@item @option{load} start tracing if the effective address of a load
instruction matches start data and mask.
@item @option{store} start tracing if the effective address of a store
instruction matches start data and mask.
@item @option{exception} start tracing if the EID of an exception matches start
data and mask.
@item @option{eret} start tracing when an @code{ERET} instruction is executed.
@item @option{wait} start tracing when a @code{WAIT} instruction is executed.
@item @option{stop} start tracing when a @code{STOP} instruction is executed.
@item @option{high} start tracing when an external signal is a logical high.
@item @option{low} start tracing when an external signal is a logical low.
@end itemize
@end deffn
@deffn Command {esirisc trace trigger stop} (@option{condition}) [stop_data stop_mask]
Configure trigger stop condition using the provided stop data and mask. A brief
description of each condition is provided below; for more detail on how these
values are used, see the eSi-RISC Architecture Manual.
Supported conditions:
@itemize
@item @option{none} manual tracing (see @command{esirisc trace stop}).
@item @option{pc} stop tracing if the PC matches stop data and mask.
@item @option{load} stop tracing if the effective address of a load
instruction matches stop data and mask.
@item @option{store} stop tracing if the effective address of a store
instruction matches stop data and mask.
@item @option{exception} stop tracing if the EID of an exception matches stop
data and mask.
@item @option{eret} stop tracing when an @code{ERET} instruction is executed.
@item @option{wait} stop tracing when a @code{WAIT} instruction is executed.
@item @option{stop} stop tracing when a @code{STOP} instruction is executed.
@end itemize
@end deffn
@deffn Command {esirisc trace trigger delay} (@option{trigger}) [cycles]
Configure trigger start/stop delay in clock cycles.
Supported triggers:
@itemize
@item @option{none} no delay to start or stop collection.
@item @option{start} delay @option{cycles} after trigger to start collection.
@item @option{stop} delay @option{cycles} after trigger to stop collection.
@item @option{both} delay @option{cycles} after both triggers to start or stop
collection.
@end itemize
@end deffn
@subsection eSi-Trace Operation
@deffn Command {esirisc trace init}
Initialize trace collection. This command must be called any time the
configuration changes. If an trace buffer has been configured, the contents will
be overwritten when trace collection starts.
@end deffn
@deffn Command {esirisc trace info}
Display trace configuration.
@end deffn
@deffn Command {esirisc trace status}
Display trace collection status.
@end deffn
@deffn Command {esirisc trace start}
Start manual trace collection.
@end deffn
@deffn Command {esirisc trace stop}
Stop manual trace collection.
@end deffn
@deffn Command {esirisc trace analyze} [address size]
Analyze collected trace data. This command may only be used if a trace buffer
has been configured. If a trace FIFO has been configured, trace data must be
copied to an in-memory buffer identified by the @option{address} and
@option{size} options using DMA.
@end deffn
@deffn Command {esirisc trace dump} [address size] @file{filename}
Dump collected trace data to file. This command may only be used if a trace
buffer has been configured. If a trace FIFO has been configured, trace data must
be copied to an in-memory buffer identified by the @option{address} and
@option{size} options using DMA.
@end deffn
@section Intel Architecture @section Intel Architecture
Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32 Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32

View File

@ -179,6 +179,7 @@ COMMAND_HANDLER(handle_mxc_biswap_command)
static const struct command_registration mxc_sub_command_handlers[] = { static const struct command_registration mxc_sub_command_handlers[] = {
{ {
.name = "biswap", .name = "biswap",
.mode = COMMAND_EXEC,
.handler = handle_mxc_biswap_command, .handler = handle_mxc_biswap_command,
.help = "Turns on/off bad block information swaping from main area, " .help = "Turns on/off bad block information swaping from main area, "
"without parameter query status.", "without parameter query status.",

View File

@ -17,6 +17,7 @@ NOR_DRIVERS = \
%D%/at91sam7.c \ %D%/at91sam7.c \
%D%/ath79.c \ %D%/ath79.c \
%D%/atsamv.c \ %D%/atsamv.c \
%D%/atsame5.c \
%D%/avrf.c \ %D%/avrf.c \
%D%/bluenrg-x.c \ %D%/bluenrg-x.c \
%D%/cc3220sf.c \ %D%/cc3220sf.c \
@ -64,6 +65,7 @@ NOR_DRIVERS = \
%D%/str9xpec.c \ %D%/str9xpec.c \
%D%/tms470.c \ %D%/tms470.c \
%D%/virtual.c \ %D%/virtual.c \
%D%/w600.c \
%D%/xcf.c \ %D%/xcf.c \
%D%/xmc1xxx.c \ %D%/xmc1xxx.c \
%D%/xmc4xxx.c %D%/xmc4xxx.c

View File

@ -74,12 +74,6 @@ static int aduc702x_build_sector_list(struct flash_bank *bank)
return ERROR_OK; return ERROR_OK;
} }
static int aduc702x_protect_check(struct flash_bank *bank)
{
printf("aduc702x_protect_check not implemented yet.\n");
return ERROR_OK;
}
static int aduc702x_erase(struct flash_bank *bank, int first, int last) static int aduc702x_erase(struct flash_bank *bank, int first, int last)
{ {
/* int res; */ /* int res; */
@ -130,12 +124,6 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK; return ERROR_OK;
} }
static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
{
printf("aduc702x_protect not implemented yet.\n");
return ERROR_FLASH_OPERATION_FAILED;
}
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
* back to another mechanism that does not require onboard RAM * back to another mechanism that does not require onboard RAM
* *
@ -394,11 +382,9 @@ struct flash_driver aduc702x_flash = {
.name = "aduc702x", .name = "aduc702x",
.flash_bank_command = aduc702x_flash_bank_command, .flash_bank_command = aduc702x_flash_bank_command,
.erase = aduc702x_erase, .erase = aduc702x_erase,
.protect = aduc702x_protect,
.write = aduc702x_write, .write = aduc702x_write,
.read = default_flash_read, .read = default_flash_read,
.probe = aduc702x_probe, .probe = aduc702x_probe,
.auto_probe = aduc702x_probe, .auto_probe = aduc702x_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = aduc702x_protect_check,
}; };

View File

@ -102,13 +102,6 @@ static int aducm360_build_sector_list(struct flash_bank *bank)
return ERROR_OK; return ERROR_OK;
} }
/* ----------------------------------------------------------------------- */
static int aducm360_protect_check(struct flash_bank *bank)
{
LOG_WARNING("aducm360_protect_check not implemented.");
return ERROR_OK;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
static int aducm360_mass_erase(struct target *target) static int aducm360_mass_erase(struct target *target)
{ {
@ -194,13 +187,6 @@ static int aducm360_erase(struct flash_bank *bank, int first, int last)
return res; return res;
} }
/* ----------------------------------------------------------------------- */
static int aducm360_protect(struct flash_bank *bank, int set, int first, int last)
{
LOG_ERROR("aducm360_protect not implemented.");
return ERROR_FLASH_OPERATION_FAILED;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
static int aducm360_write_block_sync( static int aducm360_write_block_sync(
struct flash_bank *bank, struct flash_bank *bank,
@ -572,11 +558,9 @@ struct flash_driver aducm360_flash = {
.name = "aducm360", .name = "aducm360",
.flash_bank_command = aducm360_flash_bank_command, .flash_bank_command = aducm360_flash_bank_command,
.erase = aducm360_erase, .erase = aducm360_erase,
.protect = aducm360_protect,
.write = aducm360_write, .write = aducm360_write,
.read = default_flash_read, .read = default_flash_read,
.probe = aducm360_probe, .probe = aducm360_probe,
.auto_probe = aducm360_probe, .auto_probe = aducm360_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = aducm360_protect_check,
}; };

View File

@ -2991,28 +2991,6 @@ static int sam3_GetInfo(struct sam3_chip *pChip)
return ERROR_OK; return ERROR_OK;
} }
static int sam3_erase_check(struct flash_bank *bank)
{
int x;
LOG_DEBUG("Here");
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (0 == bank->num_sectors) {
LOG_ERROR("Target: not supported/not probed");
return ERROR_FAIL;
}
LOG_INFO("sam3 - supports auto-erase, erase_check ignored");
for (x = 0; x < bank->num_sectors; x++)
bank->sectors[x].is_erased = 1;
LOG_DEBUG("Done");
return ERROR_OK;
}
static int sam3_protect_check(struct flash_bank *bank) static int sam3_protect_check(struct flash_bank *bank)
{ {
int r; int r;
@ -3785,7 +3763,7 @@ struct flash_driver at91sam3_flash = {
.read = default_flash_read, .read = default_flash_read,
.probe = sam3_probe, .probe = sam3_probe,
.auto_probe = sam3_auto_probe, .auto_probe = sam3_auto_probe,
.erase_check = sam3_erase_check, .erase_check = default_flash_blank_check,
.protect_check = sam3_protect_check, .protect_check = sam3_protect_check,
.free_driver_priv = sam3_free_driver_priv, .free_driver_priv = sam3_free_driver_priv,
}; };

View File

@ -180,6 +180,28 @@ static const struct samd_part samd21_parts[] = {
{ 0x24, "SAMD21G15B", 32, 4 }, { 0x24, "SAMD21G15B", 32, 4 },
{ 0x26, "SAMD21E16B", 64, 8 }, { 0x26, "SAMD21E16B", 64, 8 },
{ 0x27, "SAMD21E15B", 32, 4 }, { 0x27, "SAMD21E15B", 32, 4 },
/* Known SAMDA1 parts.
SAMD-A1 series uses the same series identifier like the SAMD21
taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */
{ 0x29, "SAMDA1J16A", 64, 8 },
{ 0x2A, "SAMDA1J15A", 32, 4 },
{ 0x2B, "SAMDA1J14A", 16, 4 },
{ 0x2C, "SAMDA1G16A", 64, 8 },
{ 0x2D, "SAMDA1G15A", 32, 4 },
{ 0x2E, "SAMDA1G14A", 16, 4 },
{ 0x2F, "SAMDA1E16A", 64, 8 },
{ 0x30, "SAMDA1E15A", 32, 4 },
{ 0x31, "SAMDA1E14A", 16, 4 },
{ 0x64, "SAMDA1J16B", 64, 8 },
{ 0x65, "SAMDA1J15B", 32, 4 },
{ 0x66, "SAMDA1J14B", 16, 4 },
{ 0x67, "SAMDA1G16B", 64, 8 },
{ 0x68, "SAMDA1G15B", 32, 4 },
{ 0x69, "SAMDA1G14B", 16, 4 },
{ 0x6A, "SAMDA1E16B", 64, 8 },
{ 0x6B, "SAMDA1E15B", 32, 4 },
{ 0x6C, "SAMDA1E14B", 16, 4 },
}; };
/* Known SAML21 parts. */ /* Known SAML21 parts. */
@ -208,6 +230,9 @@ static const struct samd_part saml21_parts[] = {
/* SAMR30 parts have integrated SAML21 with a radio */ /* SAMR30 parts have integrated SAML21 with a radio */
{ 0x1E, "SAMR30G18A", 256, 32 }, { 0x1E, "SAMR30G18A", 256, 32 },
{ 0x1F, "SAMR30E18A", 256, 32 }, { 0x1F, "SAMR30E18A", 256, 32 },
/* SAMR34/R35 parts have integrated SAML21 with a lora radio */
{ 0x28, "SAMR34J18", 256, 32 },
}; };
/* Known SAML22 parts. */ /* Known SAML22 parts. */
@ -237,6 +262,8 @@ static const struct samd_part samc20_parts[] = {
{ 0x0B, "SAMC20E17A", 128, 16 }, { 0x0B, "SAMC20E17A", 128, 16 },
{ 0x0C, "SAMC20E16A", 64, 8 }, { 0x0C, "SAMC20E16A", 64, 8 },
{ 0x0D, "SAMC20E15A", 32, 4 }, { 0x0D, "SAMC20E15A", 32, 4 },
{ 0x20, "SAMC20N18A", 256, 32 },
{ 0x21, "SAMC20N17A", 128, 16 },
}; };
/* Known SAMC21 parts. */ /* Known SAMC21 parts. */
@ -253,6 +280,8 @@ static const struct samd_part samc21_parts[] = {
{ 0x0B, "SAMC21E17A", 128, 16 }, { 0x0B, "SAMC21E17A", 128, 16 },
{ 0x0C, "SAMC21E16A", 64, 8 }, { 0x0C, "SAMC21E16A", 64, 8 },
{ 0x0D, "SAMC21E15A", 32, 4 }, { 0x0D, "SAMC21E15A", 32, 4 },
{ 0x20, "SAMC21N18A", 256, 32 },
{ 0x21, "SAMC21N17A", 128, 16 },
}; };
/* Each family of parts contains a parts table in the DEVSEL field of DID. The /* Each family of parts contains a parts table in the DEVSEL field of DID. The

View File

@ -522,6 +522,9 @@ static int ath79_erase(struct flash_bank *bank, int first, int last)
return ERROR_FLASH_BANK_NOT_PROBED; return ERROR_FLASH_BANK_NOT_PROBED;
} }
if (ath79_info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
for (sector = first; sector <= last; sector++) { for (sector = first; sector <= last; sector++) {
if (bank->sectors[sector].is_protected) { if (bank->sectors[sector].is_protected) {
LOG_ERROR("Flash sector %d protected", sector); LOG_ERROR("Flash sector %d protected", sector);
@ -560,7 +563,11 @@ static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
address, address,
}; };
int retval; int retval;
uint32_t i; uint32_t i, pagesize;
/* if no write pagesize, use reasonable default */
pagesize = ath79_info->dev->pagesize ?
ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
if (address & 0xff) { if (address & 0xff) {
LOG_ERROR("ath79_write_page: unaligned write address: %08x", LOG_ERROR("ath79_write_page: unaligned write address: %08x",
@ -573,7 +580,7 @@ static int ath79_write_page(struct flash_bank *bank, const uint8_t *buffer,
} }
if (len > ath79_info->dev->pagesize) { if (len > ath79_info->dev->pagesize) {
LOG_ERROR("ath79_write_page: len bigger than page size %d: %d", LOG_ERROR("ath79_write_page: len bigger than page size %d: %d",
ath79_info->dev->pagesize, len); pagesize, len);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -611,12 +618,16 @@ static int ath79_write_buffer(struct flash_bank *bank, const uint8_t *buffer,
uint32_t address, uint32_t len) uint32_t address, uint32_t len)
{ {
struct ath79_flash_bank *ath79_info = bank->driver_priv; struct ath79_flash_bank *ath79_info = bank->driver_priv;
const uint32_t page_size = ath79_info->dev->pagesize; uint32_t page_size;
int retval; int retval;
LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32,
__func__, address, len); __func__, address, len);
/* if no valid page_size, use reasonable default */
page_size = ath79_info->dev->pagesize ?
ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
while (len > 0) { while (len > 0) {
int page_len = len > page_size ? page_size : len; int page_len = len > page_size ? page_size : len;
@ -642,13 +653,6 @@ static int ath79_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
__func__, offset, count); __func__, offset, count);
if (offset < bank->base || offset >= bank->base + bank->size) {
LOG_ERROR("Start address out of range");
return ERROR_FAIL;
}
offset -= bank->base;
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted"); LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
@ -718,13 +722,6 @@ static int ath79_read(struct flash_bank *bank, uint8_t *buffer,
LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32,
__func__, offset, count); __func__, offset, count);
if (offset < bank->base || offset >= bank->base + bank->size) {
LOG_ERROR("Start address out of range");
return ERROR_FAIL;
}
offset -= bank->base;
if (target->state != TARGET_HALTED) { if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted"); LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
@ -775,6 +772,7 @@ static int ath79_probe(struct flash_bank *bank)
struct ath79_flash_bank *ath79_info = bank->driver_priv; struct ath79_flash_bank *ath79_info = bank->driver_priv;
struct flash_sector *sectors; struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */ uint32_t id = 0; /* silence uninitialized warning */
uint32_t pagesize, sectorsize;
const struct ath79_target *target_device; const struct ath79_target *target_device;
int retval; int retval;
@ -820,16 +818,27 @@ static int ath79_probe(struct flash_bank *bank)
/* Set correct size value */ /* Set correct size value */
bank->size = ath79_info->dev->size_in_bytes; bank->size = ath79_info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = ath79_info->dev->sectorsize ?
ath79_info->dev->sectorsize : ath79_info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = bank->num_sectors = ath79_info->dev->size_in_bytes / sectorsize;
ath79_info->dev->size_in_bytes / ath79_info->dev->sectorsize;
sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors); sectors = calloc(1, sizeof(struct flash_sector) * bank->num_sectors);
if (!sectors) { if (!sectors) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
return ERROR_FAIL; return ERROR_FAIL;
} }
ath79_info->spi.page_buf = malloc(ath79_info->dev->pagesize);
/* if no write pagesize, use reasonable default */
pagesize = ath79_info->dev->pagesize ? ath79_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
ath79_info->spi.page_buf = malloc(pagesize);
if (!ath79_info->spi.page_buf) { if (!ath79_info->spi.page_buf) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
free(sectors); free(sectors);
@ -837,8 +846,8 @@ static int ath79_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * ath79_info->dev->sectorsize; sectors[sector].offset = sector * sectorsize;
sectors[sector].size = ath79_info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].is_erased = 0; sectors[sector].is_erased = 0;
sectors[sector].is_protected = 1; sectors[sector].is_protected = 1;
} }

954
src/flash/nor/atsame5.c Normal file
View File

@ -0,0 +1,954 @@
/***************************************************************************
* Copyright (C) 2017 by Tomas Vanek *
* vanekt@fbl.cz *
* *
* Based on at91samd.c *
* Copyright (C) 2013 by Andrey Yurovsky *
* Andrey Yurovsky <yurovsky@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include "helper/binarybuffer.h"
#include <target/cortex_m.h>
/* A note to prefixing.
* Definitions and functions ingerited from at91samd.c without
* any change retained the original prefix samd_ so they eventualy
* may go to samd_common.h and .c
* As currently there are olny 3 short functions identical with
* the original source, no common file was created. */
#define SAME5_PAGES_PER_BLOCK 16
#define SAME5_NUM_PROT_BLOCKS 32
#define SAMD_PAGE_SIZE_MAX 1024
#define SAMD_FLASH 0x00000000 /* physical Flash memory */
#define SAMD_USER_ROW 0x00804000 /* User Row of Flash */
#define SAME5_PAC 0x40000000 /* Peripheral Access Control */
#define SAMD_DSU 0x41002000 /* Device Service Unit */
#define SAMD_NVMCTRL 0x41004000 /* Non-volatile memory controller */
#define SAMD_DSU_STATUSA 1 /* DSU status register */
#define SAMD_DSU_DID 0x18 /* Device ID register */
#define SAMD_DSU_CTRL_EXT 0x100 /* CTRL register, external access */
#define SAME5_NVMCTRL_CTRLA 0x00 /* NVM control A register */
#define SAME5_NVMCTRL_CTRLB 0x04 /* NVM control B register */
#define SAMD_NVMCTRL_PARAM 0x08 /* NVM parameters register */
#define SAME5_NVMCTRL_INTFLAG 0x10 /* NVM interrupt flag register */
#define SAME5_NVMCTRL_STATUS 0x12 /* NVM status register */
#define SAME5_NVMCTRL_ADDR 0x14 /* NVM address register */
#define SAME5_NVMCTRL_LOCK 0x18 /* NVM Lock section register */
#define SAMD_CMDEX_KEY 0xA5UL
#define SAMD_NVM_CMD(n) ((SAMD_CMDEX_KEY << 8) | (n & 0x7F))
/* NVMCTRL commands. */
#define SAME5_NVM_CMD_EP 0x00 /* Erase Page (User Page only) */
#define SAME5_NVM_CMD_EB 0x01 /* Erase Block */
#define SAME5_NVM_CMD_WP 0x03 /* Write Page */
#define SAME5_NVM_CMD_WQW 0x04 /* Write Quad Word */
#define SAME5_NVM_CMD_LR 0x11 /* Lock Region */
#define SAME5_NVM_CMD_UR 0x12 /* Unlock Region */
#define SAME5_NVM_CMD_PBC 0x15 /* Page Buffer Clear */
#define SAME5_NVM_CMD_SSB 0x16 /* Set Security Bit */
/* NVMCTRL bits */
#define SAME5_NVMCTRL_CTRLA_WMODE_MASK 0x30
#define SAME5_NVMCTRL_INTFLAG_DONE (1 << 0)
#define SAME5_NVMCTRL_INTFLAG_ADDRE (1 << 1)
#define SAME5_NVMCTRL_INTFLAG_PROGE (1 << 2)
#define SAME5_NVMCTRL_INTFLAG_LOCKE (1 << 3)
#define SAME5_NVMCTRL_INTFLAG_ECCSE (1 << 4)
#define SAME5_NVMCTRL_INTFLAG_ECCDE (1 << 5)
#define SAME5_NVMCTRL_INTFLAG_NVME (1 << 6)
/* Known identifiers */
#define SAMD_PROCESSOR_M0 0x01
#define SAMD_PROCESSOR_M4 0x06
#define SAMD_FAMILY_D 0x00
#define SAMD_FAMILY_E 0x03
#define SAMD_SERIES_51 0x06
#define SAME_SERIES_51 0x01
#define SAME_SERIES_53 0x03
#define SAME_SERIES_54 0x04
/* Device ID macros */
#define SAMD_GET_PROCESSOR(id) (id >> 28)
#define SAMD_GET_FAMILY(id) (((id >> 23) & 0x1F))
#define SAMD_GET_SERIES(id) (((id >> 16) & 0x3F))
#define SAMD_GET_DEVSEL(id) (id & 0xFF)
/* Bits to mask user row */
#define NVMUSERROW_SAM_E5_D5_MASK ((uint64_t)0x7FFF00FF3C007FFF)
struct samd_part {
uint8_t id;
const char *name;
uint32_t flash_kb;
uint32_t ram_kb;
};
/* See SAM D5x/E5x Family Silicon Errata and Data Sheet Clarification
* DS80000748B */
/* Known SAMD51 parts. */
static const struct samd_part samd51_parts[] = {
{ 0x00, "SAMD51P20A", 1024, 256 },
{ 0x01, "SAMD51P19A", 512, 192 },
{ 0x02, "SAMD51N20A", 1024, 256 },
{ 0x03, "SAMD51N19A", 512, 192 },
{ 0x04, "SAMD51J20A", 1024, 256 },
{ 0x05, "SAMD51J19A", 512, 192 },
{ 0x06, "SAMD51J18A", 256, 128 },
{ 0x07, "SAMD51G19A", 512, 192 },
{ 0x08, "SAMD51G18A", 256, 128 },
};
/* Known SAME51 parts. */
static const struct samd_part same51_parts[] = {
{ 0x00, "SAME51N20A", 1024, 256 },
{ 0x01, "SAME51N19A", 512, 192 },
{ 0x02, "SAME51J19A", 512, 192 },
{ 0x03, "SAME51J18A", 256, 128 },
{ 0x04, "SAME51J20A", 1024, 256 },
};
/* Known SAME53 parts. */
static const struct samd_part same53_parts[] = {
{ 0x02, "SAME53N20A", 1024, 256 },
{ 0x03, "SAME53N19A", 512, 192 },
{ 0x04, "SAME53J20A", 1024, 256 },
{ 0x05, "SAME53J19A", 512, 192 },
{ 0x06, "SAME53J18A", 256, 128 },
};
/* Known SAME54 parts. */
static const struct samd_part same54_parts[] = {
{ 0x00, "SAME54P20A", 1024, 256 },
{ 0x01, "SAME54P19A", 512, 192 },
{ 0x02, "SAME54N20A", 1024, 256 },
{ 0x03, "SAME54N19A", 512, 192 },
};
/* 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. */
struct samd_family {
uint8_t processor;
uint8_t family;
uint8_t series;
const struct samd_part *parts;
size_t num_parts;
};
/* Known SAMD families */
static const struct samd_family samd_families[] = {
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_D, SAMD_SERIES_51,
samd51_parts, ARRAY_SIZE(samd51_parts) },
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_51,
same51_parts, ARRAY_SIZE(same51_parts) },
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_53,
same53_parts, ARRAY_SIZE(same53_parts) },
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54,
same54_parts, ARRAY_SIZE(same54_parts) },
};
struct samd_info {
const struct samd_params *par;
uint32_t page_size;
int num_pages;
int sector_size;
int prot_block_size;
bool probed;
struct target *target;
};
/**
* Gives the family structure to specific device id.
* @param id The id of the device.
* @return On failure NULL, otherwise a pointer to the structure.
*/
static const struct samd_family *samd_find_family(uint32_t id)
{
uint8_t processor = SAMD_GET_PROCESSOR(id);
uint8_t family = SAMD_GET_FAMILY(id);
uint8_t series = SAMD_GET_SERIES(id);
for (unsigned i = 0; i < ARRAY_SIZE(samd_families); i++) {
if (samd_families[i].processor == processor &&
samd_families[i].series == series &&
samd_families[i].family == family)
return &samd_families[i];
}
return NULL;
}
/**
* Gives the part structure to specific device id.
* @param id The id of the device.
* @return On failure NULL, otherwise a pointer to the structure.
*/
static const struct samd_part *samd_find_part(uint32_t id)
{
uint8_t devsel = SAMD_GET_DEVSEL(id);
const struct samd_family *family = samd_find_family(id);
if (family == NULL)
return NULL;
for (unsigned i = 0; i < family->num_parts; i++) {
if (family->parts[i].id == devsel)
return &family->parts[i];
}
return NULL;
}
static int same5_protect_check(struct flash_bank *bank)
{
int res, prot_block;
uint32_t lock;
res = target_read_u32(bank->target,
SAMD_NVMCTRL + SAME5_NVMCTRL_LOCK, &lock);
if (res != ERROR_OK)
return res;
/* Lock bits are active-low */
for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++)
bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block));
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 same5_probe(struct flash_bank *bank)
{
uint32_t id;
int res;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
const struct samd_part *part;
if (chip->probed)
return ERROR_OK;
res = target_read_u32(bank->target, SAMD_DSU + SAMD_DSU_DID, &id);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read Device ID register");
return res;
}
part = samd_find_part(id);
if (part == NULL) {
LOG_ERROR("Couldn't find part corresponding to DID %08" PRIx32, id);
return ERROR_FAIL;
}
bank->size = part->flash_kb * 1024;
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("SAM: bank size doesn't match NVM parameters. "
"Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages",
part->flash_kb, chip->num_pages, chip->page_size);
}
/* Erase granularity = 1 block = 16 pages */
chip->sector_size = chip->page_size * SAME5_PAGES_PER_BLOCK;
/* Allocate the sector table */
bank->num_sectors = chip->num_pages / SAME5_PAGES_PER_BLOCK;
bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors);
if (!bank->sectors)
return ERROR_FAIL;
/* 16 protection blocks per device */
chip->prot_block_size = bank->size / SAME5_NUM_PROT_BLOCKS;
/* Allocate the table of protection blocks */
bank->num_prot_blocks = SAME5_NUM_PROT_BLOCKS;
bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks);
if (!bank->prot_blocks)
return ERROR_FAIL;
same5_protect_check(bank);
/* Done */
chip->probed = true;
LOG_INFO("SAM MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name,
part->flash_kb, part->ram_kb);
return ERROR_OK;
}
static int same5_wait_and_check_error(struct target *target)
{
int ret, ret2;
int rep_cnt = 100;
uint16_t intflag;
do {
ret = target_read_u16(target,
SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, &intflag);
if (ret == ERROR_OK && intflag & SAME5_NVMCTRL_INTFLAG_DONE)
break;
} while (--rep_cnt);
if (ret != ERROR_OK) {
LOG_ERROR("Can't read NVM INTFLAG");
return ret;
}
#if 0
if (intflag & SAME5_NVMCTRL_INTFLAG_ECCSE)
LOG_ERROR("SAM: ECC Single Error");
if (intflag & SAME5_NVMCTRL_INTFLAG_ECCDE) {
LOG_ERROR("SAM: ECC Double Error");
ret = ERROR_FLASH_OPERATION_FAILED;
}
#endif
if (intflag & SAME5_NVMCTRL_INTFLAG_ADDRE) {
LOG_ERROR("SAM: Addr Error");
ret = ERROR_FLASH_OPERATION_FAILED;
}
if (intflag & SAME5_NVMCTRL_INTFLAG_NVME) {
LOG_ERROR("SAM: NVM Error");
ret = ERROR_FLASH_OPERATION_FAILED;
}
if (intflag & SAME5_NVMCTRL_INTFLAG_LOCKE) {
LOG_ERROR("SAM: NVM lock error");
ret = ERROR_FLASH_PROTECTED;
}
if (intflag & SAME5_NVMCTRL_INTFLAG_PROGE) {
LOG_ERROR("SAM: NVM programming error");
ret = ERROR_FLASH_OPER_UNSUPPORTED;
}
/* Clear the error conditions by writing a one to them */
ret2 = target_write_u16(target,
SAMD_NVMCTRL + SAME5_NVMCTRL_INTFLAG, intflag);
if (ret2 != ERROR_OK)
LOG_ERROR("Can't clear NVM error conditions");
return ret;
}
static int same5_issue_nvmctrl_command(struct target *target, uint16_t cmd)
{
int res;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Issue the NVM command */
/* 32-bit write is used to ensure atomic operation on ST-Link */
res = target_write_u32(target,
SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLB, SAMD_NVM_CMD(cmd));
if (res != ERROR_OK)
return res;
/* Check to see if the NVM command resulted in an error condition. */
return same5_wait_and_check_error(target);
}
/**
* Erases a flash block or page at the given address.
* @param target Pointer to the target structure.
* @param address The address of the row.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int same5_erase_block(struct target *target, uint32_t address)
{
int res;
/* Set an address contained in the block to be erased */
res = target_write_u32(target,
SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR, address);
/* Issue the Erase Block command. */
if (res == ERROR_OK)
res = same5_issue_nvmctrl_command(target,
address == SAMD_USER_ROW ? SAME5_NVM_CMD_EP : SAME5_NVM_CMD_EB);
if (res != ERROR_OK) {
LOG_ERROR("Failed to erase block containing %08" PRIx32, address);
return ERROR_FAIL;
}
return ERROR_OK;
}
static int same5_pre_write_check(struct target *target)
{
int res;
uint32_t nvm_ctrla;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
/* Check if manual write mode is set */
res = target_read_u32(target, SAMD_NVMCTRL + SAME5_NVMCTRL_CTRLA, &nvm_ctrla);
if (res != ERROR_OK)
return res;
if (nvm_ctrla & SAME5_NVMCTRL_CTRLA_WMODE_MASK) {
LOG_ERROR("The flash controller must be in manual write mode. Issue 'reset init' and retry.");
return ERROR_FAIL;
}
return res;
}
/**
* Modify the contents of the User Row in Flash. The User Row itself
* has a size of one page and contains a combination of "fuses" and
* calibration data. Bits which have a value of zero in the mask will
* not be changed.
* @param target Pointer to the target structure.
* @param data Pointer to the value to write.
* @param mask Pointer to bitmask, 0 -> value stays untouched.
* @param offset Offset in user row where new data will be applied.
* @param count Size of buffer and mask in bytes.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int same5_modify_user_row_masked(struct target *target,
const uint8_t *data, const uint8_t *mask,
uint32_t offset, uint32_t count)
{
int res;
/* Retrieve the MCU's flash 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;
}
/* Make sure the size is sane. */
assert(page_size <= SAMD_PAGE_SIZE_MAX &&
page_size >= offset + count);
uint8_t buf[SAMD_PAGE_SIZE_MAX];
/* Read the user row (comprising one page) by words. */
res = target_read_memory(target, SAMD_USER_ROW, 4, page_size / 4, buf);
if (res != ERROR_OK)
return res;
/* Modify buffer and check if really changed */
bool changed = false;
uint32_t i;
for (i = 0; i < count; i++) {
uint8_t old_b = buf[offset+i];
uint8_t new_b = (old_b & ~mask[i]) | (data[i] & mask[i]);
buf[offset+i] = new_b;
if (old_b != new_b)
changed = true;
}
if (!changed)
return ERROR_OK;
res = same5_pre_write_check(target);
if (res != ERROR_OK)
return res;
res = same5_erase_block(target, SAMD_USER_ROW);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't erase user row");
return res;
}
/* Write the page buffer back out to the target using Write Quad Word */
for (i = 0; i < page_size; i += 4 * 4) {
res = target_write_memory(target, SAMD_USER_ROW + i, 4, 4, buf + i);
if (res != ERROR_OK)
return res;
/* Trigger flash write */
res = same5_issue_nvmctrl_command(target, SAME5_NVM_CMD_WQW);
if (res != ERROR_OK)
return res;
}
return res;
}
/**
* Modifies the user row register to the given value.
* @param target Pointer to the target structure.
* @param value The value to write.
* @param startb The bit-offset by which the given value is shifted.
* @param endb The bit-offset of the last bit in value to write.
* @return On success ERROR_OK, on failure an errorcode.
*/
static int same5_modify_user_row(struct target *target, uint32_t value,
uint8_t startb, uint8_t endb)
{
uint8_t buf_val[8] = { 0 };
uint8_t buf_mask[8] = { 0 };
assert(startb <= endb && endb < 64);
buf_set_u32(buf_val, startb, endb + 1 - startb, value);
buf_set_u32(buf_mask, startb, endb + 1 - startb, 0xffffffff);
return same5_modify_user_row_masked(target,
buf_val, buf_mask, 0, 8);
}
static int same5_protect(struct flash_bank *bank, int set, int first_prot_bl, int last_prot_bl)
{
int res = ERROR_OK;
int prot_block;
/* 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;
}
for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) {
if (set != bank->prot_blocks[prot_block].is_protected) {
/* Load an address that is within this protection block (we use offset 0) */
res = target_write_u32(bank->target,
SAMD_NVMCTRL + SAME5_NVMCTRL_ADDR,
bank->prot_blocks[prot_block].offset);
if (res != ERROR_OK)
goto exit;
/* Tell the controller to lock that block */
res = same5_issue_nvmctrl_command(bank->target,
set ? SAME5_NVM_CMD_LR : SAME5_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.
* A '1' means unlocked and a '0' means locked. */
const uint8_t lock[4] = { 0, 0, 0, 0 };
const uint8_t unlock[4] = { 0xff, 0xff, 0xff, 0xff };
uint8_t mask[4] = { 0, 0, 0, 0 };
buf_set_u32(mask, first_prot_bl, last_prot_bl + 1 - first_prot_bl, 0xffffffff);
res = same5_modify_user_row_masked(bank->target,
set ? lock : unlock, mask, 8, 4);
if (res != ERROR_OK)
LOG_WARNING("SAM: protect settings were not made persistent!");
res = ERROR_OK;
exit:
same5_protect_check(bank);
return res;
}
static int same5_erase(struct flash_bank *bank, int first_sect, int last_sect)
{
int res, s;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (!chip->probed)
return ERROR_FLASH_BANK_NOT_PROBED;
/* For each sector to be erased */
for (s = first_sect; s <= last_sect; s++) {
res = same5_erase_block(bank->target, bank->sectors[s].offset);
if (res != ERROR_OK) {
LOG_ERROR("SAM: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset);
return res;
}
}
return ERROR_OK;
}
static int same5_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
int res;
uint32_t address;
uint32_t pg_offset;
uint32_t nb;
uint32_t nw;
struct samd_info *chip = (struct samd_info *)bank->driver_priv;
uint8_t *pb = NULL;
res = same5_pre_write_check(bank->target);
if (res != ERROR_OK)
return res;
if (!chip->probed)
return ERROR_FLASH_BANK_NOT_PROBED;
res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_PBC);
if (res != ERROR_OK) {
LOG_ERROR("%s: %d", __func__, __LINE__);
return res;
}
while (count) {
nb = chip->page_size - offset % chip->page_size;
if (count < nb)
nb = count;
address = bank->base + offset;
pg_offset = offset % chip->page_size;
if (offset % 4 || (offset + nb) % 4) {
/* Either start or end of write is not word aligned */
if (!pb) {
pb = malloc(chip->page_size);
if (!pb)
return ERROR_FAIL;
}
/* Set temporary page buffer to 0xff and overwrite the relevant part */
memset(pb, 0xff, chip->page_size);
memcpy(pb + pg_offset, buffer, nb);
/* Align start address to a word boundary */
address -= offset % 4;
pg_offset -= offset % 4;
assert(pg_offset % 4 == 0);
/* Extend length to whole words */
nw = (nb + offset % 4 + 3) / 4;
assert(pg_offset + 4 * nw <= chip->page_size);
/* Now we have original data extended by 0xff bytes
* to the nearest word boundary on both start and end */
res = target_write_memory(bank->target, address, 4, nw, pb + pg_offset);
} else {
assert(nb % 4 == 0);
nw = nb / 4;
assert(pg_offset + 4 * nw <= chip->page_size);
/* Word aligned data, use direct write from buffer */
res = target_write_memory(bank->target, address, 4, nw, buffer);
}
if (res != ERROR_OK) {
LOG_ERROR("%s: %d", __func__, __LINE__);
goto free_pb;
}
res = same5_issue_nvmctrl_command(bank->target, SAME5_NVM_CMD_WP);
if (res != ERROR_OK) {
LOG_ERROR("%s: write failed at address 0x%08" PRIx32, __func__, address);
goto free_pb;
}
/* We're done with the page contents */
count -= nb;
offset += nb;
buffer += nb;
}
free_pb:
if (pb)
free(pb);
return res;
}
FLASH_BANK_COMMAND_HANDLER(same5_flash_bank_command)
{
if (bank->base != SAMD_FLASH) {
LOG_ERROR("Address 0x%08" TARGET_PRIxADDR " invalid bank address (try "
"0x%08" PRIx32 "[same5] )", bank->base, SAMD_FLASH);
return ERROR_FAIL;
}
struct samd_info *chip;
chip = calloc(1, sizeof(*chip));
if (!chip) {
LOG_ERROR("No memory for flash bank chip info");
return ERROR_FAIL;
}
chip->target = bank->target;
chip->probed = false;
bank->driver_priv = chip;
return ERROR_OK;
}
COMMAND_HANDLER(same5_handle_chip_erase_command)
{
struct target *target = get_current_target(CMD_CTX);
if (!target)
return ERROR_FAIL;
/* Enable access to the DSU by disabling the write protect bit */
target_write_u32(target, SAME5_PAC, (1<<16) | (1<<5) | (1<<1));
/* intentionally without error checking - not accessible on secured chip */
/* Tell the DSU to perform a full chip erase. It takes about 240ms to
* perform the erase. */
int res = target_write_u8(target, SAMD_DSU + SAMD_DSU_CTRL_EXT, (1<<4));
if (res == ERROR_OK)
command_print(CMD_CTX, "chip erase started");
else
command_print(CMD_CTX, "write to DSU CTRL failed");
return res;
}
COMMAND_HANDLER(same5_handle_userpage_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (!target)
return ERROR_FAIL;
if (CMD_ARGC > 2) {
command_print(CMD_CTX, "Too much Arguments given.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (CMD_ARGC >= 1) {
uint64_t mask = NVMUSERROW_SAM_E5_D5_MASK;
uint64_t value = strtoull(CMD_ARGV[0], NULL, 0);
if (CMD_ARGC == 2) {
uint64_t mask_temp = strtoull(CMD_ARGV[1], NULL, 0);
mask &= mask_temp;
}
uint8_t val_buf[8], mask_buf[8];
target_buffer_set_u64(target, val_buf, value);
target_buffer_set_u64(target, mask_buf, mask);
res = same5_modify_user_row_masked(target,
val_buf, mask_buf, 0, sizeof(val_buf));
}
uint8_t buffer[8];
int res2 = target_read_memory(target, SAMD_USER_ROW, 4, 2, buffer);
if (res2 == ERROR_OK) {
uint64_t value = target_buffer_get_u64(target, buffer);
command_print(CMD_CTX, "USER PAGE: 0x%016"PRIX64, value);
} else {
LOG_ERROR("USER PAGE could not be read.");
}
if (CMD_ARGC >= 1)
return res;
else
return res2;
}
COMMAND_HANDLER(same5_handle_bootloader_command)
{
int res = ERROR_OK;
struct target *target = get_current_target(CMD_CTX);
if (!target)
return ERROR_FAIL;
if (CMD_ARGC >= 1) {
unsigned long size = strtoul(CMD_ARGV[0], NULL, 0);
uint32_t code = (size + 8191) / 8192;
if (code > 15) {
command_print(CMD_CTX, "Invalid bootloader size. Please "
"see datasheet for a list valid sizes.");
return ERROR_COMMAND_SYNTAX_ERROR;
}
res = same5_modify_user_row(target, 15 - code, 26, 29);
}
uint32_t val;
int res2 = target_read_u32(target, SAMD_USER_ROW, &val);
if (res2 == ERROR_OK) {
uint32_t code = (val >> 26) & 0xf; /* grab size code */
uint32_t size = (15 - code) * 8192;
command_print(CMD_CTX, "Bootloader protected in the first %"
PRIu32 " bytes", size);
}
if (CMD_ARGC >= 1)
return res;
else
return res2;
}
COMMAND_HANDLER(samd_handle_reset_deassert)
{
struct target *target = get_current_target(CMD_CTX);
int res = ERROR_OK;
enum reset_types jtag_reset_config = jtag_get_reset_config();
if (!target)
return ERROR_FAIL;
/* If the target has been unresponsive before, try to re-establish
* communication now - CPU is held in reset by DSU, DAP is working */
if (!target_was_examined(target))
target_examine_one(target);
target_poll(target);
/* In case of sysresetreq, debug retains state set in cortex_m_assert_reset()
* so we just release reset held by DSU
*
* n_RESET (srst) clears the DP, so reenable debug and set vector catch here
*
* After vectreset DSU release is not needed however makes no harm
*/
if (target->reset_halt && (jtag_reset_config & RESET_HAS_SRST)) {
res = target_write_u32(target, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN);
if (res == ERROR_OK)
res = target_write_u32(target, DCB_DEMCR,
TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET);
/* do not return on error here, releasing DSU reset is more important */
}
/* clear CPU Reset Phase Extension bit */
int res2 = target_write_u8(target, SAMD_DSU + SAMD_DSU_STATUSA, (1<<1));
if (res2 != ERROR_OK)
return res2;
return res;
}
static const struct command_registration same5_exec_command_handlers[] = {
{
.name = "dsu_reset_deassert",
.handler = samd_handle_reset_deassert,
.mode = COMMAND_EXEC,
.help = "Deasert internal reset held by DSU."
},
{
.name = "chip-erase",
.handler = same5_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 = "bootloader",
.usage = "[size_in_bytes]",
.handler = same5_handle_bootloader_command,
.mode = COMMAND_EXEC,
.help = "Show or set the bootloader protection size, stored in the User Row. "
"Changes are stored immediately but take affect after the MCU is "
"reset.",
},
{
.name = "userpage",
.usage = "[value] [mask]",
.handler = same5_handle_userpage_command,
.mode = COMMAND_EXEC,
.help = "Show or set the first 64-bit part of user page "
"located at address 0x804000. Use the optional mask argument "
"to prevent changes at positions where the bitvalue is zero. "
"For security reasons the reserved-bits are masked out "
"in background and therefore cannot be changed.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration same5_command_handlers[] = {
{
.name = "atsame5",
.mode = COMMAND_ANY,
.help = "atsame5 flash command group",
.usage = "",
.chain = same5_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver atsame5_flash = {
.name = "atsame5",
.commands = same5_command_handlers,
.flash_bank_command = same5_flash_bank_command,
.erase = same5_erase,
.protect = same5_protect,
.write = same5_write,
.read = default_flash_read,
.probe = same5_probe,
.auto_probe = same5_probe,
.erase_check = default_flash_blank_check,
.protect_check = same5_protect_check,
.free_driver_priv = default_flash_free_driver_priv,
};

View File

@ -233,12 +233,6 @@ static int avrf_erase(struct flash_bank *bank, int first, int last)
return avr_jtagprg_leaveprogmode(avr); return avr_jtagprg_leaveprogmode(avr);
} }
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
{
LOG_INFO("%s", __func__);
return ERROR_OK;
}
static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{ {
struct target *target = bank->target; struct target *target = bank->target;
@ -338,7 +332,7 @@ static int avrf_probe(struct flash_bank *bank)
bank->sectors[i].offset = i * avr_info->flash_page_size; bank->sectors[i].offset = i * avr_info->flash_page_size;
bank->sectors[i].size = avr_info->flash_page_size; bank->sectors[i].size = avr_info->flash_page_size;
bank->sectors[i].is_erased = -1; bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1; bank->sectors[i].is_protected = -1;
} }
avrf_info->probed = 1; avrf_info->probed = 1;
@ -360,12 +354,6 @@ static int avrf_auto_probe(struct flash_bank *bank)
return avrf_probe(bank); return avrf_probe(bank);
} }
static int avrf_protect_check(struct flash_bank *bank)
{
LOG_INFO("%s", __func__);
return ERROR_OK;
}
static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct target *target = bank->target; struct target *target = bank->target;
@ -479,13 +467,11 @@ struct flash_driver avr_flash = {
.commands = avrf_command_handlers, .commands = avrf_command_handlers,
.flash_bank_command = avrf_flash_bank_command, .flash_bank_command = avrf_flash_bank_command,
.erase = avrf_erase, .erase = avrf_erase,
.protect = avrf_protect,
.write = avrf_write, .write = avrf_write,
.read = default_flash_read, .read = default_flash_read,
.probe = avrf_probe, .probe = avrf_probe,
.auto_probe = avrf_auto_probe, .auto_probe = avrf_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = avrf_protect_check,
.info = avrf_info, .info = avrf_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -312,12 +312,6 @@ static int cc26xx_erase(struct flash_bank *bank, int first, int last)
return retval; return retval;
} }
static int cc26xx_protect(struct flash_bank *bank, int set, int first,
int last)
{
return ERROR_OK;
}
static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
@ -497,22 +491,12 @@ static int cc26xx_auto_probe(struct flash_bank *bank)
int retval = ERROR_OK; int retval = ERROR_OK;
if (bank->bank_number != 0) {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (!cc26xx_bank->probed) if (!cc26xx_bank->probed)
retval = cc26xx_probe(bank); retval = cc26xx_probe(bank);
return retval; return retval;
} }
static int cc26xx_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size) static int cc26xx_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_bank *cc26xx_bank = bank->driver_priv;
@ -555,13 +539,11 @@ struct flash_driver cc26xx_flash = {
.name = "cc26xx", .name = "cc26xx",
.flash_bank_command = cc26xx_flash_bank_command, .flash_bank_command = cc26xx_flash_bank_command,
.erase = cc26xx_erase, .erase = cc26xx_erase,
.protect = cc26xx_protect,
.write = cc26xx_write, .write = cc26xx_write,
.read = default_flash_read, .read = default_flash_read,
.probe = cc26xx_probe, .probe = cc26xx_probe,
.auto_probe = cc26xx_auto_probe, .auto_probe = cc26xx_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = cc26xx_protect_check,
.info = cc26xx_info, .info = cc26xx_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -173,12 +173,6 @@ static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
return retval; return retval;
} }
static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
int last)
{
return ERROR_OK;
}
static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer, static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
@ -436,18 +430,10 @@ static int cc3220sf_probe(struct flash_bank *bank)
uint32_t base; uint32_t base;
uint32_t size; uint32_t size;
int num_sectors; int num_sectors;
int bank_id;
bank_id = bank->bank_number; base = FLASH_BASE_ADDR;
size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
if (0 == bank_id) { num_sectors = FLASH_NUM_SECTORS;
base = FLASH_BASE_ADDR;
size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
num_sectors = FLASH_NUM_SECTORS;
} else {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (NULL != bank->sectors) { if (NULL != bank->sectors) {
free(bank->sectors); free(bank->sectors);
@ -485,22 +471,12 @@ static int cc3220sf_auto_probe(struct flash_bank *bank)
int retval = ERROR_OK; int retval = ERROR_OK;
if (0 != bank->bank_number) {
/* Invalid bank number somehow */
return ERROR_FAIL;
}
if (!cc3220sf_bank->probed) if (!cc3220sf_bank->probed)
retval = cc3220sf_probe(bank); retval = cc3220sf_probe(bank);
return retval; return retval;
} }
static int cc3220sf_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size) static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
int printed; int printed;
@ -517,13 +493,11 @@ struct flash_driver cc3220sf_flash = {
.name = "cc3220sf", .name = "cc3220sf",
.flash_bank_command = cc3220sf_flash_bank_command, .flash_bank_command = cc3220sf_flash_bank_command,
.erase = cc3220sf_erase, .erase = cc3220sf_erase,
.protect = cc3220sf_protect,
.write = cc3220sf_write, .write = cc3220sf_write,
.read = default_flash_read, .read = default_flash_read,
.probe = cc3220sf_probe, .probe = cc3220sf_probe,
.auto_probe = cc3220sf_auto_probe, .auto_probe = cc3220sf_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = cc3220sf_protect_check,
.info = cc3220sf_info, .info = cc3220sf_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -1098,11 +1098,6 @@ static int cfi_protect(struct flash_bank *bank, int set, int first, int last)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
} }
if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
LOG_ERROR("Invalid sector range");
return ERROR_FLASH_SECTOR_INVALID;
}
if (cfi_info->qry[0] != 'Q') if (cfi_info->qry[0] != 'Q')
return ERROR_FLASH_BANK_NOT_PROBED; return ERROR_FLASH_BANK_NOT_PROBED;

View File

@ -68,6 +68,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
/* force "set" to 0/1 */ /* force "set" to 0/1 */
set = !!set; set = !!set;
if (bank->driver->protect == NULL) {
LOG_ERROR("Flash protection is not supported.");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
/* DANGER! /* DANGER!
* *
* We must not use any cached information about protection state!!!! * We must not use any cached information about protection state!!!!
@ -319,8 +324,8 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
for (j = 0; j < bank->sectors[i].size; j += buffer_size) { for (j = 0; j < bank->sectors[i].size; j += buffer_size) {
uint32_t chunk; uint32_t chunk;
chunk = buffer_size; chunk = buffer_size;
if (chunk > (j - bank->sectors[i].size)) if (chunk > (bank->sectors[i].size - j))
chunk = (j - bank->sectors[i].size); chunk = (bank->sectors[i].size - j);
retval = target_read_memory(target, retval = target_read_memory(target,
bank->base + bank->sectors[i].offset + j, bank->base + bank->sectors[i].offset + j,

View File

@ -109,6 +109,8 @@ struct flash_driver {
/** /**
* Bank/sector protection routine (target-specific). * Bank/sector protection routine (target-specific).
* *
* If protection is not implemented, set method to NULL
*
* When called, the driver should enable/disable protection * When called, the driver should enable/disable protection
* for MINIMUM the range covered by first..last sectors * for MINIMUM the range covered by first..last sectors
* inclusive. Some chips have alignment requirements will * inclusive. Some chips have alignment requirements will
@ -178,6 +180,8 @@ struct flash_driver {
* flash_sector_s::is_protected field for each of the flash * flash_sector_s::is_protected field for each of the flash
* bank's sectors. * bank's sectors.
* *
* If protection is not implemented, set method to NULL
*
* @param bank - the bank to check * @param bank - the bank to check
* @returns ERROR_OK if successful; otherwise, an error code. * @returns ERROR_OK if successful; otherwise, an error code.
*/ */

View File

@ -29,6 +29,7 @@ extern struct flash_driver at91sam4l_flash;
extern struct flash_driver at91sam7_flash; extern struct flash_driver at91sam7_flash;
extern struct flash_driver at91samd_flash; extern struct flash_driver at91samd_flash;
extern struct flash_driver ath79_flash; extern struct flash_driver ath79_flash;
extern struct flash_driver atsame5_flash;
extern struct flash_driver atsamv_flash; extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash; extern struct flash_driver avr_flash;
extern struct flash_driver bluenrgx_flash; extern struct flash_driver bluenrgx_flash;
@ -78,6 +79,7 @@ extern struct flash_driver str9x_flash;
extern struct flash_driver str9xpec_flash; extern struct flash_driver str9xpec_flash;
extern struct flash_driver tms470_flash; extern struct flash_driver tms470_flash;
extern struct flash_driver virtual_flash; extern struct flash_driver virtual_flash;
extern struct flash_driver w600_flash;
extern struct flash_driver xcf_flash; extern struct flash_driver xcf_flash;
extern struct flash_driver xmc1xxx_flash; extern struct flash_driver xmc1xxx_flash;
extern struct flash_driver xmc4xxx_flash; extern struct flash_driver xmc4xxx_flash;
@ -96,6 +98,7 @@ static struct flash_driver *flash_drivers[] = {
&at91sam7_flash, &at91sam7_flash,
&at91samd_flash, &at91samd_flash,
&ath79_flash, &ath79_flash,
&atsame5_flash,
&atsamv_flash, &atsamv_flash,
&avr_flash, &avr_flash,
&bluenrgx_flash, &bluenrgx_flash,
@ -148,6 +151,7 @@ static struct flash_driver *flash_drivers[] = {
&xcf_flash, &xcf_flash,
&xmc1xxx_flash, &xmc1xxx_flash,
&xmc4xxx_flash, &xmc4xxx_flash,
&w600_flash,
NULL, NULL,
}; };

View File

@ -429,7 +429,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
*/ */
int ret = 0; int ret = 0;
uint32_t status = 0; uint32_t status = 0;
addr += bank->base;
LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr);
ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);

View File

@ -104,9 +104,12 @@ struct esirisc_flash_bank {
uint32_t wait_states; uint32_t wait_states;
}; };
static const struct command_registration esirisc_flash_command_handlers[];
FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command) FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
{ {
struct esirisc_flash_bank *esirisc_info; struct esirisc_flash_bank *esirisc_info;
struct command *esirisc_cmd;
if (CMD_ARGC < 9) if (CMD_ARGC < 9)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
@ -119,6 +122,10 @@ FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
bank->driver_priv = esirisc_info; bank->driver_priv = esirisc_info;
/* register commands using existing esirisc context */
esirisc_cmd = command_find_in_context(CMD_CTX, "esirisc");
register_commands(CMD_CTX, esirisc_cmd, esirisc_flash_command_handlers);
return ERROR_OK; return ERROR_OK;
} }
@ -149,7 +156,7 @@ static int esirisc_flash_disable_protect(struct flash_bank *bank)
if (!(control & CONTROL_WP)) if (!(control & CONTROL_WP))
return ERROR_OK; return ERROR_OK;
esirisc_flash_unlock(bank); (void)esirisc_flash_unlock(bank);
control &= ~CONTROL_WP; control &= ~CONTROL_WP;
@ -168,7 +175,7 @@ static int esirisc_flash_enable_protect(struct flash_bank *bank)
if (control & CONTROL_WP) if (control & CONTROL_WP)
return ERROR_OK; return ERROR_OK;
esirisc_flash_unlock(bank); (void)esirisc_flash_unlock(bank);
control |= CONTROL_WP; control |= CONTROL_WP;
@ -254,7 +261,7 @@ static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
if (target->state != TARGET_HALTED) if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank); (void)esirisc_flash_disable_protect(bank);
for (int page = first; page < last; ++page) { for (int page = first; page < last; ++page) {
uint32_t address = page * PAGE_SIZE; uint32_t address = page * PAGE_SIZE;
@ -268,7 +275,7 @@ static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
} }
} }
esirisc_flash_enable_protect(bank); (void)esirisc_flash_enable_protect(bank);
return retval; return retval;
} }
@ -282,7 +289,7 @@ static int esirisc_flash_mass_erase(struct flash_bank *bank)
if (target->state != TARGET_HALTED) if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank); (void)esirisc_flash_disable_protect(bank);
target_write_u32(target, esirisc_info->cfg + ADDRESS, 0); target_write_u32(target, esirisc_info->cfg + ADDRESS, 0);
@ -290,7 +297,7 @@ static int esirisc_flash_mass_erase(struct flash_bank *bank)
if (retval != ERROR_OK) if (retval != ERROR_OK)
LOG_ERROR("%s: failed to mass erase", bank->name); LOG_ERROR("%s: failed to mass erase", bank->name);
esirisc_flash_enable_protect(bank); (void)esirisc_flash_enable_protect(bank);
return retval; return retval;
} }
@ -308,32 +315,17 @@ static int esirisc_flash_ref_erase(struct flash_bank *bank)
if (target->state != TARGET_HALTED) if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank); (void)esirisc_flash_disable_protect(bank);
retval = esirisc_flash_control(bank, CONTROL_ERC); retval = esirisc_flash_control(bank, CONTROL_ERC);
if (retval != ERROR_OK) if (retval != ERROR_OK)
LOG_ERROR("%s: failed to erase reference cell", bank->name); LOG_ERROR("%s: failed to erase reference cell", bank->name);
esirisc_flash_enable_protect(bank); (void)esirisc_flash_enable_protect(bank);
return retval; return retval;
} }
static int esirisc_flash_protect(struct flash_bank *bank, int set, int first, int last)
{
struct target *target = bank->target;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
if (set)
esirisc_flash_enable_protect(bank);
else
esirisc_flash_disable_protect(bank);
return ERROR_OK;
}
static int esirisc_flash_fill_pb(struct flash_bank *bank, static int esirisc_flash_fill_pb(struct flash_bank *bank,
const uint8_t *buffer, uint32_t count) const uint8_t *buffer, uint32_t count)
{ {
@ -375,7 +367,7 @@ static int esirisc_flash_write(struct flash_bank *bank,
if (target->state != TARGET_HALTED) if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED; return ERROR_TARGET_NOT_HALTED;
esirisc_flash_disable_protect(bank); (void)esirisc_flash_disable_protect(bank);
/* /*
* The address register is auto-incremented based on the contents of * The address register is auto-incremented based on the contents of
@ -406,7 +398,7 @@ static int esirisc_flash_write(struct flash_bank *bank,
count -= num_bytes; count -= num_bytes;
} }
esirisc_flash_enable_protect(bank); (void)esirisc_flash_enable_protect(bank);
return retval; return retval;
} }
@ -432,11 +424,11 @@ static int esirisc_flash_init(struct flash_bank *bank)
uint32_t value; uint32_t value;
int retval; int retval;
esirisc_flash_disable_protect(bank); (void)esirisc_flash_disable_protect(bank);
/* initialize timing registers */ /* initialize timing registers */
value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) | value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH))
TIMING0_R(esirisc_info->wait_states); | TIMING0_R(esirisc_info->wait_states);
LOG_DEBUG("TIMING0: 0x%" PRIx32, value); LOG_DEBUG("TIMING0: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING0, value); target_write_u32(target, esirisc_info->cfg + TIMING0, value);
@ -446,9 +438,9 @@ static int esirisc_flash_init(struct flash_bank *bank)
LOG_DEBUG("TIMING1: 0x%" PRIx32, value); LOG_DEBUG("TIMING1: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING1, value); target_write_u32(target, esirisc_info->cfg + TIMING1, value);
value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) | value = TIMING2_T(esirisc_flash_num_cycles(bank, 10))
TIMING2_H(esirisc_flash_num_cycles(bank, 100)) | | TIMING2_H(esirisc_flash_num_cycles(bank, 100))
TIMING2_P(esirisc_flash_num_cycles(bank, TPROG)); | TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
LOG_DEBUG("TIMING2: 0x%" PRIx32, value); LOG_DEBUG("TIMING2: 0x%" PRIx32, value);
target_write_u32(target, esirisc_info->cfg + TIMING2, value); target_write_u32(target, esirisc_info->cfg + TIMING2, value);
@ -458,7 +450,7 @@ static int esirisc_flash_init(struct flash_bank *bank)
if (retval != ERROR_OK) if (retval != ERROR_OK)
LOG_ERROR("%s: failed to recall trim code", bank->name); LOG_ERROR("%s: failed to recall trim code", bank->name);
esirisc_flash_enable_protect(bank); (void)esirisc_flash_enable_protect(bank);
return retval; return retval;
} }
@ -475,13 +467,6 @@ static int esirisc_flash_probe(struct flash_bank *bank)
bank->num_sectors = bank->size / PAGE_SIZE; bank->num_sectors = bank->size / PAGE_SIZE;
bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors); bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors);
/*
* Register write protection is enforced using a single protection
* block for the entire bank. This is as good as it gets.
*/
bank->num_prot_blocks = 1;
bank->prot_blocks = alloc_block_array(0, bank->size, bank->num_prot_blocks);
retval = esirisc_flash_init(bank); retval = esirisc_flash_init(bank);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("%s: failed to initialize bank", bank->name); LOG_ERROR("%s: failed to initialize bank", bank->name);
@ -503,23 +488,6 @@ static int esirisc_flash_auto_probe(struct flash_bank *bank)
return esirisc_flash_probe(bank); return esirisc_flash_probe(bank);
} }
static int esirisc_flash_protect_check(struct flash_bank *bank)
{
struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t control;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
/* single protection block (also see: esirisc_flash_probe()) */
bank->prot_blocks[0].is_protected = !!(control & CONTROL_WP);
return ERROR_OK;
}
static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size) static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct esirisc_flash_bank *esirisc_info = bank->driver_priv; struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
@ -579,14 +547,14 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =
.name = "mass_erase", .name = "mass_erase",
.handler = handle_esirisc_flash_mass_erase_command, .handler = handle_esirisc_flash_mass_erase_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.help = "erases all pages in data memory", .help = "erase all pages in data memory",
.usage = "bank_id", .usage = "bank_id",
}, },
{ {
.name = "ref_erase", .name = "ref_erase",
.handler = handle_esirisc_flash_ref_erase_command, .handler = handle_esirisc_flash_ref_erase_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.help = "erases reference cell (uncommon)", .help = "erase reference cell (uncommon)",
.usage = "bank_id", .usage = "bank_id",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
@ -594,9 +562,9 @@ static const struct command_registration esirisc_flash_exec_command_handlers[] =
static const struct command_registration esirisc_flash_command_handlers[] = { static const struct command_registration esirisc_flash_command_handlers[] = {
{ {
.name = "esirisc_flash", .name = "flash",
.mode = COMMAND_ANY, .mode = COMMAND_EXEC,
.help = "eSi-RISC flash command group", .help = "eSi-TSMC Flash command group",
.usage = "", .usage = "",
.chain = esirisc_flash_exec_command_handlers, .chain = esirisc_flash_exec_command_handlers,
}, },
@ -605,17 +573,15 @@ static const struct command_registration esirisc_flash_command_handlers[] = {
struct flash_driver esirisc_flash = { struct flash_driver esirisc_flash = {
.name = "esirisc", .name = "esirisc",
.commands = esirisc_flash_command_handlers,
.usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target " .usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target "
"cfg_address clock_hz wait_states", "cfg_address clock_hz wait_states",
.flash_bank_command = esirisc_flash_bank_command, .flash_bank_command = esirisc_flash_bank_command,
.erase = esirisc_flash_erase, .erase = esirisc_flash_erase,
.protect = esirisc_flash_protect,
.write = esirisc_flash_write, .write = esirisc_flash_write,
.read = default_flash_read, .read = default_flash_read,
.probe = esirisc_flash_probe, .probe = esirisc_flash_probe,
.auto_probe = esirisc_flash_auto_probe, .auto_probe = esirisc_flash_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = esirisc_flash_protect_check,
.info = esirisc_flash_info, .info = esirisc_flash_info,
.free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -85,12 +85,6 @@ static int faux_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK; return ERROR_OK;
} }
static int faux_protect(struct flash_bank *bank, int set, int first, int last)
{
LOG_USER("set protection sector %d to %d to %s", first, last, set ? "on" : "off");
return ERROR_OK;
}
static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{ {
struct faux_flash_bank *info = bank->driver_priv; struct faux_flash_bank *info = bank->driver_priv;
@ -98,11 +92,6 @@ static int faux_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o
return ERROR_OK; return ERROR_OK;
} }
static int faux_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int faux_info(struct flash_bank *bank, char *buf, int buf_size) static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
snprintf(buf, buf_size, "faux flash driver"); snprintf(buf, buf_size, "faux flash driver");
@ -129,13 +118,11 @@ struct flash_driver faux_flash = {
.commands = faux_command_handlers, .commands = faux_command_handlers,
.flash_bank_command = faux_flash_bank_command, .flash_bank_command = faux_flash_bank_command,
.erase = faux_erase, .erase = faux_erase,
.protect = faux_protect,
.write = faux_write, .write = faux_write,
.read = default_flash_read, .read = default_flash_read,
.probe = faux_probe, .probe = faux_probe,
.auto_probe = faux_probe, .auto_probe = faux_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = faux_protect_check,
.info = faux_info, .info = faux_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -391,6 +391,9 @@ static int fespi_erase(struct flash_bank *bank, int first, int last)
} }
} }
if (fespi_info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
if (fespi_write_reg(bank, FESPI_REG_TXCTRL, FESPI_TXWM(1)) != ERROR_OK) if (fespi_write_reg(bank, FESPI_REG_TXCTRL, FESPI_TXWM(1)) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
retval = fespi_txwm_wait(bank); retval = fespi_txwm_wait(bank);
@ -795,7 +798,9 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer,
data_wa_size /= 2; data_wa_size /= 2;
} }
page_size = fespi_info->dev->pagesize; /* If no valid page_size, use reasonable default. */
page_size = fespi_info->dev->pagesize ?
fespi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
fespi_txwm_wait(bank); fespi_txwm_wait(bank);
@ -911,6 +916,7 @@ static int fespi_probe(struct flash_bank *bank)
uint32_t id = 0; /* silence uninitialized warning */ uint32_t id = 0; /* silence uninitialized warning */
const struct fespi_target *target_device; const struct fespi_target *target_device;
int retval; int retval;
uint32_t sectorsize;
if (fespi_info->probed) if (fespi_info->probed)
free(bank->sectors); free(bank->sectors);
@ -972,9 +978,17 @@ static int fespi_probe(struct flash_bank *bank)
/* Set correct size value */ /* Set correct size value */
bank->size = fespi_info->dev->size_in_bytes; bank->size = fespi_info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = fespi_info->dev->sectorsize ?
fespi_info->dev->sectorsize : fespi_info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = bank->num_sectors = fespi_info->dev->size_in_bytes / sectorsize;
fespi_info->dev->size_in_bytes / fespi_info->dev->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) { if (sectors == NULL) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
@ -982,8 +996,8 @@ static int fespi_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * fespi_info->dev->sectorsize; sectors[sector].offset = sector * sectorsize;
sectors[sector].size = fespi_info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1; sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0; sectors[sector].is_protected = 0;
} }

View File

@ -537,11 +537,6 @@ static int fm4_auto_probe(struct flash_bank *bank)
return fm4_probe(bank); return fm4_probe(bank);
} }
static int fm4_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size) static int fm4_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct fm4_flash_bank *fm4_bank = bank->driver_priv; struct fm4_flash_bank *fm4_bank = bank->driver_priv;
@ -714,7 +709,6 @@ struct flash_driver fm4_flash = {
.info = fm4_get_info_command, .info = fm4_get_info_command,
.probe = fm4_probe, .probe = fm4_probe,
.auto_probe = fm4_auto_probe, .auto_probe = fm4_auto_probe,
.protect_check = fm4_protect_check,
.read = default_flash_read, .read = default_flash_read,
.erase = fm4_flash_erase, .erase = fm4_flash_erase,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,

View File

@ -166,7 +166,7 @@ static int jtagspi_probe(struct flash_bank *bank)
struct jtagspi_flash_bank *info = bank->driver_priv; struct jtagspi_flash_bank *info = bank->driver_priv;
struct flash_sector *sectors; struct flash_sector *sectors;
uint8_t in_buf[3]; uint8_t in_buf[3];
uint32_t id; uint32_t id, sectorsize;
if (info->probed) if (info->probed)
free(bank->sectors); free(bank->sectors);
@ -199,10 +199,17 @@ static int jtagspi_probe(struct flash_bank *bank)
/* Set correct size value */ /* Set correct size value */
bank->size = info->dev->size_in_bytes; bank->size = info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = info->dev->sectorsize ?
info->dev->sectorsize : info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = bank->num_sectors = info->dev->size_in_bytes / sectorsize;
info->dev->size_in_bytes / info->dev->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) { if (sectors == NULL) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
@ -210,8 +217,8 @@ static int jtagspi_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * info->dev->sectorsize; sectors[sector].offset = sector * sectorsize;
sectors[sector].size = info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1; sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0; sectors[sector].is_protected = 0;
} }
@ -269,6 +276,9 @@ static int jtagspi_bulk_erase(struct flash_bank *bank)
int retval; int retval;
int64_t t0 = timeval_ms(); int64_t t0 = timeval_ms();
if (info->dev->chip_erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
retval = jtagspi_write_enable(bank); retval = jtagspi_write_enable(bank);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -328,6 +338,9 @@ static int jtagspi_erase(struct flash_bank *bank, int first, int last)
LOG_WARNING("Bulk flash erase failed. Falling back to sector erase."); LOG_WARNING("Bulk flash erase failed. Falling back to sector erase.");
} }
if (info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
for (sector = first; sector <= last; sector++) { for (sector = first; sector <= last; sector++) {
retval = jtagspi_sector_erase(bank, sector); retval = jtagspi_sector_erase(bank, sector);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
@ -343,21 +356,11 @@ static int jtagspi_protect(struct flash_bank *bank, int set, int first, int last
{ {
int sector; int sector;
if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
LOG_ERROR("Flash sector invalid");
return ERROR_FLASH_SECTOR_INVALID;
}
for (sector = first; sector <= last; sector++) for (sector = first; sector <= last; sector++)
bank->sectors[sector].is_protected = set; bank->sectors[sector].is_protected = set;
return ERROR_OK; return ERROR_OK;
} }
static int jtagspi_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) static int jtagspi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{ {
struct jtagspi_flash_bank *info = bank->driver_priv; struct jtagspi_flash_bank *info = bank->driver_priv;
@ -386,16 +389,19 @@ static int jtagspi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_
{ {
struct jtagspi_flash_bank *info = bank->driver_priv; struct jtagspi_flash_bank *info = bank->driver_priv;
int retval; int retval;
uint32_t n; uint32_t n, pagesize;
if (!(info->probed)) { if (!(info->probed)) {
LOG_ERROR("Flash bank not yet probed."); LOG_ERROR("Flash bank not yet probed.");
return ERROR_FLASH_BANK_NOT_PROBED; return ERROR_FLASH_BANK_NOT_PROBED;
} }
for (n = 0; n < count; n += info->dev->pagesize) { /* if no write pagesize, use reasonable default */
pagesize = info->dev->pagesize ? info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
for (n = 0; n < count; n += pagesize) {
retval = jtagspi_page_write(bank, buffer + n, offset + n, retval = jtagspi_page_write(bank, buffer + n, offset + n,
MIN(count - n, info->dev->pagesize)); MIN(count - n, pagesize));
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("page write error"); LOG_ERROR("page write error");
return retval; return retval;
@ -431,7 +437,6 @@ struct flash_driver jtagspi_flash = {
.probe = jtagspi_probe, .probe = jtagspi_probe,
.auto_probe = jtagspi_probe, .auto_probe = jtagspi_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = jtagspi_protect_check,
.info = jtagspi_info, .info = jtagspi_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -1035,7 +1035,7 @@ static int kinetis_disable_wdog_algo(struct target *target, size_t code_size, co
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
armv7m_info.core_mode = ARM_MODE_THREAD; armv7m_info.core_mode = ARM_MODE_THREAD;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN); init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
buf_set_u32(reg_params[0].value, 0, 32, wdog_base); buf_set_u32(reg_params[0].value, 0, 32, wdog_base);
retval = target_run_algorithm(target, 0, NULL, 1, reg_params, retval = target_run_algorithm(target, 0, NULL, 1, reg_params,

View File

@ -12,6 +12,9 @@
* by Nemui Trinomius * * by Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp * * nemuisan_kawausogasuki@live.jp *
* * * *
* LPC8N04/HNS31xx support Copyright (C) 2018 *
* by Jean-Christian de Rivaz jcdr [at] innodelec [dot] ch *
* *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
@ -38,7 +41,7 @@
/** /**
* @file * @file
* flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x and LPC2xxx devices. * flash programming support for NXP LPC8xx,LPC1xxx,LPC4xxx,LP5410x,LPC2xxx and NHS31xx devices.
* *
* @todo Provide a way to update CCLK after declaring the flash bank. The value which is correct after chip reset will * @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). * rarely still work right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
@ -77,6 +80,9 @@
* lpc800: * lpc800:
* - 810 | 1 | 2 (tested with LPC810/LPC811/LPC812) * - 810 | 1 | 2 (tested with LPC810/LPC811/LPC812)
* - 822 | 4 (tested with LPC824) * - 822 | 4 (tested with LPC824)
* - 8N04
* - NHS31xx (tested with NHS3100)
* - 844 | 5 (tested with LPC845)
* *
* lpc1100: * lpc1100:
* - 11xx * - 11xx
@ -111,6 +117,8 @@
* - 408x * - 408x
* - 81x * - 81x
* - 82x * - 82x
* - 8N04
* - NHS31xx
*/ */
/* Part IDs for autodetection */ /* Part IDs for autodetection */
@ -257,6 +265,20 @@
#define LPC824_201 0x00008241 #define LPC824_201 0x00008241
#define LPC824_201_1 0x00008242 #define LPC824_201_1 0x00008242
#define LPC8N04 0x00008A04
#define NHS3100 0x4e310020
#define NHS3152 0x4e315220
#define NHS3153 0x4e315320 /* Only specified in Rev.1 of the datasheet */
#define LPC844_201 0x00008441
#define LPC844_201_1 0x00008442
#define LPC844_201_2 0x00008444
#define LPC845_301 0x00008451
#define LPC845_301_1 0x00008452
#define LPC845_301_2 0x00008453
#define LPC845_301_3 0x00008454
#define IAP_CODE_LEN 0x34 #define IAP_CODE_LEN 0x34
#define LPC11xx_REG_SECTORS 24 #define LPC11xx_REG_SECTORS 24
@ -282,6 +304,7 @@ struct lpc2000_flash_bank {
int checksum_vector; int checksum_vector;
uint32_t iap_max_stack; uint32_t iap_max_stack;
uint32_t lpc4300_bank; uint32_t lpc4300_bank;
uint32_t iap_entry_alternative;
bool probed; bool probed;
}; };
@ -526,10 +549,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
case 16 * 1024: case 16 * 1024:
bank->num_sectors = 16; bank->num_sectors = 16;
break; break;
case 30 * 1024:
lpc2000_info->cmd51_max_buffer = 1024; /* For LPC8N04 and NHS31xx, have 8kB of SRAM */
bank->num_sectors = 30; /* There have only 30kB of writable Flash out of 32kB */
break;
case 32 * 1024: case 32 * 1024:
lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */
bank->num_sectors = 32; bank->num_sectors = 32;
break; break;
case 64 * 1024:
lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */
bank->num_sectors = 64;
break;
default: default:
LOG_ERROR("BUG: unknown bank->size encountered"); LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1); exit(-1);
@ -741,6 +772,9 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo
exit(-1); exit(-1);
} }
if (lpc2000_info->iap_entry_alternative != 0x0)
iap_entry_point = lpc2000_info->iap_entry_alternative;
struct mem_param mem_params[2]; struct mem_param mem_params[2];
/* command parameter table */ /* command parameter table */
@ -938,6 +972,8 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0) if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
lpc2000_info->calc_checksum = 1; lpc2000_info->calc_checksum = 1;
} }
if (CMD_ARGC >= 10 && !lpc2000_info->iap_entry_alternative)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], lpc2000_info->iap_entry_alternative);
return ERROR_OK; return ERROR_OK;
} }
@ -1018,12 +1054,6 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
return retval; return retval;
} }
static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
{
/* can't protect/unprotect on the lpc2000 */
return ERROR_OK;
}
static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{ {
struct target *target = bank->target; struct target *target = bank->target;
@ -1458,6 +1488,25 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank)
bank->size = 32 * 1024; bank->size = 32 * 1024;
break; break;
case LPC8N04:
case NHS3100:
case NHS3152:
case NHS3153:
lpc2000_info->variant = lpc800;
bank->size = 30 * 1024;
break;
case LPC844_201:
case LPC844_201_1:
case LPC844_201_2:
case LPC845_301:
case LPC845_301_1:
case LPC845_301_2:
case LPC845_301_3:
lpc2000_info->variant = lpc800;
bank->size = 64 * 1024;
break;
default: default:
LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id);
exit(-1); exit(-1);
@ -1501,12 +1550,6 @@ static int lpc2000_erase_check(struct flash_bank *bank)
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1); return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
} }
static int lpc2000_protect_check(struct flash_bank *bank)
{
/* sectors are always protected */
return ERROR_OK;
}
static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size) static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
@ -1571,13 +1614,11 @@ struct flash_driver lpc2000_flash = {
.commands = lpc2000_command_handlers, .commands = lpc2000_command_handlers,
.flash_bank_command = lpc2000_flash_bank_command, .flash_bank_command = lpc2000_flash_bank_command,
.erase = lpc2000_erase, .erase = lpc2000_erase,
.protect = lpc2000_protect,
.write = lpc2000_write, .write = lpc2000_write,
.read = default_flash_read, .read = default_flash_read,
.probe = lpc2000_probe, .probe = lpc2000_probe,
.auto_probe = lpc2000_probe, .auto_probe = lpc2000_probe,
.erase_check = lpc2000_erase_check, .erase_check = lpc2000_erase_check,
.protect_check = lpc2000_protect_check,
.info = get_lpc2000_info, .info = get_lpc2000_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -167,6 +167,7 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
return ERROR_OK; return ERROR_OK;
} }
/* TODO: Revisit! Is it impossible to read protection status? */
static int lpc288x_protect_check(struct flash_bank *bank) static int lpc288x_protect_check(struct flash_bank *bank)
{ {
return ERROR_OK; return ERROR_OK;
@ -231,17 +232,6 @@ static uint32_t lpc288x_system_ready(struct flash_bank *bank)
return ERROR_OK; return ERROR_OK;
} }
static int lpc288x_erase_check(struct flash_bank *bank)
{
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
if (status != ERROR_OK) {
LOG_INFO("Processor not halted/not probed");
return status;
}
return ERROR_OK;
}
static int lpc288x_erase(struct flash_bank *bank, int first, int last) static int lpc288x_erase(struct flash_bank *bank, int first, int last)
{ {
uint32_t status; uint32_t status;
@ -431,7 +421,7 @@ struct flash_driver lpc288x_flash = {
.read = default_flash_read, .read = default_flash_read,
.probe = lpc288x_probe, .probe = lpc288x_probe,
.auto_probe = lpc288x_probe, .auto_probe = lpc288x_probe,
.erase_check = lpc288x_erase_check, .erase_check = default_flash_blank_check,
.protect_check = lpc288x_protect_check, .protect_check = lpc288x_protect_check,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -1035,18 +1035,13 @@ static int lpc2900_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK; return ERROR_OK;
} }
static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last) /* lpc2900_protect command is not supported.
{ * "Protection" in LPC2900 terms is handled transparently. Sectors will
/* This command is not supported. * automatically be unprotected as needed.
* "Protection" in LPC2900 terms is handled transparently. Sectors will * Instead we use the concept of sector security. A secured sector is shown
* automatically be unprotected as needed. * as "protected" in OpenOCD. Sector security is a permanent feature, and
* Instead we use the concept of sector security. A secured sector is shown * cannot be disabled once activated.
* as "protected" in OpenOCD. Sector security is a permanent feature, and */
* cannot be disabled once activated.
*/
return ERROR_OK;
}
/** /**
* Write data to flash. * Write data to flash.
@ -1591,7 +1586,6 @@ struct flash_driver lpc2900_flash = {
.commands = lpc2900_command_handlers, .commands = lpc2900_command_handlers,
.flash_bank_command = lpc2900_flash_bank_command, .flash_bank_command = lpc2900_flash_bank_command,
.erase = lpc2900_erase, .erase = lpc2900_erase,
.protect = lpc2900_protect,
.write = lpc2900_write, .write = lpc2900_write,
.read = default_flash_read, .read = default_flash_read,
.probe = lpc2900_probe, .probe = lpc2900_probe,

View File

@ -387,6 +387,9 @@ static int lpcspifi_bulk_erase(struct flash_bank *bank)
uint32_t value; uint32_t value;
int retval = ERROR_OK; int retval = ERROR_OK;
if (lpcspifi_info->dev->chip_erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
retval = lpcspifi_set_sw_mode(bank); retval = lpcspifi_set_sw_mode(bank);
if (retval == ERROR_OK) if (retval == ERROR_OK)
@ -460,6 +463,9 @@ static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
} }
if (lpcspifi_info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
retval = lpcspifi_set_hw_mode(bank); retval = lpcspifi_set_hw_mode(bank);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
@ -613,7 +619,9 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
} }
} }
page_size = lpcspifi_info->dev->pagesize; /* if no valid page_size, use reasonable default */
page_size = lpcspifi_info->dev->pagesize ?
lpcspifi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
retval = lpcspifi_set_hw_mode(bank); retval = lpcspifi_set_hw_mode(bank);
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -839,6 +847,7 @@ static int lpcspifi_probe(struct flash_bank *bank)
struct flash_sector *sectors; struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */ uint32_t id = 0; /* silence uninitialized warning */
int retval; int retval;
uint32_t sectorsize;
/* If we've already probed, we should be fine to skip this time. */ /* If we've already probed, we should be fine to skip this time. */
if (lpcspifi_info->probed) if (lpcspifi_info->probed)
@ -876,10 +885,17 @@ static int lpcspifi_probe(struct flash_bank *bank)
/* Set correct size value */ /* Set correct size value */
bank->size = lpcspifi_info->dev->size_in_bytes; bank->size = lpcspifi_info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = lpcspifi_info->dev->sectorsize ?
lpcspifi_info->dev->sectorsize : lpcspifi_info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = bank->num_sectors = lpcspifi_info->dev->size_in_bytes / sectorsize;
lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) { if (sectors == NULL) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
@ -887,8 +903,8 @@ static int lpcspifi_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize; sectors[sector].offset = sector * sectorsize;
sectors[sector].size = lpcspifi_info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1; sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0; sectors[sector].is_protected = 0;
} }

View File

@ -86,11 +86,6 @@ FLASH_BANK_COMMAND_HANDLER(mdr_flash_bank_command)
return ERROR_OK; return ERROR_OK;
} }
static int mdr_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int mdr_mass_erase(struct flash_bank *bank) static int mdr_mass_erase(struct flash_bank *bank)
{ {
struct target *target = bank->target; struct target *target = bank->target;
@ -217,11 +212,6 @@ reset_pg_and_lock:
return retval; return retval;
} }
static int mdr_protect(struct flash_bank *bank, int set, int first, int last)
{
return ERROR_OK;
}
static int mdr_write_block(struct flash_bank *bank, const uint8_t *buffer, static int mdr_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
@ -625,13 +615,11 @@ struct flash_driver mdr_flash = {
"<type>: 0 for main memory, 1 for info memory", "<type>: 0 for main memory, 1 for info memory",
.flash_bank_command = mdr_flash_bank_command, .flash_bank_command = mdr_flash_bank_command,
.erase = mdr_erase, .erase = mdr_erase,
.protect = mdr_protect,
.write = mdr_write, .write = mdr_write,
.read = mdr_read, .read = mdr_read,
.probe = mdr_probe, .probe = mdr_probe,
.auto_probe = mdr_auto_probe, .auto_probe = mdr_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = mdr_protect_check,
.info = get_mdr_info, .info = get_mdr_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -503,6 +503,9 @@ static int mrvlqspi_bulk_erase(struct flash_bank *bank)
int retval; int retval;
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
if (mrvlqspi_info->dev->chip_erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
/* Set flash write enable */ /* Set flash write enable */
retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE); retval = mrvlqspi_set_write_status(bank, WRITE_ENABLE);
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -570,6 +573,9 @@ static int mrvlqspi_flash_erase(struct flash_bank *bank, int first, int last)
" Falling back to sector-by-sector erase."); " Falling back to sector-by-sector erase.");
} }
if (mrvlqspi_info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
for (sector = first; sector <= last; sector++) { for (sector = first; sector <= last; sector++) {
retval = mrvlqspi_block_erase(bank, retval = mrvlqspi_block_erase(bank,
sector * mrvlqspi_info->dev->sectorsize); sector * mrvlqspi_info->dev->sectorsize);
@ -619,7 +625,9 @@ static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
} }
} }
page_size = mrvlqspi_info->dev->pagesize; /* if no valid page_size, use reasonable default */
page_size = mrvlqspi_info->dev->pagesize ?
mrvlqspi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
/* See contrib/loaders/flash/mrvlqspi.S for src */ /* See contrib/loaders/flash/mrvlqspi.S for src */
static const uint8_t mrvlqspi_flash_write_code[] = { static const uint8_t mrvlqspi_flash_write_code[] = {
@ -826,6 +834,7 @@ static int mrvlqspi_probe(struct flash_bank *bank)
uint32_t id = 0; uint32_t id = 0;
int retval; int retval;
struct flash_sector *sectors; struct flash_sector *sectors;
uint32_t sectorsize;
/* If we've already probed, we should be fine to skip this time. */ /* If we've already probed, we should be fine to skip this time. */
if (mrvlqspi_info->probed) if (mrvlqspi_info->probed)
@ -859,12 +868,20 @@ static int mrvlqspi_probe(struct flash_bank *bank)
LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32, LOG_INFO("Found flash device \'%s\' ID 0x%08" PRIx32,
mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id); mrvlqspi_info->dev->name, mrvlqspi_info->dev->device_id);
/* Set correct size value */ /* Set correct size value */
bank->size = mrvlqspi_info->dev->size_in_bytes; bank->size = mrvlqspi_info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = mrvlqspi_info->dev->sectorsize ?
mrvlqspi_info->dev->sectorsize : mrvlqspi_info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = mrvlqspi_info->dev->size_in_bytes / bank->num_sectors = mrvlqspi_info->dev->size_in_bytes / sectorsize;
mrvlqspi_info->dev->sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) { if (sectors == NULL) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
@ -872,9 +889,8 @@ static int mrvlqspi_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sectors[sector].offset = sector * sectorsize;
sector * mrvlqspi_info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].size = mrvlqspi_info->dev->sectorsize;
sectors[sector].is_erased = -1; sectors[sector].is_erased = -1;
sectors[sector].is_protected = 0; sectors[sector].is_protected = 0;
} }
@ -899,12 +915,6 @@ static int mrvlqspi_flash_erase_check(struct flash_bank *bank)
return ERROR_OK; 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) int mrvlqspi_get_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv; struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
@ -947,13 +957,11 @@ struct flash_driver mrvlqspi_flash = {
.name = "mrvlqspi", .name = "mrvlqspi",
.flash_bank_command = mrvlqspi_flash_bank_command, .flash_bank_command = mrvlqspi_flash_bank_command,
.erase = mrvlqspi_flash_erase, .erase = mrvlqspi_flash_erase,
.protect = NULL,
.write = mrvlqspi_flash_write, .write = mrvlqspi_flash_write,
.read = mrvlqspi_flash_read, .read = mrvlqspi_flash_read,
.probe = mrvlqspi_probe, .probe = mrvlqspi_probe,
.auto_probe = mrvlqspi_auto_probe, .auto_probe = mrvlqspi_auto_probe,
.erase_check = mrvlqspi_flash_erase_check, .erase_check = mrvlqspi_flash_erase_check,
.protect_check = mrvlqspi_protect_check,
.info = mrvlqspi_get_info, .info = mrvlqspi_get_info,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -655,12 +655,6 @@ static int msp432_erase(struct flash_bank *bank, int first, int last)
return retval; return retval;
} }
static int msp432_protect(struct flash_bank *bank, int set, int first,
int last)
{
return ERROR_OK;
}
static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, static int msp432_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
@ -985,11 +979,6 @@ static int msp432_auto_probe(struct flash_bank *bank)
return retval; return retval;
} }
static int msp432_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int msp432_info(struct flash_bank *bank, char *buf, int buf_size) static int msp432_info(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_bank *msp432_bank = bank->driver_priv;
@ -1091,13 +1080,11 @@ struct flash_driver msp432_flash = {
.commands = msp432_command_handlers, .commands = msp432_command_handlers,
.flash_bank_command = msp432_flash_bank_command, .flash_bank_command = msp432_flash_bank_command,
.erase = msp432_erase, .erase = msp432_erase,
.protect = msp432_protect,
.write = msp432_write, .write = msp432_write,
.read = default_flash_read, .read = default_flash_read,
.probe = msp432_probe, .probe = msp432_probe,
.auto_probe = msp432_auto_probe, .auto_probe = msp432_auto_probe,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,
.protect_check = msp432_protect_check,
.info = msp432_info, .info = msp432_info,
.free_driver_priv = msp432_flash_free_driver_priv, .free_driver_priv = msp432_flash_free_driver_priv,
}; };

View File

@ -211,6 +211,7 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
/* nRF52832 Devices */ /* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512), NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
NRF5_DEVICE_DEF(0x00E3, "52832", "CIAA", "B0", 512),
/* nRF52840 Devices */ /* nRF52840 Devices */
NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024), NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
@ -248,7 +249,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
{ {
uint32_t ready; uint32_t ready;
int res; int res;
int timeout_ms = 200; int timeout_ms = 340;
int64_t ts_start = timeval_ms(); int64_t ts_start = timeval_ms();
do { do {

View File

@ -30,16 +30,6 @@ struct ocl_priv {
unsigned int bufalign; unsigned int bufalign;
}; };
static int ocl_erase_check(struct flash_bank *bank)
{
return ERROR_OK;
}
static int ocl_protect_check(struct flash_bank *bank)
{
return ERROR_OK;
}
/* flash_bank ocl 0 0 0 0 <target#> */ /* flash_bank ocl 0 0 0 0 <target#> */
FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command) FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command)
{ {
@ -111,11 +101,6 @@ static int ocl_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK; return ERROR_OK;
} }
static int ocl_protect(struct flash_bank *bank, int set, int first, int last)
{
return ERROR_OK;
}
static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
{ {
struct ocl_priv *ocl = bank->driver_priv; struct ocl_priv *ocl = bank->driver_priv;
@ -333,12 +318,10 @@ struct flash_driver ocl_flash = {
.name = "ocl", .name = "ocl",
.flash_bank_command = ocl_flash_bank_command, .flash_bank_command = ocl_flash_bank_command,
.erase = ocl_erase, .erase = ocl_erase,
.protect = ocl_protect,
.write = ocl_write, .write = ocl_write,
.read = default_flash_read, .read = default_flash_read,
.probe = ocl_probe, .probe = ocl_probe,
.erase_check = ocl_erase_check, .erase_check = default_flash_blank_check,
.protect_check = ocl_protect_check,
.auto_probe = ocl_auto_probe, .auto_probe = ocl_auto_probe,
.free_driver_priv = default_flash_free_driver_priv, .free_driver_priv = default_flash_free_driver_priv,
}; };

View File

@ -753,16 +753,6 @@ static int psoc5lp_nvl_write(struct flash_bank *bank,
return ERROR_OK; return ERROR_OK;
} }
static int psoc5lp_nvl_protect_check(struct flash_bank *bank)
{
int i;
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = -1;
return ERROR_OK;
}
static int psoc5lp_nvl_get_info_command(struct flash_bank *bank, static int psoc5lp_nvl_get_info_command(struct flash_bank *bank,
char *buf, int buf_size) char *buf, int buf_size)
{ {
@ -855,7 +845,6 @@ struct flash_driver psoc5lp_nvl_flash = {
.info = psoc5lp_nvl_get_info_command, .info = psoc5lp_nvl_get_info_command,
.probe = psoc5lp_nvl_probe, .probe = psoc5lp_nvl_probe,
.auto_probe = psoc5lp_nvl_auto_probe, .auto_probe = psoc5lp_nvl_auto_probe,
.protect_check = psoc5lp_nvl_protect_check,
.read = psoc5lp_nvl_read, .read = psoc5lp_nvl_read,
.erase = psoc5lp_nvl_erase, .erase = psoc5lp_nvl_erase,
.erase_check = psoc5lp_nvl_erase_check, .erase_check = psoc5lp_nvl_erase_check,
@ -945,16 +934,6 @@ static int psoc5lp_eeprom_write(struct flash_bank *bank,
return ERROR_OK; return ERROR_OK;
} }
static int psoc5lp_eeprom_protect_check(struct flash_bank *bank)
{
int i;
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_protected = -1;
return ERROR_OK;
}
static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, char *buf, int buf_size) static int psoc5lp_eeprom_get_info_command(struct flash_bank *bank, char *buf, int buf_size)
{ {
struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv; struct psoc5lp_eeprom_flash_bank *psoc_eeprom_bank = bank->driver_priv;
@ -1064,7 +1043,6 @@ struct flash_driver psoc5lp_eeprom_flash = {
.info = psoc5lp_eeprom_get_info_command, .info = psoc5lp_eeprom_get_info_command,
.probe = psoc5lp_eeprom_probe, .probe = psoc5lp_eeprom_probe,
.auto_probe = psoc5lp_eeprom_auto_probe, .auto_probe = psoc5lp_eeprom_auto_probe,
.protect_check = psoc5lp_eeprom_protect_check,
.read = default_flash_read, .read = default_flash_read,
.erase = psoc5lp_eeprom_erase, .erase = psoc5lp_eeprom_erase,
.erase_check = default_flash_blank_check, .erase_check = default_flash_blank_check,

View File

@ -1,4 +1,7 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2018 by Andreas Bolsch *
* andreas.bolsch@mni.thm.de *
* *
* Copyright (C) 2012 by George Harris * * Copyright (C) 2012 by George Harris *
* george@luminairecoffee.com * * george@luminairecoffee.com *
* * * *
@ -30,58 +33,118 @@
/* Shared table of known SPI flash devices for SPI-based flash drivers. Taken /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken
* from device datasheets and Linux SPI flash drivers. */ * from device datasheets and Linux SPI flash drivers. */
const struct flash_device flash_devices[] = { const struct flash_device flash_devices[] = {
/* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id,
FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), * pagesize, sectorsize, size_in_bytes */
FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000),
FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000),
FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000),
FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), FLASH_ID("st m25p40", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000),
FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000),
FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), FLASH_ID("st m25p16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000),
FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), FLASH_ID("st m25p32", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000),
FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), FLASH_ID("st m25p64", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000),
FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), FLASH_ID("st m25p128", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000),
FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), FLASH_ID("st m45pe10", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), FLASH_ID("st m45pe20", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), FLASH_ID("st m45pe40", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), FLASH_ID("st m45pe80", 0x03, 0x00, 0x02, 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), FLASH_ID("sp s25fl004", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000),
FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), FLASH_ID("sp s25fl008", 0x03, 0x08, 0x02, 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000),
FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), FLASH_ID("sp s25fl016", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000),
FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), FLASH_ID("sp s25fl116k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000),
FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), FLASH_ID("sp s25fl032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000),
FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), FLASH_ID("sp s25fl132k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000),
FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), FLASH_ID("sp s25fl064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000),
FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), FLASH_ID("sp s25fl164k", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000),
FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), FLASH_ID("sp s25fl128s", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000),
FLASH_ID("cy s25fl256", 0xd8, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000), FLASH_ID("sp s25fl256s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000),
FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), FLASH_ID("sp s25fl512s", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00200201, 0x200, 0x40000, 0x4000000),
FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000),
FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000),
FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000),
FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000),
FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000),
FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000),
FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000),
FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000),
FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000),
FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25l4005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000),
FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), FLASH_ID("mac 25l8005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000),
FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), FLASH_ID("mac 25l1605", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000),
FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), FLASH_ID("mac 25l3205", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000),
FLASH_ID("issi is25lp128", 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), FLASH_ID("mac 25l6405", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000),
FLASH_ID("issi is25wp256d", 0xd8, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000), FLASH_ID("mac 25l12845", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001820c2, 0x100, 0x10000, 0x1000000),
FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("mac 25l25645", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001920c2, 0x100, 0x10000, 0x2000000),
FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25l51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a20c2, 0x100, 0x10000, 0x4000000),
FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25lm51245", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003a85c2, 0x100, 0x10000, 0x4000000),
FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), FLASH_ID("mac 25r512f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001028c2, 0x100, 0x10000, 0x10000),
FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), FLASH_ID("mac 25r1035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001128c2, 0x100, 0x10000, 0x20000),
FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), FLASH_ID("mac 25r2035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001228c2, 0x100, 0x10000, 0x40000),
FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25r4035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001328c2, 0x100, 0x10000, 0x80000),
FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25r8035f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001428c2, 0x100, 0x10000, 0x100000),
FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), FLASH_ID("mac 25r1635f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001528c2, 0x100, 0x10000, 0x200000),
FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000),
FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000),
FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000),
FLASH_ID("micron n25q256 3v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000),
FLASH_ID("micron n25q256 1.8v", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000),
FLASH_ID("micron mt25ql512", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0020ba20, 0x100, 0x10000, 0x4000000),
FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000),
FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000),
FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000),
FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */
FLASH_ID("win w25q32fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000),
FLASH_ID("win w25q32fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), /* QPI mode */
FLASH_ID("win w25q32jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001670ef, 0x100, 0x10000, 0x400000),
FLASH_ID("win w25q64fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000),
FLASH_ID("win w25q64fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001760ef, 0x100, 0x10000, 0x800000), /* QPI mode */
FLASH_ID("win w25q64jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001770ef, 0x100, 0x10000, 0x800000),
FLASH_ID("win w25q128fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000),
FLASH_ID("win w25q128fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001860ef, 0x100, 0x10000, 0x1000000), /* QPI mode */
FLASH_ID("win w25q128jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001870ef, 0x100, 0x10000, 0x1000000),
FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000),
FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */
FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000),
FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000),
FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000),
FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000),
FLASH_ID("gd gd25q40", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001340c8, 0x100, 0x1000, 0x80000),
FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000),
FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000),
FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000),
FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
FLASH_ID("issi is25lp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000),
FLASH_ID("issi is25wp128d", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018709d, 0x100, 0x10000, 0x1000000),
FLASH_ID("issi is25lp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019609d, 0x100, 0x10000, 0x2000000),
FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000),
FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000),
/* FRAM, no erase commands, no write page or sectors */
FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800),
FRAM_ID("fu mb85rs32v", 0x03, 0, 0x02, 0x00010204, 0x1000), /* exists ? */
FRAM_ID("fu mb85rs64v", 0x03, 0, 0x02, 0x00020304, 0x2000),
FRAM_ID("fu mb85rs128b", 0x03, 0, 0x02, 0x00090404, 0x4000),
FRAM_ID("fu mb85rs256b", 0x03, 0, 0x02, 0x00090504, 0x8000),
FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000),
FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000),
FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000),
FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x000821c2, 0x4000),
FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x000022c2, 0x8000),
FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x000822c2, 0x8000),
FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x000023c2, 0x10000),
FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x000024c2, 0x20000),
FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x000825c2, 0x40000),
FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x004026c2, 0x80000),
FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}; };

View File

@ -1,4 +1,7 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2018 by Andreas Bolsch *
* andreas.bolsch@mni.thm.de *
* *
* Copyright (C) 2012 by George Harris * * Copyright (C) 2012 by George Harris *
* george@luminairecoffee.com * * george@luminairecoffee.com *
* * * *
@ -22,40 +25,69 @@
#ifndef OPENOCD_FLASH_NOR_SPI_H #ifndef OPENOCD_FLASH_NOR_SPI_H
#define OPENOCD_FLASH_NOR_SPI_H #define OPENOCD_FLASH_NOR_SPI_H
#ifndef __ASSEMBLER__
/* data structure to maintain flash ids from different vendors */ /* data structure to maintain flash ids from different vendors */
struct flash_device { struct flash_device {
char *name; char *name;
uint8_t read_cmd;
uint8_t qread_cmd;
uint8_t pprog_cmd;
uint8_t erase_cmd; uint8_t erase_cmd;
uint8_t chip_erase_cmd; uint8_t chip_erase_cmd;
uint32_t device_id; uint32_t device_id;
uint32_t pagesize; uint32_t pagesize;
unsigned long sectorsize; uint32_t sectorsize;
unsigned long size_in_bytes; uint32_t size_in_bytes;
}; };
#define FLASH_ID(n, es, ces, id, psize, ssize, size) \ #define FLASH_ID(n, re, qr, pp, es, ces, id, psize, ssize, size) \
{ \ { \
.name = n, \ .name = n, \
.erase_cmd = es, \ .read_cmd = re, \
.chip_erase_cmd = ces, \ .qread_cmd = qr, \
.device_id = id, \ .pprog_cmd = pp, \
.pagesize = psize, \ .erase_cmd = es, \
.sectorsize = ssize, \ .chip_erase_cmd = ces, \
.size_in_bytes = size \ .device_id = id, \
.pagesize = psize, \
.sectorsize = ssize, \
.size_in_bytes = size, \
}
#define FRAM_ID(n, re, qr, pp, id, size) \
{ \
.name = n, \
.read_cmd = re, \
.qread_cmd = qr, \
.pprog_cmd = pp, \
.erase_cmd = 0x00, \
.chip_erase_cmd = 0x00, \
.device_id = id, \
.pagesize = 0, \
.sectorsize = 0, \
.size_in_bytes = size, \
} }
extern const struct flash_device flash_devices[]; extern const struct flash_device flash_devices[];
#endif
/* fields in SPI flash status register */ /* fields in SPI flash status register */
#define SPIFLASH_BSY_BIT 0x00000001 /* WIP Bit of SPI SR on SMI SR */ #define SPIFLASH_BSY 0
#define SPIFLASH_WE_BIT 0x00000002 /* WEL Bit of SPI SR on SMI SR */ #define SPIFLASH_BSY_BIT (1 << SPIFLASH_BSY) /* WIP Bit of SPI SR */
#define SPIFLASH_WE 1
#define SPIFLASH_WE_BIT (1 << SPIFLASH_WE) /* WEL Bit of SPI SR */
/* SPI Flash Commands */ /* SPI Flash Commands */
#define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */ #define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */
#define SPIFLASH_READ_MID 0xAF /* Read Flash Identification, multi-io */
#define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */ #define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */
#define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */ #define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */
#define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */
#define SPIFLASH_FAST_READ 0x0B /* Fast Read */ #define SPIFLASH_FAST_READ 0x0B /* Fast Read */
#define SPIFLASH_READ 0x03 /* Normal Read */ #define SPIFLASH_READ 0x03 /* Normal Read */
#define SPIFLASH_DEF_PAGESIZE 256 /* default for non-page-oriented devices (FRAMs) */
#endif /* OPENOCD_FLASH_NOR_SPI_H */ #endif /* OPENOCD_FLASH_NOR_SPI_H */

View File

@ -1355,6 +1355,7 @@ COMMAND_HANDLER(stellaris_handle_mass_erase_command)
COMMAND_HANDLER(stellaris_handle_recover_command) COMMAND_HANDLER(stellaris_handle_recover_command)
{ {
struct flash_bank *bank; struct flash_bank *bank;
struct arm *arm;
int retval; int retval;
if (CMD_ARGC != 0) if (CMD_ARGC != 0)
@ -1383,12 +1384,13 @@ COMMAND_HANDLER(stellaris_handle_recover_command)
} }
adapter_assert_reset(); adapter_assert_reset();
arm = target_to_arm(bank->target);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
retval = dap_to_swd(bank->target); retval = dap_to_swd(arm->dap);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto done; goto done;
retval = dap_to_jtag(bank->target); retval = dap_to_jtag(arm->dap);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto done; goto done;
} }

View File

@ -131,7 +131,7 @@ struct stm32x_flash_bank {
static int stm32x_mass_erase(struct flash_bank *bank); static int stm32x_mass_erase(struct flash_bank *bank);
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count); uint32_t address, uint32_t count);
/* flash bank stm32x <base> <size> 0 0 <target#> /* flash bank stm32x <base> <size> 0 0 <target#>
*/ */
@ -343,8 +343,7 @@ static int stm32x_write_options(struct flash_bank *bank)
target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
uint32_t offset = STM32_OB_RDP - bank->base; retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2);
retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2);
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
LOG_ERROR("working area required to erase options bytes"); LOG_ERROR("working area required to erase options bytes");
@ -443,8 +442,10 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
return retval; return retval;
retval = stm32x_erase_options(bank); retval = stm32x_erase_options(bank);
if (retval != ERROR_OK) if (retval != ERROR_OK) {
LOG_ERROR("stm32x failed to erase options");
return retval; return retval;
}
for (int i = first; i <= last; i++) { for (int i = first; i <= last; i++) {
if (set) if (set)
@ -457,14 +458,13 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
} }
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t address, uint32_t count)
{ {
struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target; struct target *target = bank->target;
uint32_t buffer_size = 16384; uint32_t buffer_size = 16384;
struct working_area *write_algorithm; struct working_area *write_algorithm;
struct working_area *source; struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[5]; struct reg_param reg_params[5];
struct armv7m_algorithm armv7m_info; struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK; int retval = ERROR_OK;
@ -599,7 +599,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
goto cleanup; goto cleanup;
/* try using a block write */ /* try using a block write */
retval = stm32x_write_block(bank, buffer, offset, words_remaining); retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining);
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* if block write failed (no sufficient working area), /* if block write failed (no sufficient working area),
@ -1227,12 +1227,12 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
return retval; return retval;
if (stm32x_erase_options(bank) != ERROR_OK) { if (stm32x_erase_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to unlock device"); command_print(CMD_CTX, "stm32x failed to erase options");
return ERROR_OK; return ERROR_OK;
} }
if (stm32x_write_options(bank) != ERROR_OK) { if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to lock device"); command_print(CMD_CTX, "stm32x failed to unlock device");
return ERROR_OK; return ERROR_OK;
} }
@ -1313,7 +1313,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
{ {
struct target *target = NULL; struct target *target = NULL;
struct stm32x_flash_bank *stm32x_info = NULL; struct stm32x_flash_bank *stm32x_info = NULL;
uint16_t optionbyte; uint8_t optionbyte;
uint16_t useropt;
if (CMD_ARGC < 2) if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_COMMAND_SYNTAX_ERROR;
@ -1342,6 +1343,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
/* start with current options */ /* start with current options */
optionbyte = stm32x_info->option_bytes.user; optionbyte = stm32x_info->option_bytes.user;
useropt = stm32x_info->option_bytes.data;
/* skip over flash bank */ /* skip over flash bank */
CMD_ARGC--; CMD_ARGC--;
@ -1360,6 +1362,13 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
optionbyte |= (1 << 2); optionbyte |= (1 << 2);
else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0) else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0)
optionbyte &= ~(1 << 2); optionbyte &= ~(1 << 2);
else if (strcmp("USEROPT", CMD_ARGV[0]) == 0) {
if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR;
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], useropt);
CMD_ARGC--;
CMD_ARGV++;
}
else if (stm32x_info->has_dual_banks) { else if (stm32x_info->has_dual_banks) {
if (strcmp("BOOT0", CMD_ARGV[0]) == 0) if (strcmp("BOOT0", CMD_ARGV[0]) == 0)
optionbyte |= (1 << 3); optionbyte |= (1 << 3);
@ -1379,6 +1388,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
} }
stm32x_info->option_bytes.user = optionbyte; stm32x_info->option_bytes.user = optionbyte;
stm32x_info->option_bytes.data = useropt;
if (stm32x_write_options(bank) != ERROR_OK) { if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to write options"); command_print(CMD_CTX, "stm32x failed to write options");
@ -1536,7 +1546,7 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "bank_id ('SWWDG'|'HWWDG') " .usage = "bank_id ('SWWDG'|'HWWDG') "
"('RSTSTNDBY'|'NORSTSTNDBY') " "('RSTSTNDBY'|'NORSTSTNDBY') "
"('RSTSTOP'|'NORSTSTOP')", "('RSTSTOP'|'NORSTSTOP') ('USEROPT' user_data)",
.help = "Replace bits in device option bytes.", .help = "Replace bits in device option bytes.",
}, },
{ {

View File

@ -33,6 +33,9 @@
* RM0394 (STM32L43x/44x/45x/46x) * RM0394 (STM32L43x/44x/45x/46x)
* http://www.st.com/resource/en/reference_manual/dm00151940.pdf * http://www.st.com/resource/en/reference_manual/dm00151940.pdf
* *
* RM0432 (STM32L4R/4Sxx)
* http://www.st.com/resource/en/reference_manual/dm00310109.pdf
*
* STM32L476RG Datasheet (for erase timing) * STM32L476RG Datasheet (for erase timing)
* http://www.st.com/resource/en/datasheet/stm32l476rg.pdf * http://www.st.com/resource/en/datasheet/stm32l476rg.pdf
* *
@ -43,6 +46,14 @@
* *
* RM0394 devices have a single bank only. * RM0394 devices have a single bank only.
* *
* RM0432 devices have single and dual bank operating modes.
* The FLASH size is 1Mbyte or 2Mbyte.
* Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode).
*
* Bank mode is controlled by two different bits in option bytes register.
* In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
* In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
*
*/ */
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */
@ -82,7 +93,7 @@
#define FLASH_BSY (1 << 16) #define FLASH_BSY (1 << 16)
/* Fast programming not used => related errors not used*/ /* Fast programming not used => related errors not used*/
#define FLASH_PGSERR (1 << 7) /* Programming sequence error */ #define FLASH_PGSERR (1 << 7) /* Programming sequence error */
#define FLASH_SIZERR (1 << 6) /* Size error */ #define FLASH_SIZERR (1 << 6) /* Size error */
#define FLASH_PGAERR (1 << 5) /* Programming alignment error */ #define FLASH_PGAERR (1 << 5) /* Programming alignment error */
#define FLASH_WRPERR (1 << 4) /* Write protection error */ #define FLASH_WRPERR (1 << 4) /* Write protection error */
#define FLASH_PROGERR (1 << 3) /* Programming error */ #define FLASH_PROGERR (1 << 3) /* Programming error */
@ -93,7 +104,8 @@
/* STM32_FLASH_OBR bit definitions (reading) */ /* STM32_FLASH_OBR bit definitions (reading) */
#define OPT_DUALBANK 21 /* dual flash bank only */ #define OPT_DBANK_LE_1M (1 << 21) /* dual bank for devices up to 1M flash */
#define OPT_DBANK_GE_2M (1 << 22) /* dual bank for devices with 2M flash */
/* register unlock keys */ /* register unlock keys */
@ -325,7 +337,7 @@ static int stm32l4_protect_check(struct flash_bank *bank)
bank->sectors[i].is_protected = 0; bank->sectors[i].is_protected = 0;
} else { } else {
uint8_t snb; uint8_t snb;
snb = i - stm32l4_info->bank2_start + 256; snb = i - stm32l4_info->bank2_start;
if (((snb >= wrp2a_start) && if (((snb >= wrp2a_start) &&
(snb <= wrp2a_end)) || (snb <= wrp2a_end)) ||
((snb >= wrp2b_start) && ((snb >= wrp2b_start) &&
@ -362,7 +374,7 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last)
1. Check that no Flash memory operation is ongoing by 1. Check that no Flash memory operation is ongoing by
checking the BSY bit in the FLASH_SR register checking the BSY bit in the FLASH_SR register
2. Set the PER bit and select the page and bank 2. Set the PER bit and select the page and bank
you wish to erase in the FLASH_CR register you wish to erase in the FLASH_CR register
3. Set the STRT bit in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register
4. Wait for the BSY bit to be cleared 4. Wait for the BSY bit to be cleared
*/ */
@ -372,9 +384,9 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last)
uint32_t erase_flags; uint32_t erase_flags;
erase_flags = FLASH_PER | FLASH_STRT; erase_flags = FLASH_PER | FLASH_STRT;
if (i >= stm32l4_info->bank2_start) { if (i >= stm32l4_info->bank2_start) {
uint8_t snb; uint8_t snb;
snb = (i - stm32l4_info->bank2_start) + 256; snb = i - stm32l4_info->bank2_start;
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER; erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else } else
erase_flags |= i << FLASH_PAGE_SHIFT; erase_flags |= i << FLASH_PAGE_SHIFT;
@ -473,7 +485,7 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
* buffer, free the algorithm */ * buffer, free the algorithm */
target_free_working_area(target, write_algorithm); target_free_working_area(target, write_algorithm);
LOG_WARNING("no large enough working area available, can't do block memory writes"); LOG_WARNING("large enough working area not available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
} }
} }
@ -594,6 +606,9 @@ static int stm32l4_probe(struct flash_bank *bank)
/* set max flash size depending on family */ /* set max flash size depending on family */
switch (device_id & 0xfff) { switch (device_id & 0xfff) {
case 0x470:
max_flash_size_in_kb = 2048;
break;
case 0x461: case 0x461:
case 0x415: case 0x415:
max_flash_size_in_kb = 1024; max_flash_size_in_kb = 1024;
@ -605,7 +620,7 @@ static int stm32l4_probe(struct flash_bank *bank)
max_flash_size_in_kb = 256; max_flash_size_in_kb = 256;
break; break;
default: default:
LOG_WARNING("Cannot identify target as a STM32L4 family."); LOG_WARNING("Cannot identify target as an STM32L4 family device.");
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -622,45 +637,77 @@ static int stm32l4_probe(struct flash_bank *bank)
LOG_INFO("flash size = %dkbytes", flash_size_in_kb); LOG_INFO("flash size = %dkbytes", flash_size_in_kb);
/* did we assign flash size? */ /* did we assign a flash size? */
assert(flash_size_in_kb != 0xffff); assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
/* get options to for DUAL BANK. */ /* get options for DUAL BANK. */
retval = target_read_u32(target, STM32_FLASH_OPTR, &options); retval = target_read_u32(target, STM32_FLASH_OPTR, &options);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
/* only devices with < 1024 kiB may be set to single bank dual banks */ int num_pages = 0;
if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK)) int page_size = 0;
stm32l4_info->bank2_start = 256;
else
stm32l4_info->bank2_start = flash_size_in_kb << 9;
/* did we assign flash size? */ switch (device_id & 0xfff) {
assert((flash_size_in_kb != 0xffff) && flash_size_in_kb); case 0x470:
/* L4R/S have 1M or 2M FLASH and dual/single bank mode.
/* calculate numbers of pages */ * Page size is 4K or 8K.*/
int num_pages = flash_size_in_kb / 2; if (flash_size_in_kb == 2048) {
stm32l4_info->bank2_start = 256;
/* check that calculation result makes sense */ if (options & OPT_DBANK_GE_2M) {
assert(num_pages > 0); page_size = 4096;
num_pages = 512;
} else {
page_size = 8192;
num_pages = 256;
}
break;
}
if (flash_size_in_kb == 1024) {
stm32l4_info->bank2_start = 128;
if (options & OPT_DBANK_LE_1M) {
page_size = 4096;
num_pages = 256;
} else {
page_size = 8192;
num_pages = 128;
}
break;
}
/* Invalid FLASH size for this device. */
LOG_WARNING("Invalid flash size for STM32L4+ family device.");
return ERROR_FAIL;
default:
/* Other L4 family devices have 2K pages. */
page_size = 2048;
num_pages = flash_size_in_kb / 2;
/* check that calculation result makes sense */
assert(num_pages > 0);
if ((flash_size_in_kb == 1024) || !(options & OPT_DBANK_LE_1M))
stm32l4_info->bank2_start = 256;
else
stm32l4_info->bank2_start = num_pages / 2;
break;
}
/* Release sector table if allocated. */
if (bank->sectors) { if (bank->sectors) {
free(bank->sectors); free(bank->sectors);
bank->sectors = NULL; bank->sectors = NULL;
} }
/* Set bank configuration and construct sector table. */
bank->base = base_address; bank->base = base_address;
bank->size = num_pages * (1 << 11); bank->size = num_pages * page_size;
bank->num_sectors = num_pages; bank->num_sectors = num_pages;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
if (!bank->sectors) if (!bank->sectors)
return ERROR_FAIL; /* Checkme: What better error to use?*/ return ERROR_FAIL; /* Checkme: What better error to use?*/
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
bank->sectors[i].offset = i << 11; bank->sectors[i].offset = i * page_size;
bank->sectors[i].size = 1 << 11; bank->sectors[i].size = page_size;
bank->sectors[i].is_erased = -1; bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1; bank->sectors[i].is_protected = 1;
} }
@ -703,6 +750,10 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
const char *device_str; const char *device_str;
switch (device_id) { switch (device_id) {
case 0x470:
device_str = "STM32L4R/4Sxx";
break;
case 0x461: case 0x461:
device_str = "STM32L496/4A6"; device_str = "STM32L496/4A6";
break; break;

View File

@ -424,13 +424,6 @@ static int stm32lx_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK; return ERROR_OK;
} }
static int stm32lx_protect(struct flash_bank *bank, int set, int first,
int last)
{
LOG_WARNING("protection of the STM32L flash is not implemented");
return ERROR_OK;
}
static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer, static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count) uint32_t offset, uint32_t count)
{ {
@ -863,7 +856,7 @@ static int stm32lx_probe(struct flash_bank *bank)
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE;
bank->sectors[i].is_erased = -1; bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1; bank->sectors[i].is_protected = -1;
} }
stm32lx_info->probed = 1; stm32lx_info->probed = 1;
@ -956,7 +949,6 @@ struct flash_driver stm32lx_flash = {
.commands = stm32lx_command_handlers, .commands = stm32lx_command_handlers,
.flash_bank_command = stm32lx_flash_bank_command, .flash_bank_command = stm32lx_flash_bank_command,
.erase = stm32lx_erase, .erase = stm32lx_erase,
.protect = stm32lx_protect,
.write = stm32lx_write, .write = stm32lx_write,
.read = default_flash_read, .read = default_flash_read,
.probe = stm32lx_probe, .probe = stm32lx_probe,

View File

@ -269,17 +269,14 @@ static int smi_write_enable(struct flash_bank *bank)
static uint32_t erase_command(struct stmsmi_flash_bank *stmsmi_info, static uint32_t erase_command(struct stmsmi_flash_bank *stmsmi_info,
uint32_t offset) uint32_t offset)
{ {
union { uint8_t cmd_bytes[] = {
uint32_t command; stmsmi_info->dev->erase_cmd,
uint8_t x[4]; offset >> 16,
} cmd; offset >> 8,
offset
};
cmd.x[0] = stmsmi_info->dev->erase_cmd; return le_to_h_u32(cmd_bytes);
cmd.x[1] = offset >> 16;
cmd.x[2] = offset >> 8;
cmd.x[3] = offset;
return cmd.command;
} }
static int smi_erase_sector(struct flash_bank *bank, int sector) static int smi_erase_sector(struct flash_bank *bank, int sector)
@ -348,6 +345,9 @@ static int stmsmi_erase(struct flash_bank *bank, int first, int last)
} }
} }
if (stmsmi_info->dev->erase_cmd == 0x00)
return ERROR_FLASH_OPER_UNSUPPORTED;
for (sector = first; sector <= last; sector++) { for (sector = first; sector <= last; sector++) {
retval = smi_erase_sector(bank, sector); retval = smi_erase_sector(bank, sector);
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -431,7 +431,9 @@ static int stmsmi_write(struct flash_bank *bank, const uint8_t *buffer,
} }
} }
page_size = stmsmi_info->dev->pagesize; /* if no valid page_size, use reasonable default */
page_size = stmsmi_info->dev->pagesize ?
stmsmi_info->dev->pagesize : SPIFLASH_DEF_PAGESIZE;
/* unaligned buffer head */ /* unaligned buffer head */
if (count > 0 && (offset & 3) != 0) { if (count > 0 && (offset & 3) != 0) {
@ -524,7 +526,7 @@ static int stmsmi_probe(struct flash_bank *bank)
{ {
struct target *target = bank->target; struct target *target = bank->target;
struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv;
uint32_t io_base; uint32_t io_base, sectorsize;
struct flash_sector *sectors; struct flash_sector *sectors;
uint32_t id = 0; /* silence uninitialized warning */ uint32_t id = 0; /* silence uninitialized warning */
const struct stmsmi_target *target_device; const struct stmsmi_target *target_device;
@ -589,10 +591,18 @@ static int stmsmi_probe(struct flash_bank *bank)
/* Set correct size value */ /* Set correct size value */
bank->size = stmsmi_info->dev->size_in_bytes; bank->size = stmsmi_info->dev->size_in_bytes;
if (bank->size <= (1UL << 16))
LOG_WARNING("device needs 2-byte addresses - not implemented");
if (bank->size > (1UL << 24))
LOG_WARNING("device needs paging or 4-byte addresses - not implemented");
/* if no sectors, treat whole bank as single sector */
sectorsize = stmsmi_info->dev->sectorsize ?
stmsmi_info->dev->sectorsize : stmsmi_info->dev->size_in_bytes;
/* create and fill sectors array */ /* create and fill sectors array */
bank->num_sectors = bank->num_sectors =
stmsmi_info->dev->size_in_bytes / stmsmi_info->dev->sectorsize; stmsmi_info->dev->size_in_bytes / sectorsize;
sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
if (sectors == NULL) { if (sectors == NULL) {
LOG_ERROR("not enough memory"); LOG_ERROR("not enough memory");
@ -600,8 +610,8 @@ static int stmsmi_probe(struct flash_bank *bank)
} }
for (int sector = 0; sector < bank->num_sectors; sector++) { for (int sector = 0; sector < bank->num_sectors; sector++) {
sectors[sector].offset = sector * stmsmi_info->dev->sectorsize; sectors[sector].offset = sector * sectorsize;
sectors[sector].size = stmsmi_info->dev->sectorsize; sectors[sector].size = sectorsize;
sectors[sector].is_erased = -1; sectors[sector].is_erased = -1;
sectors[sector].is_protected = 1; sectors[sector].is_protected = 1;
} }

View File

@ -98,10 +98,18 @@ COMMAND_HANDLER(handle_flash_info_command)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
/* We must query the hardware to avoid printing stale information! */ /* If the driver does not implement protection, we show the default
retval = p->driver->protect_check(p); * state of is_protected array - usually protection state unknown */
if (retval != ERROR_OK) if (p->driver->protect_check == NULL) {
return retval; retval = ERROR_FLASH_OPER_UNSUPPORTED;
} else {
/* We must query the hardware to avoid printing stale information! */
retval = p->driver->protect_check(p);
if (retval != ERROR_OK && retval != ERROR_FLASH_OPER_UNSUPPORTED)
return retval;
}
if (retval == ERROR_FLASH_OPER_UNSUPPORTED)
LOG_WARNING("Flash protection check is not implemented.");
command_print(CMD_CTX, command_print(CMD_CTX,
"#%d : %s at 0x%8.8" TARGET_PRIxADDR ", size 0x%8.8" PRIx32 "#%d : %s at 0x%8.8" TARGET_PRIxADDR ", size 0x%8.8" PRIx32

390
src/flash/nor/w600.c Normal file
View File

@ -0,0 +1,390 @@
/***************************************************************************
* Copyright (C) 2018 by Simon Qian *
* SimonQian@SimonQian.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
#define W600_FLASH_SECSIZE 0x1000
#define W600_FLASH_PAGESIZE 0x100
#define W600_FLASH_BASE 0x08000000
#define W600_FLASH_PROTECT_SIZE 0x2000
/* w600 register locations */
#define QFLASH_REGBASE 0X40002000
#define QFLASH_CMD_INFO (QFLASH_REGBASE + 0)
#define QFLASH_CMD_START (QFLASH_REGBASE + 4)
#define QFLASH_BUFFER (QFLASH_REGBASE + 0X200)
#define QFLASH_CMD_READ (1ul << 14)
#define QFLASH_CMD_WRITE 0
#define QFLASH_CMD_ADDR (1ul << 31)
#define QFLASH_CMD_DATA (1ul << 15)
#define QFLASH_CMD_DATALEN(len) (((len) & 0x3FF) << 16)
#define QFLASH_CMD_RDID (QFLASH_CMD_READ | 0x9F)
#define QFLASH_CMD_WREN (QFLASH_CMD_WRITE | 0x06)
#define QFLASH_CMD_WRDI (QFLASH_CMD_WRITE | 0x04)
#define QFLASH_CMD_SE (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 11) | 0x20)
#define QFLASH_CMD_PP (QFLASH_CMD_WRITE | QFLASH_CMD_ADDR | (1ul << 12) | 0x02)
#define QFLASH_START (1ul << 28)
#define QFLASH_ADDR(addr) (((addr) & 0xFFFFF) << 8)
#define QFLASH_CRM(crm) (((crm) & 0xFF) << 0)
struct w600_flash_param {
uint8_t id;
uint8_t se_delay;
uint8_t pp_delay;
};
static const struct w600_flash_param w600_param[] = {
{
.id = 0x85,
.se_delay = 8,
.pp_delay = 2,
},
{
.id = 0x1C,
.se_delay = 50,
.pp_delay = 1,
},
{
.id = 0xC8,
.se_delay = 45,
.pp_delay = 1,
},
{
.id = 0x0B,
.se_delay = 60,
.pp_delay = 1,
},
{
.id = 0x68,
.se_delay = 50,
.pp_delay = 1,
},
};
struct w600_flash_bank {
int probed;
uint32_t id;
const struct w600_flash_param *param;
uint32_t register_base;
uint32_t user_bank_size;
};
/* flash bank w600 <base> <size> 0 0 <target#>
*/
FLASH_BANK_COMMAND_HANDLER(w600_flash_bank_command)
{
struct w600_flash_bank *w600_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
w600_info = malloc(sizeof(struct w600_flash_bank));
bank->driver_priv = w600_info;
w600_info->probed = 0;
w600_info->register_base = QFLASH_REGBASE;
w600_info->user_bank_size = bank->size;
return ERROR_OK;
}
static int w600_get_delay(struct flash_bank *bank, uint32_t cmd)
{
struct w600_flash_bank *w600_info = bank->driver_priv;
if (!w600_info->param)
return 0;
switch (cmd) {
case QFLASH_CMD_SE:
return w600_info->param->se_delay;
case QFLASH_CMD_PP:
return w600_info->param->pp_delay;
default:
return 0;
}
}
static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
uint32_t len, int timeout)
{
struct target *target = bank->target;
if (len > 0)
cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA;
LOG_DEBUG("WRITE CMD: 0x%08" PRIx32 "", cmd);
int retval = target_write_u32(target, QFLASH_CMD_INFO, cmd);
if (retval != ERROR_OK)
return retval;
addr |= QFLASH_START;
LOG_DEBUG("WRITE START: 0x%08" PRIx32 "", addr);
retval = target_write_u32(target, QFLASH_CMD_START, addr);
if (retval != ERROR_OK)
return retval;
LOG_DEBUG("DELAY %dms", timeout);
alive_sleep(timeout);
int retry = 100;
uint32_t status;
for (;;) {
LOG_DEBUG("READ START...");
retval = target_read_u32(target, QFLASH_CMD_START, &status);
if (retval == ERROR_OK)
LOG_DEBUG("READ START: 0x%08" PRIx32 "", status);
else
LOG_DEBUG("READ START FAILED");
if ((retval != ERROR_OK) || (status & QFLASH_START)) {
if (retry-- <= 0) {
LOG_ERROR("timed out waiting for flash");
return ERROR_FAIL;
}
continue;
}
break;
}
return retval;
}
static int w600_write_enable(struct flash_bank *bank)
{
return w600_start_do(bank, QFLASH_CMD_WREN, 0, 0, 0);
}
static int w600_write_disable(struct flash_bank *bank)
{
return w600_start_do(bank, QFLASH_CMD_WRDI, 0, 0, 0);
}
static int w600_start(struct flash_bank *bank, uint32_t cmd, uint32_t addr,
uint32_t len)
{
int retval = w600_write_enable(bank);
if (retval != ERROR_OK)
return retval;
retval = w600_start_do(bank, cmd, addr, len, w600_get_delay(bank, cmd));
if (retval != ERROR_OK)
return retval;
retval = w600_write_disable(bank);
if (retval != ERROR_OK)
return retval;
return retval;
}
static int w600_erase(struct flash_bank *bank, int first, int last)
{
int retval = ERROR_OK;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if (first < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE) {
LOG_ERROR("can not erase protected area");
return ERROR_FAIL;
}
for (int i = first; i <= last; i++) {
retval = w600_start(bank, QFLASH_CMD_SE,
QFLASH_ADDR(bank->sectors[i].offset), 0);
if (retval != ERROR_OK)
break;
}
return retval;
}
static int w600_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
int retval = ERROR_OK;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
if ((offset % W600_FLASH_PAGESIZE) != 0) {
LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
offset, W600_FLASH_PAGESIZE);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
if ((count % W600_FLASH_PAGESIZE) != 0) {
LOG_WARNING("count 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment",
offset, W600_FLASH_PAGESIZE);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
while (count > 0) {
retval = target_write_buffer(target, QFLASH_BUFFER, W600_FLASH_PAGESIZE, buffer);
if (retval != ERROR_OK)
break;
retval = w600_start(bank, QFLASH_CMD_PP, QFLASH_ADDR(offset),
W600_FLASH_PAGESIZE);
if (retval != ERROR_OK)
break;
count -= W600_FLASH_PAGESIZE;
offset += W600_FLASH_PAGESIZE;
buffer += W600_FLASH_PAGESIZE;
}
return retval;
}
static int w600_get_flash_id(struct flash_bank *bank, uint32_t *flash_id)
{
struct target *target = bank->target;
int retval = w600_start(bank, QFLASH_CMD_RDID, 0, 4);
if (retval != ERROR_OK)
return retval;
return target_read_u32(target, QFLASH_BUFFER, flash_id);
}
static int w600_probe(struct flash_bank *bank)
{
struct w600_flash_bank *w600_info = bank->driver_priv;
uint32_t flash_size;
uint32_t flash_id;
size_t i;
w600_info->probed = 0;
/* read stm32 device id register */
int retval = w600_get_flash_id(bank, &flash_id);
if (retval != ERROR_OK)
return retval;
LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id);
w600_info->id = flash_id;
w600_info->param = NULL;
for (i = 0; i < ARRAY_SIZE(w600_param); i++) {
if (w600_param[i].id == (flash_id & 0xFF)) {
w600_info->param = &w600_param[i];
break;
}
}
if (!w600_info->param) {
LOG_ERROR("flash_id not supported for w600");
return ERROR_FAIL;
}
/* 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 (w600_info->user_bank_size) {
LOG_INFO("ignoring flash probed value, using configured bank size");
flash_size = w600_info->user_bank_size;
} else {
flash_size = ((flash_id & 0xFFFFFF) >> 16) & 0xFF;
if ((flash_size != 0x14) && (flash_size != 0x13)) {
LOG_ERROR("w600 flash size failed, probe inaccurate");
return ERROR_FAIL;
}
flash_size = 1 << flash_size;
}
LOG_INFO("flash size = %dkbytes", flash_size / 1024);
/* calculate numbers of pages */
size_t num_pages = flash_size / W600_FLASH_SECSIZE;
/* check that calculation result makes sense */
assert(num_pages > 0);
if (bank->sectors) {
free(bank->sectors);
bank->sectors = NULL;
}
bank->base = W600_FLASH_BASE;
bank->size = num_pages * W600_FLASH_SECSIZE;
bank->num_sectors = num_pages;
bank->write_start_alignment = W600_FLASH_PAGESIZE;
bank->write_end_alignment = W600_FLASH_PAGESIZE;
bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
for (i = 0; i < num_pages; i++) {
bank->sectors[i].offset = i * W600_FLASH_SECSIZE;
bank->sectors[i].size = W600_FLASH_SECSIZE;
bank->sectors[i].is_erased = -1;
/* offset 0 to W600_FLASH_PROTECT_SIZE shoule be protected */
bank->sectors[i].is_protected = (i < W600_FLASH_PROTECT_SIZE / W600_FLASH_SECSIZE);
}
w600_info->probed = 1;
return ERROR_OK;
}
static int w600_auto_probe(struct flash_bank *bank)
{
struct w600_flash_bank *w600_info = bank->driver_priv;
if (w600_info->probed)
return ERROR_OK;
return w600_probe(bank);
}
static int get_w600_info(struct flash_bank *bank, char *buf, int buf_size)
{
uint32_t flash_id;
/* read w600 device id register */
int retval = w600_get_flash_id(bank, &flash_id);
if (retval != ERROR_OK)
return retval;
snprintf(buf, buf_size, "w600 : 0x%08" PRIx32 "", flash_id);
return ERROR_OK;
}
struct flash_driver w600_flash = {
.name = "w600",
.flash_bank_command = w600_flash_bank_command,
.erase = w600_erase,
.write = w600_write,
.read = default_flash_read,
.probe = w600_probe,
.auto_probe = w600_auto_probe,
.erase_check = default_flash_blank_check,
.info = get_w600_info,
.free_driver_priv = default_flash_free_driver_priv,
};

View File

@ -557,6 +557,10 @@ static char *__command_name(struct command *c, char delim, unsigned extra)
if (NULL == c->parent) { if (NULL == c->parent) {
/* allocate enough for the name, child names, and '\0' */ /* allocate enough for the name, child names, and '\0' */
name = malloc(len + extra + 1); name = malloc(len + extra + 1);
if (!name) {
LOG_ERROR("Out of memory");
return NULL;
}
strcpy(name, c->name); strcpy(name, c->name);
} else { } else {
/* parent's extra must include both the space and name */ /* parent's extra must include both the space and name */
@ -575,31 +579,35 @@ char *command_name(struct command *c, char delim)
static bool command_can_run(struct command_context *cmd_ctx, struct command *c) static bool command_can_run(struct command_context *cmd_ctx, struct command *c)
{ {
return c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode; if (c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode)
return true;
/* Many commands may be run only before/after 'init' */
const char *when;
switch (c->mode) {
case COMMAND_CONFIG:
when = "before";
break;
case COMMAND_EXEC:
when = "after";
break;
/* handle the impossible with humor; it guarantees a bug report! */
default:
when = "if Cthulhu is summoned by";
break;
}
char *full_name = command_name(c, ' ');
LOG_ERROR("The '%s' command must be used %s 'init'.",
full_name ? full_name : c->name, when);
free(full_name);
return false;
} }
static int run_command(struct command_context *context, static int run_command(struct command_context *context,
struct command *c, const char *words[], unsigned num_words) struct command *c, const char *words[], unsigned num_words)
{ {
if (!command_can_run(context, c)) { if (!command_can_run(context, c))
/* Many commands may be run only before/after 'init' */
const char *when;
switch (c->mode) {
case COMMAND_CONFIG:
when = "before";
break;
case COMMAND_EXEC:
when = "after";
break;
/* handle the impossible with humor; it guarantees a bug report! */
default:
when = "if Cthulhu is summoned by";
break;
}
LOG_ERROR("The '%s' command must be used %s 'init'.",
c->name, when);
return ERROR_FAIL; return ERROR_FAIL;
}
struct command_invocation cmd = { struct command_invocation cmd = {
.ctx = context, .ctx = context,
@ -631,15 +639,17 @@ static int run_command(struct command_context *context,
if (NULL != full_name) { if (NULL != full_name) {
command_run_linef(context, "usage %s", full_name); command_run_linef(context, "usage %s", full_name);
free(full_name); free(full_name);
} else }
retval = -ENOMEM;
} else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
/* just fall through for a shutdown request */ /* just fall through for a shutdown request */
} else if (retval != ERROR_OK) { } else if (retval != ERROR_OK) {
/* we do not print out an error message because the command *should* /* we do not print out an error message because the command *should*
* have printed out an error * have printed out an error
*/ */
LOG_DEBUG("Command failed with error code %d", retval); char *full_name = command_name(c, ' ');
LOG_DEBUG("Command '%s' failed with error code %d",
full_name ? full_name : c->name, retval);
free(full_name);
} }
return retval; return retval;
@ -870,7 +880,7 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
{ {
char *cmd_name = command_name(c, ' '); char *cmd_name = command_name(c, ' ');
if (NULL == cmd_name) if (NULL == cmd_name)
return -ENOMEM; return ERROR_FAIL;
/* If the match string occurs anywhere, we print out /* If the match string occurs anywhere, we print out
* stuff for this command. */ * stuff for this command. */
@ -1026,6 +1036,9 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
} }
/* pass the command through to the intended handler */ /* pass the command through to the intended handler */
if (c->jim_handler) { if (c->jim_handler) {
if (!command_can_run(cmd_ctx, c))
return ERROR_FAIL;
interp->cmdPrivData = c->jim_handler_data; interp->cmdPrivData = c->jim_handler_data;
return (*c->jim_handler)(interp, count, start); return (*c->jim_handler)(interp, count, start);
} }

View File

@ -61,46 +61,16 @@ static const char * const log_strings[6] = {
static int count; static int count;
static struct store_log_forward *log_head; /* forward the log to the listeners */
static int log_forward_count;
struct store_log_forward {
struct store_log_forward *next;
const char *file;
int line;
const char *function;
const char *string;
};
/* either forward the log to the listeners or store it for possible forwarding later */
static void log_forward(const char *file, unsigned line, const char *function, const char *string) static void log_forward(const char *file, unsigned line, const char *function, const char *string)
{ {
if (log_forward_count == 0) { struct log_callback *cb, *next;
struct log_callback *cb, *next; cb = log_callbacks;
cb = log_callbacks; /* DANGER!!!! the log callback can remove itself!!!! */
/* DANGER!!!! the log callback can remove itself!!!! */ while (cb) {
while (cb) { next = cb->next;
next = cb->next; cb->fn(cb->priv, file, line, function, string);
cb->fn(cb->priv, file, line, function, string); cb = next;
cb = next;
}
} else {
struct store_log_forward *log = malloc(sizeof(struct store_log_forward));
log->file = strdup(file);
log->line = line;
log->function = strdup(function);
log->string = strdup(string);
log->next = NULL;
if (log_head == NULL)
log_head = log;
else {
/* append to tail */
struct store_log_forward *t;
t = log_head;
while (t->next != NULL)
t = t->next;
t->next = log;
}
} }
} }

View File

@ -12,15 +12,18 @@ proc exit {} {
# All commands are registered with an 'ocd_' prefix, while the "real" # All commands are registered with an 'ocd_' prefix, while the "real"
# command is a wrapper that calls this function. Its primary purpose is # command is a wrapper that calls this function. Its primary purpose is
# to discard 'handler' command output, # to discard 'handler' command output.
# Due to the two nested proc calls, this wrapper has to explicitly run
# the wrapped command in the stack frame two levels above.
proc ocd_bouncer {name args} { proc ocd_bouncer {name args} {
set cmd [format "ocd_%s" $name] set cmd [format "ocd_%s" $name]
set type [eval ocd_command type $cmd $args] set type [eval ocd_command type $cmd $args]
set errcode error set errcode error
set skiplevel [expr [eval info level] > 1 ? 2 : 1]
if {$type == "native"} { if {$type == "native"} {
return [eval $cmd $args] return [uplevel $skiplevel $cmd $args]
} else {if {$type == "simple"} { } else {if {$type == "simple"} {
set errcode [catch {eval $cmd $args}] set errcode [catch {uplevel $skiplevel $cmd $args}]
if {$errcode == 0} { if {$errcode == 0} {
return "" return ""
} else { } else {

View File

@ -35,6 +35,7 @@
#include "interface.h" #include "interface.h"
#include "interfaces.h" #include "interfaces.h"
#include <transport/transport.h> #include <transport/transport.h>
#include <jtag/drivers/jtag_usb_common.h>
#ifdef HAVE_STRINGS_H #ifdef HAVE_STRINGS_H
#include <strings.h> #include <strings.h>
@ -456,7 +457,54 @@ COMMAND_HANDLER(handle_adapter_khz_command)
return retval; return retval;
} }
#ifndef HAVE_JTAG_MINIDRIVER_H
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
COMMAND_HANDLER(handle_usb_location_command)
{
if (CMD_ARGC == 1)
jtag_usb_set_location(CMD_ARGV[0]);
command_print(CMD_CTX, "adapter usb location: %s", jtag_usb_get_location());
return ERROR_OK;
}
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
static const struct command_registration adapter_usb_command_handlers[] = {
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
{
.name = "location",
.handler = &handle_usb_location_command,
.mode = COMMAND_CONFIG,
.help = "set the USB bus location of the USB device",
.usage = "<bus>-port[.port]...",
},
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
COMMAND_REGISTRATION_DONE
};
#endif /* MINIDRIVER */
static const struct command_registration adapter_command_handlers[] = {
#ifndef HAVE_JTAG_MINIDRIVER_H
{
.name = "usb",
.mode = COMMAND_ANY,
.help = "usb adapter command group",
.usage = "",
.chain = adapter_usb_command_handlers,
},
#endif /* MINIDRIVER */
COMMAND_REGISTRATION_DONE
};
static const struct command_registration interface_command_handlers[] = { static const struct command_registration interface_command_handlers[] = {
{
.name = "adapter",
.mode = COMMAND_ANY,
.help = "adapter command group",
.usage = "",
.chain = adapter_command_handlers,
},
{ {
.name = "adapter_khz", .name = "adapter_khz",
.handler = handle_adapter_khz_command, .handler = handle_adapter_khz_command,

View File

@ -340,7 +340,7 @@ aice_transport_jtag_subcommand_handlers[] = {
}, },
{ {
.name = "configure", .name = "configure",
.mode = COMMAND_EXEC, .mode = COMMAND_ANY,
.jim_handler = jim_jtag_configure, .jim_handler = jim_jtag_configure,
.help = "Provide a Tcl handler for the specified " .help = "Provide a Tcl handler for the specified "
"TAP event.", "TAP event.",

View File

@ -2139,11 +2139,8 @@ static int aice_usb_open(struct aice_port_param_s *param)
unsigned int aice_read_ep; unsigned int aice_read_ep;
unsigned int aice_write_ep; unsigned int aice_write_ep;
#ifdef HAVE_LIBUSB1
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, LIBUSB_TRANSFER_TYPE_BULK); jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, LIBUSB_TRANSFER_TYPE_BULK);
#else
jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1, USB_ENDPOINT_TYPE_BULK);
#endif
LOG_DEBUG("aice_read_ep=0x%x, aice_write_ep=0x%x", aice_read_ep, aice_write_ep); LOG_DEBUG("aice_read_ep=0x%x, aice_write_ep=0x%x", aice_read_ep, aice_write_ep);
aice_handler.usb_read_ep = aice_read_ep; aice_handler.usb_read_ep = aice_read_ep;

View File

@ -19,6 +19,7 @@ DRIVERFILES =
# Standard Driver: common files # Standard Driver: common files
DRIVERFILES += %D%/driver.c DRIVERFILES += %D%/driver.c
DRIVERFILES += %D%/jtag_usb_common.c
if USE_LIBUSB1 if USE_LIBUSB1
DRIVERFILES += %D%/libusb1_common.c DRIVERFILES += %D%/libusb1_common.c
@ -166,6 +167,7 @@ endif
DRIVERHEADERS = \ DRIVERHEADERS = \
%D%/bitbang.h \ %D%/bitbang.h \
%D%/bitq.h \ %D%/bitq.h \
%D%/jtag_usb_common.h \
%D%/libusb0_common.h \ %D%/libusb0_common.h \
%D%/libusb1_common.h \ %D%/libusb1_common.h \
%D%/libusb_common.h \ %D%/libusb_common.h \

View File

@ -30,9 +30,6 @@
#include <jtag/interface.h> #include <jtag/interface.h>
#include <jtag/commands.h> #include <jtag/commands.h>
/* YUK! - but this is currently a global.... */
extern struct jtag_interface *jtag_interface;
/** /**
* Function bitbang_stableclocks * Function bitbang_stableclocks
* issues a number of clock cycles while staying in a stable state. * issues a number of clock cycles while staying in a stable state.

View File

@ -1096,7 +1096,7 @@ static int cmsis_dap_init(void)
if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
if (jtag_reset_config & RESET_SRST_NO_GATING) { if (jtag_reset_config & RESET_SRST_NO_GATING) {
retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, (1 << 7), 0, NULL); retval = cmsis_dap_cmd_DAP_SWJ_Pins(0, SWJ_PIN_SRST, 0, NULL);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
LOG_INFO("Connecting under reset"); LOG_INFO("Connecting under reset");
@ -1670,6 +1670,30 @@ COMMAND_HANDLER(cmsis_dap_handle_info_command)
return ERROR_OK; return ERROR_OK;
} }
COMMAND_HANDLER(cmsis_dap_handle_cmd_command)
{
int retval;
unsigned i;
uint8_t *buffer = cmsis_dap_handle->packet_buffer;
buffer[0] = 0; /* report number */
for (i = 0; i < CMD_ARGC; i++)
buffer[i + 1] = strtoul(CMD_ARGV[i], NULL, 16);
retval = cmsis_dap_usb_xfer(cmsis_dap_handle, CMD_ARGC + 1);
if (retval != ERROR_OK) {
LOG_ERROR("CMSIS-DAP command failed.");
return ERROR_JTAG_DEVICE_ERROR;
}
LOG_INFO("Returned data %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8,
buffer[1], buffer[2], buffer[3], buffer[4]);
return ERROR_OK;
}
COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command) COMMAND_HANDLER(cmsis_dap_handle_vid_pid_command)
{ {
if (CMD_ARGC > MAX_USB_IDS * 2) { if (CMD_ARGC > MAX_USB_IDS * 2) {
@ -1729,6 +1753,13 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = {
.usage = "", .usage = "",
.help = "show cmsis-dap info", .help = "show cmsis-dap info",
}, },
{
.name = "cmd",
.handler = &cmsis_dap_handle_cmd_command,
.mode = COMMAND_EXEC,
.usage = "",
.help = "issue cmsis-dap command",
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };

View File

@ -39,24 +39,9 @@
#include <time.h> #include <time.h>
/* /*
* Bit 7 (0x80, pin 6, RI ): unused.
* Bit 6 (0x40, pin 10,DCD): /SYSRST output.
* Bit 5 (0x20, pin 9, DSR): unused.
* Bit 4 (0x10, pin 2, DTR): /TRST output.
* Bit 3 (0x08, pin 11,CTS): TMS output.
* Bit 2 (0x04, pin 3, RTS): TDO input.
* Bit 1 (0x02, pin 5, RXD): TDI output.
* Bit 0 (0x01, pin 1, TXD): TCK output.
*
* Sync bit bang mode is implemented as described in FTDI Application * Sync bit bang mode is implemented as described in FTDI Application
* Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R". * Note AN232R-01: "Bit Bang Modes for the FT232R and FT245R".
*/ */
#define TCK (1 << 0)
#define TDI (1 << 1)
#define READ_TDO (1 << 2)
#define TMS (1 << 3)
#define NTRST (1 << 4)
#define NSYSRST (1 << 6)
/* /*
* USB endpoints. * USB endpoints.
@ -81,7 +66,7 @@
#define SIO_WRITE_EEPROM 0x91 #define SIO_WRITE_EEPROM 0x91
#define SIO_ERASE_EEPROM 0x92 #define SIO_ERASE_EEPROM 0x92
#define FT232R_BUF_SIZE 4000 #define FT232R_BUF_SIZE_EXTRA 4096
static char *ft232r_serial_desc; static char *ft232r_serial_desc;
static uint16_t ft232r_vid = 0x0403; /* FTDI */ static uint16_t ft232r_vid = 0x0403; /* FTDI */
@ -91,6 +76,33 @@ static jtag_libusb_device_handle *adapter;
static uint8_t *ft232r_output; static uint8_t *ft232r_output;
static size_t ft232r_output_len; static size_t ft232r_output_len;
/**
* FT232R GPIO bit number to RS232 name
*/
#define FT232R_BIT_COUNT 8
static char *ft232r_bit_name_array[FT232R_BIT_COUNT] = {
"TXD", /* 0: pin 1 TCK output */
"RXD", /* 1: pin 5 TDI output */
"RTS", /* 2: pin 3 TDO input */
"CTS", /* 3: pin 11 TMS output */
"DTR", /* 4: pin 2 /TRST output */
"DSR", /* 5: pin 9 unused */
"DCD", /* 6: pin 10 /SYSRST output */
"RI" /* 7: pin 6 unused */
};
static int tck_gpio; /* initialized to 0 by default */
static int tdi_gpio = 1;
static int tdo_gpio = 2;
static int tms_gpio = 3;
static int ntrst_gpio = 4;
static int nsysrst_gpio = 6;
static size_t ft232r_buf_size = FT232R_BUF_SIZE_EXTRA;
/** 0xFFFF disables restore by default, after exit serial port will not work.
* 0x15 sets TXD RTS DTR as outputs, after exit serial port will continue to work.
*/
static uint16_t ft232r_restore_bitmode = 0xFFFF;
/** /**
* Perform sync bitbang output/input transaction. * Perform sync bitbang output/input transaction.
* Before call, an array ft232r_output[] should be filled with data to send. * Before call, an array ft232r_output[] should be filled with data to send.
@ -160,20 +172,35 @@ static int ft232r_send_recv(void)
return ERROR_OK; return ERROR_OK;
} }
void ft232r_increase_buf_size(size_t new_buf_size)
{
uint8_t *new_buf_ptr;
if (new_buf_size >= ft232r_buf_size) {
new_buf_size += FT232R_BUF_SIZE_EXTRA;
new_buf_ptr = realloc(ft232r_output, new_buf_size);
if (new_buf_ptr != NULL) {
ft232r_output = new_buf_ptr;
ft232r_buf_size = new_buf_size;
}
}
}
/** /**
* Add one TCK/TMS/TDI sample to send buffer. * Add one TCK/TMS/TDI sample to send buffer.
*/ */
static void ft232r_write(int tck, int tms, int tdi) static void ft232r_write(int tck, int tms, int tdi)
{ {
unsigned out_value = NTRST | NSYSRST; unsigned out_value = (1<<ntrst_gpio) | (1<<nsysrst_gpio);
if (tck) if (tck)
out_value |= TCK; out_value |= (1<<tck_gpio);
if (tms) if (tms)
out_value |= TMS; out_value |= (1<<tms_gpio);
if (tdi) if (tdi)
out_value |= TDI; out_value |= (1<<tdi_gpio);
if (ft232r_output_len >= FT232R_BUF_SIZE) { ft232r_increase_buf_size(ft232r_output_len);
if (ft232r_output_len >= ft232r_buf_size) {
/* FIXME: should we just execute queue here? */ /* FIXME: should we just execute queue here? */
LOG_ERROR("ft232r_write: buffer overflow"); LOG_ERROR("ft232r_write: buffer overflow");
return; return;
@ -187,20 +214,22 @@ static void ft232r_write(int tck, int tms, int tdi)
*/ */
static void ft232r_reset(int trst, int srst) static void ft232r_reset(int trst, int srst)
{ {
unsigned out_value = NTRST | NSYSRST; unsigned out_value = (1<<ntrst_gpio) | (1<<nsysrst_gpio);
LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst); LOG_DEBUG("ft232r_reset(%d,%d)", trst, srst);
if (trst == 1) if (trst == 1)
out_value &= ~NTRST; /* switch /TRST low */ out_value &= ~(1<<ntrst_gpio); /* switch /TRST low */
else if (trst == 0) else if (trst == 0)
out_value |= NTRST; /* switch /TRST high */ out_value |= (1<<ntrst_gpio); /* switch /TRST high */
if (srst == 1) if (srst == 1)
out_value &= ~NSYSRST; /* switch /SYSRST low */ out_value &= ~(1<<nsysrst_gpio); /* switch /SYSRST low */
else if (srst == 0) else if (srst == 0)
out_value |= NSYSRST; /* switch /SYSRST high */ out_value |= (1<<nsysrst_gpio); /* switch /SYSRST high */
if (ft232r_output_len >= FT232R_BUF_SIZE) { ft232r_increase_buf_size(ft232r_output_len);
if (ft232r_output_len >= ft232r_buf_size) {
/* FIXME: should we just execute queue here? */ /* FIXME: should we just execute queue here? */
LOG_ERROR("ft232r_write: buffer overflow"); LOG_ERROR("ft232r_write: buffer overflow");
return; return;
@ -236,7 +265,10 @@ static int ft232r_init(void)
return ERROR_JTAG_INIT_FAILED; return ERROR_JTAG_INIT_FAILED;
} }
libusb_detach_kernel_driver(adapter, 0); if (ft232r_restore_bitmode == 0xFFFF) /* serial port will not be restored after jtag: */
libusb_detach_kernel_driver(adapter, 0);
else /* serial port will be restored after jtag: */
libusb_set_auto_detach_kernel_driver(adapter, 1); /* 1: DONT_DETACH_SIO_MODULE */
if (jtag_libusb_claim_interface(adapter, 0)) { if (jtag_libusb_claim_interface(adapter, 0)) {
LOG_ERROR("unable to claim interface"); LOG_ERROR("unable to claim interface");
@ -254,7 +286,7 @@ static int ft232r_init(void)
/* Sync bit bang mode. */ /* Sync bit bang mode. */
if (jtag_libusb_control_transfer(adapter, if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BITMODE, TCK | TDI | TMS | NTRST | NSYSRST | 0x400, SIO_SET_BITMODE, (1<<tck_gpio) | (1<<tdi_gpio) | (1<<tms_gpio) | (1<<ntrst_gpio) | (1<<nsysrst_gpio) | 0x400,
0, 0, 0, 1000) != 0) { 0, 0, 0, 1000) != 0) {
LOG_ERROR("cannot set sync bitbang mode"); LOG_ERROR("cannot set sync bitbang mode");
return ERROR_JTAG_INIT_FAILED; return ERROR_JTAG_INIT_FAILED;
@ -279,7 +311,7 @@ static int ft232r_init(void)
return ERROR_JTAG_INIT_FAILED; return ERROR_JTAG_INIT_FAILED;
} }
ft232r_output = malloc(FT232R_BUF_SIZE); ft232r_output = malloc(ft232r_buf_size);
if (ft232r_output == NULL) { if (ft232r_output == NULL) {
LOG_ERROR("Unable to allocate memory for the buffer"); LOG_ERROR("Unable to allocate memory for the buffer");
return ERROR_JTAG_INIT_FAILED; return ERROR_JTAG_INIT_FAILED;
@ -290,11 +322,24 @@ static int ft232r_init(void)
static int ft232r_quit(void) static int ft232r_quit(void)
{ {
/* to restore serial port: set TXD RTS DTR as outputs, others as inputs, disable sync bit bang mode. */
if (ft232r_restore_bitmode != 0xFFFF) {
if (jtag_libusb_control_transfer(adapter,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT,
SIO_SET_BITMODE, ft232r_restore_bitmode,
0, 0, 0, 1000) != 0) {
LOG_ERROR("cannot set bitmode to restore serial port");
}
}
if (jtag_libusb_release_interface(adapter, 0) != 0) if (jtag_libusb_release_interface(adapter, 0) != 0)
LOG_ERROR("usb release interface failed"); LOG_ERROR("usb release interface failed");
jtag_libusb_close(adapter); jtag_libusb_close(adapter);
free(ft232r_output);
free(ft232r_output); /* free used memory */
ft232r_output = NULL; /* reset pointer to memory */
ft232r_buf_size = FT232R_BUF_SIZE_EXTRA; /* reset next initial buffer size */
return ERROR_OK; return ERROR_OK;
} }
@ -331,6 +376,27 @@ static int ft232r_khz(int khz, int *divisor)
return ERROR_OK; return ERROR_OK;
} }
static char *ft232r_bit_number_to_name(int bit)
{
if (bit >= 0 && bit < FT232R_BIT_COUNT)
return ft232r_bit_name_array[bit];
return "?";
}
static int ft232r_bit_name_to_number(const char *name)
{
int i;
if (name[0] >= '0' && name[0] <= '9' && name[1] == '\0') {
i = atoi(name);
if (i >= 0 && i < FT232R_BIT_COUNT)
return i;
}
for (i = 0; i < FT232R_BIT_COUNT; i++)
if (strcasecmp(name, ft232r_bit_name_array[i]) == 0)
return i;
return -1;
}
COMMAND_HANDLER(ft232r_handle_serial_desc_command) COMMAND_HANDLER(ft232r_handle_serial_desc_command)
{ {
if (CMD_ARGC == 1) if (CMD_ARGC == 1)
@ -357,6 +423,145 @@ COMMAND_HANDLER(ft232r_handle_vid_pid_command)
return ERROR_OK; return ERROR_OK;
} }
COMMAND_HANDLER(ft232r_handle_jtag_nums_command)
{
if (CMD_ARGC == 4) {
tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[1]);
tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[2]);
tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[3]);
} else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tck_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tms_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tdi_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tdo_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R nums: TCK = %d %s, TMS = %d %s, TDI = %d %s, TDO = %d %s",
tck_gpio, ft232r_bit_number_to_name(tck_gpio),
tms_gpio, ft232r_bit_number_to_name(tms_gpio),
tdi_gpio, ft232r_bit_number_to_name(tdi_gpio),
tdo_gpio, ft232r_bit_number_to_name(tdo_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_tck_num_command)
{
if (CMD_ARGC == 1)
tck_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tck_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: TCK = %d %s", tck_gpio, ft232r_bit_number_to_name(tck_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_tms_num_command)
{
if (CMD_ARGC == 1)
tms_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tms_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: TMS = %d %s", tms_gpio, ft232r_bit_number_to_name(tms_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_tdo_num_command)
{
if (CMD_ARGC == 1)
tdo_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tdo_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: TDO = %d %s", tdo_gpio, ft232r_bit_number_to_name(tdo_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_tdi_num_command)
{
if (CMD_ARGC == 1)
tdi_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (tdi_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: TDI = %d %s", tdi_gpio, ft232r_bit_number_to_name(tdi_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_trst_num_command)
{
if (CMD_ARGC == 1)
ntrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (ntrst_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: TRST = %d %s", ntrst_gpio, ft232r_bit_number_to_name(ntrst_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_srst_num_command)
{
if (CMD_ARGC == 1)
nsysrst_gpio = ft232r_bit_name_to_number(CMD_ARGV[0]);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
if (nsysrst_gpio < 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R num: SRST = %d %s", nsysrst_gpio, ft232r_bit_number_to_name(nsysrst_gpio));
return ERROR_OK;
}
COMMAND_HANDLER(ft232r_handle_restore_serial_command)
{
if (CMD_ARGC == 1)
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], ft232r_restore_bitmode);
else if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
command_print(CMD_CTX,
"FT232R restore serial: 0x%04X (%s)",
ft232r_restore_bitmode, ft232r_restore_bitmode == 0xFFFF ? "disabled" : "enabled");
return ERROR_OK;
}
static const struct command_registration ft232r_command_handlers[] = { static const struct command_registration ft232r_command_handlers[] = {
{ {
.name = "ft232r_serial_desc", .name = "ft232r_serial_desc",
@ -372,6 +577,62 @@ static const struct command_registration ft232r_command_handlers[] = {
.help = "USB VID and PID of the adapter", .help = "USB VID and PID of the adapter",
.usage = "vid pid", .usage = "vid pid",
}, },
{
.name = "ft232r_jtag_nums",
.handler = ft232r_handle_jtag_nums_command,
.mode = COMMAND_CONFIG,
.help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
.usage = "<0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI> <0-7|TXD-RI>",
},
{
.name = "ft232r_tck_num",
.handler = ft232r_handle_tck_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for tck.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_tms_num",
.handler = ft232r_handle_tms_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for tms.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_tdo_num",
.handler = ft232r_handle_tdo_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for tdo.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_tdi_num",
.handler = ft232r_handle_tdi_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for tdi.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_srst_num",
.handler = ft232r_handle_srst_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for srst.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_trst_num",
.handler = ft232r_handle_trst_num_command,
.mode = COMMAND_CONFIG,
.help = "gpio number for trst.",
.usage = "<0-7|TXD|RXD|RTS|CTS|DTR|DSR|DCD|RI>",
},
{
.name = "ft232r_restore_serial",
.handler = ft232r_handle_restore_serial_command,
.mode = COMMAND_CONFIG,
.help = "bitmode control word that restores serial port.",
.usage = "bitmode_control_word",
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };
@ -553,7 +814,7 @@ static void syncbb_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int
int bcval = 1 << (bit_cnt % 8); int bcval = 1 << (bit_cnt % 8);
int val = ft232r_output[bit0_index + bit_cnt*2 + 1]; int val = ft232r_output[bit0_index + bit_cnt*2 + 1];
if (val & READ_TDO) if (val & (1<<tdo_gpio))
buffer[bytec] |= bcval; buffer[bytec] |= bcval;
else else
buffer[bytec] &= ~bcval; buffer[bytec] &= ~bcval;

View File

@ -160,10 +160,10 @@ static int imx_gpio_swd_write(int tck, int tms, int tdi)
static int imx_gpio_reset(int trst, int srst) static int imx_gpio_reset(int trst, int srst)
{ {
if (trst_gpio != -1) if (trst_gpio != -1)
trst ? gpio_set(trst_gpio) : gpio_clear(trst_gpio); trst ? gpio_clear(trst_gpio) : gpio_set(trst_gpio);
if (srst_gpio != -1) if (srst_gpio != -1)
srst ? gpio_set(srst_gpio) : gpio_clear(srst_gpio); srst ? gpio_clear(srst_gpio) : gpio_set(srst_gpio);
return ERROR_OK; return ERROR_OK;
} }

View File

@ -2130,7 +2130,7 @@ skip:
static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
{ {
uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)]; uint8_t data_parity_trn[DIV_ROUND_UP(32 + 1, 8)];
if (tap_length + 46 + 8 + ap_delay_clk >= sizeof(tdi_buffer) * 8 || if (tap_length + 46 + 8 + ap_delay_clk >= swd_buffer_size * 8 ||
pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) { pending_scan_results_length == MAX_PENDING_SCAN_RESULTS) {
/* Not enough room in the queue. Run the queue. */ /* Not enough room in the queue. Run the queue. */
queued_retval = jlink_swd_run_queue(); queued_retval = jlink_swd_run_queue();

View File

@ -0,0 +1,85 @@
/*
* SPDX-License-Identifier: GPL-2.0+
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/
#include <helper/log.h>
#include "jtag_usb_common.h"
static char *jtag_usb_location;
/*
* 1 char: bus
* 2 * 7 chars: max 7 ports
* 1 char: test for overflow
* ------
* 16 chars
*/
#define JTAG_USB_MAX_LOCATION_LENGHT 16
void jtag_usb_set_location(const char *location)
{
if (strnlen(location, JTAG_USB_MAX_LOCATION_LENGHT) ==
JTAG_USB_MAX_LOCATION_LENGHT)
LOG_WARNING("usb location string is too long!!\n");
if (jtag_usb_location)
free(jtag_usb_location);
jtag_usb_location = strndup(location, JTAG_USB_MAX_LOCATION_LENGHT);
}
const char *jtag_usb_get_location(void)
{
return jtag_usb_location;
}
bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
size_t path_len)
{
size_t path_step, string_lengh;
char *ptr, *loc;
bool equal = false;
/* strtok need non const char */
loc = strndup(jtag_usb_get_location(), JTAG_USB_MAX_LOCATION_LENGHT);
string_lengh = strnlen(loc, JTAG_USB_MAX_LOCATION_LENGHT);
ptr = strtok(loc, "-");
if (ptr == NULL) {
LOG_WARNING("no '-' in usb path\n");
goto done;
}
string_lengh -= 1;
/* check bus mismatch */
if (atoi(ptr) != dev_bus)
goto done;
path_step = 0;
while (path_step < path_len) {
ptr = strtok(NULL, ".");
/* no more tokens in path */
if (ptr == NULL)
break;
/* path mismatch at some step */
if (path_step < path_len && atoi(ptr) != port_path[path_step])
break;
path_step++;
string_lengh -= 2;
};
/* walked the full path, all elements match */
if (path_step == path_len && !string_lengh)
equal = true;
else
LOG_WARNING("excluded by device path option: %s\n",
jtag_usb_get_location());
done:
free(loc);
return equal;
}

View File

@ -0,0 +1,14 @@
/*
* SPDX-License-Identifier: GPL-2.0+
* Copyright (c) 2018 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
*/
#ifndef OPENOCD_JTAG_USB_COMMON_H
#define OPENOCD_JTAG_USB_COMMON_H
void jtag_usb_set_location(const char *location);
const char *jtag_usb_get_location(void);
bool jtag_usb_location_equal(uint8_t dev_bus, uint8_t *port_path,
size_t path_len);
#endif /* OPENOCD_JTAG_USB_COMMON_H */

View File

@ -29,6 +29,10 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#endif #endif
#ifndef _WIN32
#include <netinet/tcp.h>
#endif
#define NO_TAP_SHIFT 0 #define NO_TAP_SHIFT 0
#define TAP_SHIFT 1 #define TAP_SHIFT 1
@ -368,6 +372,8 @@ static int jtag_vpi_execute_queue(void)
static int jtag_vpi_init(void) static int jtag_vpi_init(void)
{ {
int flag = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0); sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) { if (sockfd < 0) {
LOG_ERROR("Could not create socket"); LOG_ERROR("Could not create socket");
@ -395,6 +401,13 @@ static int jtag_vpi_init(void)
return ERROR_COMMAND_CLOSE_CONNECTION; return ERROR_COMMAND_CLOSE_CONNECTION;
} }
if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
/* This increases performance drematically for local
* connections, which is the most likely arrangement
* for a VPI connection. */
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
}
LOG_INFO("Connection to %s : %u succeed", server_address, server_port); LOG_INFO("Connection to %s : %u succeed", server_address, server_port);
return ERROR_OK; return ERROR_OK;

View File

@ -67,7 +67,8 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
const char *serial, const char *serial,
struct jtag_libusb_device_handle **out) struct jtag_libusb_device_handle **out)
{ {
int retval = -ENODEV; int retval = ERROR_FAIL;
bool serial_mismatch = false;
struct jtag_libusb_device_handle *libusb_handle; struct jtag_libusb_device_handle *libusb_handle;
usb_init(); usb_init();
@ -83,21 +84,27 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
libusb_handle = usb_open(dev); libusb_handle = usb_open(dev);
if (NULL == libusb_handle) { if (NULL == libusb_handle) {
retval = -errno; LOG_ERROR("usb_open() failed with %s", usb_strerror());
continue; continue;
} }
/* Device must be open to use libusb_get_string_descriptor_ascii. */ /* Device must be open to use libusb_get_string_descriptor_ascii. */
if (serial != NULL && if (serial != NULL &&
!string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) { !string_descriptor_equal(libusb_handle, dev->descriptor.iSerialNumber, serial)) {
serial_mismatch = true;
usb_close(libusb_handle); usb_close(libusb_handle);
continue; continue;
} }
*out = libusb_handle; *out = libusb_handle;
retval = 0; retval = ERROR_OK;
serial_mismatch = false;
break; break;
} }
} }
if (serial_mismatch)
LOG_INFO("No device matches the serial string");
return retval; return retval;
} }

View File

@ -38,6 +38,7 @@
#define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE #define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE
#define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT #define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT
#define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN #define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN
#define LIBUSB_TRANSFER_TYPE_BULK USB_ENDPOINT_TYPE_BULK
static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh, static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh,
int iface) int iface)

View File

@ -20,8 +20,15 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include "config.h"
#endif #endif
#include "log.h" #include <jtag/drivers/jtag_usb_common.h>
#include "libusb1_common.h" #include "libusb1_common.h"
#include "log.h"
/*
* comment from libusb:
* As per the USB 3.0 specs, the current maximum limit for the depth is 7.
*/
#define MAX_USB_PORTS 7
static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ static struct libusb_context *jtag_libusb_context; /**< Libusb context **/
static libusb_device **devs; /**< The usb device list **/ static libusb_device **devs; /**< The usb device list **/
@ -38,6 +45,31 @@ static bool jtag_libusb_match(struct libusb_device_descriptor *dev_desc,
return false; return false;
} }
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
static bool jtag_libusb_location_equal(libusb_device *device)
{
uint8_t port_path[MAX_USB_PORTS];
uint8_t dev_bus;
int path_len;
path_len = libusb_get_port_numbers(device, port_path, MAX_USB_PORTS);
if (path_len == LIBUSB_ERROR_OVERFLOW) {
LOG_WARNING("cannot determine path to usb device! (more than %i ports in path)\n",
MAX_USB_PORTS);
return false;
}
dev_bus = libusb_get_bus_number(device);
return jtag_usb_location_equal(dev_bus, port_path, path_len);
}
#else /* HAVE_LIBUSB_GET_PORT_NUMBERS */
static bool jtag_libusb_location_equal(libusb_device *device)
{
return true;
}
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
/* Returns true if the string descriptor indexed by str_index in device matches string */ /* 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, static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index,
const char *string) const char *string)
@ -72,6 +104,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
{ {
int cnt, idx, errCode; int cnt, idx, errCode;
int retval = ERROR_FAIL; int retval = ERROR_FAIL;
bool serial_mismatch = false;
struct jtag_libusb_device_handle *libusb_handle = NULL; struct jtag_libusb_device_handle *libusb_handle = NULL;
if (libusb_init(&jtag_libusb_context) < 0) if (libusb_init(&jtag_libusb_context) < 0)
@ -88,6 +121,9 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
if (!jtag_libusb_match(&dev_desc, vids, pids)) if (!jtag_libusb_match(&dev_desc, vids, pids))
continue; continue;
if (jtag_usb_get_location() && !jtag_libusb_location_equal(devs[idx]))
continue;
errCode = libusb_open(devs[idx], &libusb_handle); errCode = libusb_open(devs[idx], &libusb_handle);
if (errCode) { if (errCode) {
@ -99,6 +135,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
/* Device must be open to use libusb_get_string_descriptor_ascii. */ /* Device must be open to use libusb_get_string_descriptor_ascii. */
if (serial != NULL && if (serial != NULL &&
!string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) { !string_descriptor_equal(libusb_handle, dev_desc.iSerialNumber, serial)) {
serial_mismatch = true;
libusb_close(libusb_handle); libusb_close(libusb_handle);
continue; continue;
} }
@ -106,10 +143,15 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
/* Success. */ /* Success. */
*out = libusb_handle; *out = libusb_handle;
retval = ERROR_OK; retval = ERROR_OK;
serial_mismatch = false;
break; break;
} }
if (cnt >= 0) if (cnt >= 0)
libusb_free_device_list(devs, 1); libusb_free_device_list(devs, 1);
if (serial_mismatch)
LOG_INFO("No device matches the serial string");
return retval; return retval;
} }

File diff suppressed because it is too large Load Diff

View File

@ -457,62 +457,70 @@ static const struct command_registration sysfsgpio_command_handlers[] = {
.handler = &sysfsgpio_handle_jtag_gpionums, .handler = &sysfsgpio_handle_jtag_gpionums,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)",
.usage = "(tck tms tdi tdo)* ", .usage = "[tck tms tdi tdo]",
}, },
{ {
.name = "sysfsgpio_tck_num", .name = "sysfsgpio_tck_num",
.handler = &sysfsgpio_handle_jtag_gpionum_tck, .handler = &sysfsgpio_handle_jtag_gpionum_tck,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for tck.", .help = "gpio number for tck.",
.usage = "[tck]",
}, },
{ {
.name = "sysfsgpio_tms_num", .name = "sysfsgpio_tms_num",
.handler = &sysfsgpio_handle_jtag_gpionum_tms, .handler = &sysfsgpio_handle_jtag_gpionum_tms,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for tms.", .help = "gpio number for tms.",
.usage = "[tms]",
}, },
{ {
.name = "sysfsgpio_tdo_num", .name = "sysfsgpio_tdo_num",
.handler = &sysfsgpio_handle_jtag_gpionum_tdo, .handler = &sysfsgpio_handle_jtag_gpionum_tdo,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for tdo.", .help = "gpio number for tdo.",
.usage = "[tdo]",
}, },
{ {
.name = "sysfsgpio_tdi_num", .name = "sysfsgpio_tdi_num",
.handler = &sysfsgpio_handle_jtag_gpionum_tdi, .handler = &sysfsgpio_handle_jtag_gpionum_tdi,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for tdi.", .help = "gpio number for tdi.",
.usage = "[tdi]",
}, },
{ {
.name = "sysfsgpio_srst_num", .name = "sysfsgpio_srst_num",
.handler = &sysfsgpio_handle_jtag_gpionum_srst, .handler = &sysfsgpio_handle_jtag_gpionum_srst,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for srst.", .help = "gpio number for srst.",
.usage = "[srst]",
}, },
{ {
.name = "sysfsgpio_trst_num", .name = "sysfsgpio_trst_num",
.handler = &sysfsgpio_handle_jtag_gpionum_trst, .handler = &sysfsgpio_handle_jtag_gpionum_trst,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for trst.", .help = "gpio number for trst.",
.usage = "[trst]",
}, },
{ {
.name = "sysfsgpio_swd_nums", .name = "sysfsgpio_swd_nums",
.handler = &sysfsgpio_handle_swd_gpionums, .handler = &sysfsgpio_handle_swd_gpionums,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio numbers for swclk, swdio. (in that order)", .help = "gpio numbers for swclk, swdio. (in that order)",
.usage = "(swclk swdio)* ", .usage = "[swclk swdio]",
}, },
{ {
.name = "sysfsgpio_swclk_num", .name = "sysfsgpio_swclk_num",
.handler = &sysfsgpio_handle_swd_gpionum_swclk, .handler = &sysfsgpio_handle_swd_gpionum_swclk,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for swclk.", .help = "gpio number for swclk.",
.usage = "[swclk]",
}, },
{ {
.name = "sysfsgpio_swdio_num", .name = "sysfsgpio_swdio_num",
.handler = &sysfsgpio_handle_swd_gpionum_swdio, .handler = &sysfsgpio_handle_swd_gpionum_swdio,
.mode = COMMAND_CONFIG, .mode = COMMAND_CONFIG,
.help = "gpio number for swdio.", .help = "gpio number for swdio.",
.usage = "[swdio]",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };
@ -561,6 +569,8 @@ static void cleanup_all_fds(void)
cleanup_fd(tdo_fd, tdo_gpio); cleanup_fd(tdo_fd, tdo_gpio);
cleanup_fd(trst_fd, trst_gpio); cleanup_fd(trst_fd, trst_gpio);
cleanup_fd(srst_fd, srst_gpio); cleanup_fd(srst_fd, srst_gpio);
cleanup_fd(swclk_fd, swclk_gpio);
cleanup_fd(swdio_fd, swdio_gpio);
} }
static bool sysfsgpio_jtag_mode_possible(void) static bool sysfsgpio_jtag_mode_possible(void)

View File

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#endif #endif
#include "usb_common.h" #include "usb_common.h"
#include "log.h"
static bool jtag_usb_match(struct usb_device *dev, static bool jtag_usb_match(struct usb_device *dev,
@ -45,10 +46,12 @@ int jtag_usb_open(const uint16_t vids[], const uint16_t pids[],
continue; continue;
*out = usb_open(dev); *out = usb_open(dev);
if (NULL == *out) if (NULL == *out) {
return -errno; LOG_ERROR("usb_open() failed with %s", usb_strerror());
return 0; return ERROR_FAIL;
}
return ERROR_OK;
} }
} }
return -ENODEV; return ERROR_FAIL;
} }

View File

@ -29,6 +29,13 @@
/* XDS110 USB serial number length */ /* XDS110 USB serial number length */
#define XDS110_SERIAL_LEN 8 #define XDS110_SERIAL_LEN 8
/* XDS110 stand-alone probe voltage supply limits */
#define XDS110_MIN_VOLTAGE 1800
#define XDS110_MAX_VOLTAGE 3600
/* XDS110 stand-alone probe hardware ID */
#define XDS110_STAND_ALONE_ID 0x21
/* Firmware version that introduced OpenOCD support via block accesses */ /* Firmware version that introduced OpenOCD support via block accesses */
#define OCD_FIRMWARE_VERSION 0x02030011 #define OCD_FIRMWARE_VERSION 0x02030011
#define OCD_FIRMWARE_UPGRADE \ #define OCD_FIRMWARE_UPGRADE \
@ -162,6 +169,7 @@
#define SWD_DISCONNECT 0x18 /* Switch from SWD to JTAG connection */ #define SWD_DISCONNECT 0x18 /* Switch from SWD to JTAG connection */
#define CJTAG_CONNECT 0x2b /* Switch from JTAG to cJTAG connection */ #define CJTAG_CONNECT 0x2b /* Switch from JTAG to cJTAG connection */
#define CJTAG_DISCONNECT 0x2c /* Switch from cJTAG to JTAG connection */ #define CJTAG_DISCONNECT 0x2c /* Switch from cJTAG to JTAG connection */
#define XDS_SET_SUPPLY 0x32 /* Set up stand-alone probe upply voltage */
#define OCD_DAP_REQUEST 0x3a /* Handle block of DAP requests */ #define OCD_DAP_REQUEST 0x3a /* Handle block of DAP requests */
#define OCD_SCAN_REQUEST 0x3b /* Handle block of JTAG scan requests */ #define OCD_SCAN_REQUEST 0x3b /* Handle block of JTAG scan requests */
#define OCD_PATHMOVE 0x3c /* Handle PATHMOVE to navigate JTAG states */ #define OCD_PATHMOVE 0x3c /* Handle PATHMOVE to navigate JTAG states */
@ -219,6 +227,8 @@ struct xds110_info {
uint32_t delay_count; uint32_t delay_count;
/* XDS110 serial number */ /* XDS110 serial number */
char serial[XDS110_SERIAL_LEN + 1]; char serial[XDS110_SERIAL_LEN + 1];
/* XDS110 voltage supply setting */
uint32_t voltage;
/* XDS110 firmware and hardware version */ /* XDS110 firmware and hardware version */
uint32_t firmware; uint32_t firmware;
uint16_t hardware; uint16_t hardware;
@ -242,6 +252,7 @@ static struct xds110_info xds110 = {
.speed = XDS110_MAX_TCK_SPEED, .speed = XDS110_MAX_TCK_SPEED,
.delay_count = 0, .delay_count = 0,
.serial = {0}, .serial = {0},
.voltage = 0,
.firmware = 0, .firmware = 0,
.hardware = 0, .hardware = 0,
.txn_request_size = 0, .txn_request_size = 0,
@ -601,10 +612,15 @@ static bool xds_execute(uint32_t out_length, uint32_t in_length,
if (bytes_read != in_length) { if (bytes_read != in_length) {
/* Unexpected amount of data returned */ /* Unexpected amount of data returned */
success = false; success = false;
LOG_DEBUG("XDS110: command 0x%02x return %d bytes, expected %d",
xds110.write_payload[0], bytes_read, in_length);
} else { } else {
/* Extract error code from return packet */ /* Extract error code from return packet */
error = (int)xds110_get_u32(&xds110.read_payload[0]); error = (int)xds110_get_u32(&xds110.read_payload[0]);
done = true; done = true;
if (SC_ERR_NONE != error)
LOG_DEBUG("XDS110: command 0x%02x returned error %d",
xds110.write_payload[0], error);
} }
} }
} }
@ -952,6 +968,24 @@ static bool cjtag_disconnect(void)
return success; return success;
} }
static bool xds_set_supply(uint32_t voltage)
{
uint8_t *volts_pntr = &xds110.write_payload[XDS_OUT_LEN + 0]; /* 32-bits */
uint8_t *source_pntr = &xds110.write_payload[XDS_OUT_LEN + 4]; /* 8-bits */
bool success;
xds110.write_payload[0] = XDS_SET_SUPPLY;
xds110_set_u32(volts_pntr, voltage);
*source_pntr = (uint8_t)(0 != voltage ? 1 : 0);
success = xds_execute(XDS_OUT_LEN + 5, XDS_IN_LEN, DEFAULT_ATTEMPTS,
DEFAULT_TIMEOUT);
return success;
}
static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size, static bool ocd_dap_request(uint8_t *dap_requests, uint32_t request_size,
uint32_t *dap_results, uint32_t result_count) uint32_t *dap_results, uint32_t result_count)
{ {
@ -1318,7 +1352,7 @@ static void xds110_show_info(void)
(((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf)); (((firmware >> 4) & 0xf) * 10) + ((firmware >> 0) & 0xf));
LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware); LOG_INFO("XDS110: hardware version = 0x%04x", xds110.hardware);
if (0 != xds110.serial[0]) if (0 != xds110.serial[0])
LOG_INFO("XDS110: serial number = %s)", xds110.serial); LOG_INFO("XDS110: serial number = %s", xds110.serial);
if (xds110.is_swd_mode) { if (xds110.is_swd_mode) {
LOG_INFO("XDS110: connected to target via SWD"); LOG_INFO("XDS110: connected to target via SWD");
LOG_INFO("XDS110: SWCLK set to %d kHz", xds110.speed); LOG_INFO("XDS110: SWCLK set to %d kHz", xds110.speed);
@ -1390,6 +1424,20 @@ static int xds110_init(void)
} }
} }
if (success) {
/* Set supply voltage for stand-alone probes */
if (XDS110_STAND_ALONE_ID == xds110.hardware) {
success = xds_set_supply(xds110.voltage);
/* Allow time for target device to power up */
/* (CC32xx takes up to 1300 ms before debug is enabled) */
alive_sleep(1500);
} else if (0 != xds110.voltage) {
/* Voltage supply not a feature of embedded probes */
LOG_WARNING(
"XDS110: ignoring supply voltage, not supported on this probe");
}
}
if (success) { if (success) {
success = xds_set_trst(0); success = xds_set_trst(0);
if (success) if (success)
@ -1569,6 +1617,9 @@ static void xds110_execute_reset(struct jtag_command *cmd)
srst = 0; srst = 0;
} }
(void)xds_set_srst(srst); (void)xds_set_srst(srst);
/* Toggle TCK to trigger HIB on CC13x/CC26x devices */
(void)xds_cycle_tck(60000);
} }
} }
@ -1918,6 +1969,31 @@ COMMAND_HANDLER(xds110_handle_serial_command)
return ERROR_OK; return ERROR_OK;
} }
COMMAND_HANDLER(xds110_handle_supply_voltage_command)
{
uint32_t voltage = 0;
if (CMD_ARGC == 1) {
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], voltage);
if (voltage == 0 || (voltage >= XDS110_MIN_VOLTAGE && voltage
<= XDS110_MAX_VOLTAGE)) {
/* Requested voltage is in range */
xds110.voltage = voltage;
} else {
LOG_ERROR("XDS110: voltage must be 0 or between %d and %d "
"millivolts", XDS110_MIN_VOLTAGE, XDS110_MAX_VOLTAGE);
return ERROR_FAIL;
}
xds110.voltage = voltage;
} else {
LOG_ERROR("XDS110: expected one argument to xds110_supply_voltage "
"<millivolts>");
return ERROR_FAIL;
}
return ERROR_OK;
}
static const struct command_registration xds110_subcommand_handlers[] = { static const struct command_registration xds110_subcommand_handlers[] = {
{ {
.name = "info", .name = "info",
@ -1944,6 +2020,13 @@ static const struct command_registration xds110_command_handlers[] = {
.help = "set the XDS110 probe serial number", .help = "set the XDS110 probe serial number",
.usage = "serial_string", .usage = "serial_string",
}, },
{
.name = "xds110_supply_voltage",
.handler = &xds110_handle_supply_voltage_command,
.mode = COMMAND_CONFIG,
.help = "set the XDS110 probe supply voltage",
.usage = "supply_voltage (millivolts)",
},
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };

View File

@ -53,16 +53,25 @@ 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> */ /* SWD_ACK_* bits are defined in <target/arm_adi_v5.h> */
/*
* The following sequences are updated to
* ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E
*/
/** /**
* Line reset. * SWD Line reset.
* *
* Line reset is at least 50 SWCLK cycles with SWDIO driven high, followed * SWD Line reset is at least 50 SWCLK cycles with SWDIO driven high,
* by at least one idle (low) cycle. * followed by at least two idle (low) cycle.
* Bits are stored (and transmitted) LSB-first.
*/ */
static const uint8_t swd_seq_line_reset[] = { static const uint8_t swd_seq_line_reset[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03 /* At least 50 SWCLK cycles with SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* At least 2 idle (low) cycles */
0x00,
}; };
static const unsigned swd_seq_line_reset_len = 51; static const unsigned swd_seq_line_reset_len = 64;
/** /**
* JTAG-to-SWD sequence. * JTAG-to-SWD sequence.
@ -71,36 +80,53 @@ static const unsigned swd_seq_line_reset_len = 51;
* high, putting either interface logic into reset state, followed by a * 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 * specific 16-bit sequence and finally a line reset in case the SWJ-DP was
* already in SWD mode. * already in SWD mode.
* Bits are stored (and transmitted) LSB-first.
*/ */
static const uint8_t swd_seq_jtag_to_swd[] = { static const uint8_t swd_seq_jtag_to_swd[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x9e, /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching sequence from JTAG to SWD */
0x9e, 0xe7,
/* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* At least 2 idle (low) cycles */
0x00,
}; };
static const unsigned swd_seq_jtag_to_swd_len = 118; static const unsigned swd_seq_jtag_to_swd_len = 136;
/** /**
* SWD-to-JTAG sequence. * SWD-to-JTAG sequence.
* *
* The SWD-to-JTAG sequence is at least 50 TCK/SWCLK cycles with TMS/SWDIO * 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 * 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 * specific 16-bit sequence and finally at least 5 TCK/SWCLK cycles with
* JTAG TAP in TLR. * TMS/SWDIO high to put the JTAG TAP in Test-Logic-Reset state.
* Bits are stored (and transmitted) LSB-first.
*/ */
static const uint8_t swd_seq_swd_to_jtag[] = { static const uint8_t swd_seq_swd_to_jtag[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x9c, 0xff /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching sequence from SWD to JTAG */
0x3c, 0xe7,
/* At least 5 TCK/SWCLK cycles with TMS/SWDIO high */
0xff,
}; };
static const unsigned swd_seq_swd_to_jtag_len = 71; static const unsigned swd_seq_swd_to_jtag_len = 80;
/** /**
* SWD-to-dormant sequence. * SWD-to-dormant sequence.
* *
* This is at least 50 SWCLK cycles with SWDIO high to put the interface * This is at least 50 SWCLK cycles with SWDIO high to put the interface
* in reset state, followed by a specific 16-bit sequence. * in reset state, followed by a specific 16-bit sequence.
* Bits are stored (and transmitted) LSB-first.
*/ */
static const uint8_t swd_seq_swd_to_dormant[] = { static const uint8_t swd_seq_swd_to_dormant[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x8e, 0x03 /* At least 50 SWCLK cycles with SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching sequence from SWD to dormant */
0xbc, 0xe3,
}; };
static const unsigned swd_seq_swd_to_dormant_len = 66; static const unsigned swd_seq_swd_to_dormant_len = 72;
/** /**
* Dormant-to-SWD sequence. * Dormant-to-SWD sequence.
@ -110,14 +136,82 @@ static const unsigned swd_seq_swd_to_dormant_len = 66;
* sequence, followed by 4 TCK/SWCLK cycles with TMS/SWDIO low, followed by * sequence, followed by 4 TCK/SWCLK cycles with TMS/SWDIO low, followed by
* a specific protocol-dependent activation code. For SWD the activation code * a specific protocol-dependent activation code. For SWD the activation code
* is an 8-bit sequence. The sequence ends with a line reset. * is an 8-bit sequence. The sequence ends with a line reset.
* Bits are stored (and transmitted) LSB-first.
*/ */
static const uint8_t swd_seq_dormant_to_swd[] = { static const uint8_t swd_seq_dormant_to_swd[] = {
/* At least 8 SWCLK cycles with SWDIO high */
0xff, 0xff,
/* Selection alert sequence */
0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86, 0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86,
0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19, 0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19,
0x10, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f /*
* 4 SWCLK cycles with SWDIO low ...
* + SWD activation code 0x1a ...
* + at least 8 SWCLK cycles with SWDIO high
*/
0xa0, /* ((0x00) & GENMASK(3, 0)) | ((0x1a << 4) & GENMASK(7, 4)) */
0xf1, /* ((0x1a >> 4) & GENMASK(3, 0)) | ((0xff << 4) & GENMASK(7, 4)) */
0xff,
/* At least 50 SWCLK cycles with SWDIO high */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* At least 2 idle (low) cycles */
0x00,
}; };
static const unsigned swd_seq_dormant_to_swd_len = 199; static const unsigned swd_seq_dormant_to_swd_len = 224;
/**
* JTAG-to-dormant sequence.
*
* This is at least 5 TCK cycles with TMS high to put the interface
* in test-logic-reset state, followed by a specific 31-bit sequence.
* Bits are stored (and transmitted) LSB-first.
*/
static const uint8_t swd_seq_jtag_to_dormant[] = {
/* At least 5 TCK cycles with TMS high */
0xff,
/*
* Still one TCK cycle with TMS high followed by 31 bits JTAG-to-DS
* select sequence 0xba, 0xbb, 0xbb, 0x33,
*/
0x75, /* ((0xff >> 7) & GENMASK(0, 0)) | ((0xba << 1) & GENMASK(7, 1)) */
0x77, /* ((0xba >> 7) & GENMASK(0, 0)) | ((0xbb << 1) & GENMASK(7, 1)) */
0x77, /* ((0xbb >> 7) & GENMASK(0, 0)) | ((0xbb << 1) & GENMASK(7, 1)) */
0x67, /* ((0xbb >> 7) & GENMASK(0, 0)) | ((0x33 << 1) & GENMASK(7, 1)) */
};
static const unsigned swd_seq_jtag_to_dormant_len = 40;
/**
* Dormant-to-JTAG 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 JTAG there are two
* possible activation codes:
* - "JTAG-Serial": 12 bits 0x00, 0x00
* - "Arm CoreSight JTAG-DP": 8 bits 0x0a
* We use "JTAG-Serial" only, which seams more generic.
* Since the target TAP can be either in Run/Test Idle or in Test-Logic-Reset
* states, Arm recommends to put the TAP in Run/Test Idle using one TCK cycle
* with TMS low. To keep the sequence length multiple of 8, 8 TCK cycle with
* TMS low are sent (allowed by JTAG state machine).
* Bits are stored (and transmitted) LSB-first.
*/
static const uint8_t swd_seq_dormant_to_jtag[] = {
/* At least 8 TCK/SWCLK cycles with TMS/SWDIO high */
0xff,
/* Selection alert sequence */
0x92, 0xf3, 0x09, 0x62, 0x95, 0x2d, 0x85, 0x86,
0xe9, 0xaf, 0xdd, 0xe3, 0xa2, 0x0e, 0xbc, 0x19,
/*
* 4 TCK/SWCLK cycles with TMS/SWDIO low ...
* + 12 bits JTAG-serial activation code 0x00, 0x00
*/
0x00, 0x00,
/* put the TAP in Run/Test Idle */
0x00,
};
static const unsigned swd_seq_dormant_to_jtag_len = 160;
enum swd_special_seq { enum swd_special_seq {
LINE_RESET, LINE_RESET,

View File

@ -894,7 +894,7 @@ static const struct command_registration jtag_subcommand_handlers[] = {
}, },
{ {
.name = "configure", .name = "configure",
.mode = COMMAND_EXEC, .mode = COMMAND_ANY,
.jim_handler = jim_jtag_configure, .jim_handler = jim_jtag_configure,
.help = "Provide a Tcl handler for the specified " .help = "Provide a Tcl handler for the specified "
"TAP event.", "TAP event.",

View File

@ -12,6 +12,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/eCos.c \ %D%/eCos.c \
%D%/linux.c \ %D%/linux.c \
%D%/ChibiOS.c \ %D%/ChibiOS.c \
%D%/chromium-ec.c \
%D%/embKernel.c \ %D%/embKernel.c \
%D%/mqx.c \ %D%/mqx.c \
%D%/riscv_debug.c \ %D%/riscv_debug.c \

387
src/rtos/chromium-ec.c Normal file
View File

@ -0,0 +1,387 @@
/*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright (c) 2018 National Instruments Corp
* Author: Moritz Fischer <moritz.fischer@ettus.com>
*
* Chromium-EC RTOS Task Awareness
*/
#include <rtos/rtos.h>
#include <target/target.h>
#include <target/target_type.h>
#include "rtos_standard_stackings.h"
#define CROS_EC_MAX_TASKS 32
#define CROS_EC_MAX_NAME 200
#define CROS_EC_IDLE_STRING "<< idle >>"
#define BIT(x) (1 << (x))
struct chromium_ec_params {
const char *target_name;
size_t ptr_size;
off_t task_offset_next;
off_t task_offset_sp;
off_t task_offset_events;
off_t task_offset_runtime;
const struct rtos_register_stacking *stacking;
};
static const struct chromium_ec_params chromium_ec_params_list[] = {
{
.target_name = "hla_target",
.ptr_size = 4,
.task_offset_next = 24,
.task_offset_sp = 0,
.task_offset_events = 4,
.task_offset_runtime = 8,
.stacking = &rtos_standard_Cortex_M3_stacking,
},
{
.target_name = "cortex_m",
.ptr_size = 4,
.task_offset_next = 24,
.task_offset_sp = 0,
.task_offset_events = 4,
.task_offset_runtime = 8,
.stacking = &rtos_standard_Cortex_M3_stacking,
},
};
static const char * const chromium_ec_symbol_list[] = {
"start_called",
"current_task",
"tasks",
"tasks_enabled",
"tasks_ready",
"task_names",
"build_info",
NULL,
};
enum chromium_ec_symbol_values {
CHROMIUM_EC_VAL_start_called = 0,
CHROMIUM_EC_VAL_current_task,
CHROMIUM_EC_VAL_tasks,
CHROMIUM_EC_VAL_tasks_enabled,
CHROMIUM_EC_VAL_tasks_ready,
CHROMIUM_EC_VAL_task_names,
CHROMIUM_EC_VAL_build_info,
CHROMIUM_EC_VAL_COUNT,
};
#define CROS_EC_MAX_BUILDINFO 512
static bool chromium_ec_detect_rtos(struct target *target)
{
char build_info_buf[CROS_EC_MAX_BUILDINFO];
enum chromium_ec_symbol_values sym;
int ret;
if (!target || !target->rtos || !target->rtos->symbols)
return false;
for (sym = CHROMIUM_EC_VAL_start_called;
sym < CHROMIUM_EC_VAL_COUNT; sym++) {
if (target->rtos->symbols[sym].address) {
LOG_DEBUG("Chromium-EC: Symbol \"%s\" found",
chromium_ec_symbol_list[sym]);
} else {
LOG_ERROR("Chromium-EC: Symbol \"%s\" missing",
chromium_ec_symbol_list[sym]);
return false;
}
}
ret = target_read_buffer(target,
target->rtos->symbols[CHROMIUM_EC_VAL_build_info].address,
sizeof(build_info_buf),
(uint8_t *)build_info_buf);
if (ret != ERROR_OK)
return false;
LOG_INFO("Chromium-EC: Buildinfo: %s", build_info_buf);
return target->rtos->symbols &&
target->rtos->symbols[CHROMIUM_EC_VAL_start_called].address;
}
static int chromium_ec_create(struct target *target)
{
struct chromium_ec_params *params;
size_t t;
for (t = 0; t < ARRAY_SIZE(chromium_ec_params_list); t++)
if (!strcmp(chromium_ec_params_list[t].target_name, target->type->name)) {
params = malloc(sizeof(*params));
if (!params) {
LOG_ERROR("Chromium-EC: out of memory");
return ERROR_FAIL;
}
memcpy(params, &chromium_ec_params_list[t], sizeof(*params));
target->rtos->rtos_specific_params = (void *)params;
target->rtos->current_thread = 0;
target->rtos->thread_details = NULL;
target->rtos->thread_count = 0;
LOG_INFO("Chromium-EC: Using target: %s", target->type->name);
return ERROR_OK;
}
LOG_ERROR("Chromium-EC: target not supported: %s", target->type->name);
return ERROR_FAIL;
}
static int chromium_ec_get_current_task_ptr(struct rtos *rtos, uint32_t *current_task)
{
if (!rtos || !rtos->symbols)
return ERROR_FAIL;
return target_read_u32(rtos->target,
rtos->symbols[CHROMIUM_EC_VAL_current_task].address,
current_task);
}
static int chromium_ec_get_num_tasks(struct rtos *rtos, int *num_tasks)
{
uint32_t tasks_enabled;
int ret, t, found;
ret = target_read_u32(rtos->target,
rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address,
&tasks_enabled);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to determine #of tasks");
return ret;
}
found = 0;
for (t = 0; t < CROS_EC_MAX_TASKS; t++)
if (tasks_enabled & BIT(t))
found++;
*num_tasks = found;
return ERROR_OK;
}
static int chromium_ec_update_threads(struct rtos *rtos)
{
uint32_t tasks_enabled, tasks_ready, start_called;
uint32_t current_task, thread_ptr, name_ptr;
char thread_str_buf[CROS_EC_MAX_NAME];
int ret, t, num_tasks, tasks_found;
struct chromium_ec_params *params;
uint8_t runtime_buf[8];
uint64_t runtime;
uint32_t events;
params = rtos->rtos_specific_params;
if (!params)
return ERROR_FAIL;
if (!rtos->symbols)
return ERROR_FAIL;
num_tasks = 0;
ret = chromium_ec_get_num_tasks(rtos, &num_tasks);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to get number of tasks");
return ret;
}
current_task = 0;
ret = chromium_ec_get_current_task_ptr(rtos, &current_task);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to get current task");
return ret;
}
LOG_DEBUG("Current task: %lx tasks_found: %d",
(unsigned long)current_task,
num_tasks);
/* set current task to what we read */
rtos->current_thread = current_task;
/* Nuke the old tasks */
rtos_free_threadlist(rtos);
/* One check if task switching has started ... */
start_called = 0;
ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_start_called].address,
&start_called);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to load start_called");
return ret;
}
if (!rtos->current_thread || !num_tasks || !start_called) {
num_tasks++;
rtos->thread_details = malloc(
sizeof(struct thread_detail) * num_tasks);
rtos->thread_details->threadid = 1;
rtos->thread_details->exists = true;
rtos->thread_details->extra_info_str = NULL;
rtos->thread_details->thread_name_str = strdup("Current Execution");
if (!num_tasks || !start_called) {
rtos->thread_count = 1;
return ERROR_OK;
}
} else {
/* create space for new thread details */
rtos->thread_details = malloc(
sizeof(struct thread_detail) * num_tasks);
}
tasks_enabled = 0;
ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_enabled].address,
&tasks_enabled);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to load tasks_enabled");
return ret;
}
tasks_ready = 0;
ret = target_read_u32(rtos->target, rtos->symbols[CHROMIUM_EC_VAL_tasks_ready].address,
&tasks_ready);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to load tasks_ready");
return ret;
}
thread_ptr = rtos->symbols[CHROMIUM_EC_VAL_tasks].address;
tasks_found = 0;
for (t = 0; t < CROS_EC_MAX_TASKS; t++) {
if (!(tasks_enabled & BIT(t)))
continue;
if (thread_ptr == current_task)
rtos->current_thread = thread_ptr;
rtos->thread_details[tasks_found].threadid = thread_ptr;
ret = target_read_u32(rtos->target,
rtos->symbols[CHROMIUM_EC_VAL_task_names].address +
params->ptr_size * t, &name_ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read name_ptr");
return ret;
}
/* read name buffer */
ret = target_read_buffer(rtos->target, name_ptr, CROS_EC_MAX_NAME,
(uint8_t *)thread_str_buf);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read task name");
return ret;
}
/* sanitize string, gdb chokes on "<< idle >>" */
if (thread_str_buf[CROS_EC_MAX_NAME - 1] != '\0')
thread_str_buf[CROS_EC_MAX_NAME - 1] = '\0';
if (!strncmp(thread_str_buf, CROS_EC_IDLE_STRING, CROS_EC_MAX_NAME))
rtos->thread_details[tasks_found].thread_name_str = strdup("IDLE");
else
rtos->thread_details[tasks_found].thread_name_str = strdup(thread_str_buf);
events = 0;
ret = target_read_u32(rtos->target,
thread_ptr + params->task_offset_events,
&events);
if (ret != ERROR_OK)
LOG_ERROR("Failed to get task %d's events", t);
/* this is a bit kludgy but will do for now */
ret = target_read_buffer(rtos->target,
thread_ptr + params->task_offset_runtime,
sizeof(runtime_buf), runtime_buf);
if (ret != ERROR_OK)
LOG_ERROR("Failed to get task %d's runtime", t);
runtime = target_buffer_get_u64(rtos->target, runtime_buf);
/* Priority is simply the positon in the array */
if (thread_ptr == current_task)
snprintf(thread_str_buf, sizeof(thread_str_buf),
"State: Running, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
t, events, runtime);
else
snprintf(thread_str_buf, sizeof(thread_str_buf),
"State: %s, Priority: %u, Events: %" PRIx32 ", Runtime: %" PRIu64 "\n",
tasks_ready & BIT(t) ? "Ready" : "Waiting", t,
events, runtime);
rtos->thread_details[tasks_found].extra_info_str = strdup(thread_str_buf);
rtos->thread_details[tasks_found].exists = true;
thread_ptr += params->task_offset_next;
tasks_found++;
}
rtos->thread_count = tasks_found;
return ERROR_OK;
}
static int chromium_ec_get_thread_reg_list(struct rtos *rtos,
threadid_t threadid,
struct rtos_reg **reg_list,
int *num_regs)
{
struct chromium_ec_params *params = rtos->rtos_specific_params;
uint32_t stack_ptr = 0;
int ret, t;
for (t = 0; t < rtos->thread_count; t++)
if (threadid == rtos->thread_details[t].threadid)
break;
/* if we didn't find threadid, bail */
if (t == rtos->thread_count)
return ERROR_FAIL;
ret = target_read_u32(rtos->target,
rtos->symbols[CHROMIUM_EC_VAL_tasks].address +
params->task_offset_next * t,
&stack_ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to load TCB");
return ret;
}
return rtos_generic_stack_read(rtos->target, params->stacking,
stack_ptr, reg_list, num_regs);
}
static int chromium_ec_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
{
size_t s;
*symbol_list = calloc(ARRAY_SIZE(chromium_ec_symbol_list),
sizeof(symbol_table_elem_t));
if (!(*symbol_list)) {
LOG_ERROR("Chromium-EC: out of memory");
return ERROR_FAIL;
}
for (s = 0; s < ARRAY_SIZE(chromium_ec_symbol_list); s++)
(*symbol_list)[s].symbol_name = chromium_ec_symbol_list[s];
return ERROR_OK;
}
const struct rtos_type chromium_ec_rtos = {
.name = "Chromium-EC",
.detect_rtos = chromium_ec_detect_rtos,
.create = chromium_ec_create,
.update_threads = chromium_ec_update_threads,
.get_thread_reg_list = chromium_ec_get_thread_reg_list,
.get_symbol_list_to_lookup = chromium_ec_get_symbol_list_to_lookup,
};

View File

@ -32,6 +32,7 @@ extern struct rtos_type ThreadX_rtos;
extern struct rtos_type eCos_rtos; extern struct rtos_type eCos_rtos;
extern struct rtos_type Linux_os; extern struct rtos_type Linux_os;
extern struct rtos_type ChibiOS_rtos; extern struct rtos_type ChibiOS_rtos;
extern struct rtos_type chromium_ec_rtos;
extern struct rtos_type embKernel_rtos; extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos; extern struct rtos_type mqx_rtos;
extern struct rtos_type uCOS_III_rtos; extern struct rtos_type uCOS_III_rtos;
@ -45,6 +46,7 @@ static struct rtos_type *rtos_types[] = {
&eCos_rtos, &eCos_rtos,
&Linux_os, &Linux_os,
&ChibiOS_rtos, &ChibiOS_rtos,
&chromium_ec_rtos,
&embKernel_rtos, &embKernel_rtos,
&mqx_rtos, &mqx_rtos,
&uCOS_III_rtos, &uCOS_III_rtos,

View File

@ -143,7 +143,8 @@ INTEL_IA32_SRC = \
ESIRISC_SRC = \ ESIRISC_SRC = \
%D%/esirisc.c \ %D%/esirisc.c \
%D%/esirisc_jtag.c %D%/esirisc_jtag.c \
%D%/esirisc_trace.c
%C%_libtarget_la_SOURCES += \ %C%_libtarget_la_SOURCES += \
%D%/algorithm.h \ %D%/algorithm.h \
@ -228,7 +229,8 @@ ESIRISC_SRC = \
%D%/arm_cti.h \ %D%/arm_cti.h \
%D%/esirisc.h \ %D%/esirisc.h \
%D%/esirisc_jtag.h \ %D%/esirisc_jtag.h \
%D%/esirisc_regs.h %D%/esirisc_regs.h \
%D%/esirisc_trace.h
include %D%/openrisc/Makefile.am include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am include %D%/riscv/Makefile.am

View File

@ -100,6 +100,7 @@ static int aarch64_restore_system_control_reg(struct target *target)
case ARM_MODE_ABT: case ARM_MODE_ABT:
case ARM_MODE_FIQ: case ARM_MODE_FIQ:
case ARM_MODE_IRQ: case ARM_MODE_IRQ:
case ARM_MODE_SYS:
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
break; break;
@ -172,6 +173,7 @@ static int aarch64_mmu_modify(struct target *target, int enable)
case ARM_MODE_ABT: case ARM_MODE_ABT:
case ARM_MODE_FIQ: case ARM_MODE_FIQ:
case ARM_MODE_IRQ: case ARM_MODE_IRQ:
case ARM_MODE_SYS:
instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0);
break; break;
@ -1032,6 +1034,7 @@ static int aarch64_post_debug_entry(struct target *target)
case ARM_MODE_ABT: case ARM_MODE_ABT:
case ARM_MODE_FIQ: case ARM_MODE_FIQ:
case ARM_MODE_IRQ: case ARM_MODE_IRQ:
case ARM_MODE_SYS:
instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0);
break; break;
@ -2824,6 +2827,7 @@ struct target_type aarch64_target = {
.deassert_reset = aarch64_deassert_reset, .deassert_reset = aarch64_deassert_reset,
/* REVISIT allow exporting VFP3 registers ... */ /* REVISIT allow exporting VFP3 registers ... */
.get_gdb_arch = armv8_get_gdb_arch,
.get_gdb_reg_list = armv8_get_gdb_reg_list, .get_gdb_reg_list = armv8_get_gdb_reg_list,
.read_memory = aarch64_read_memory, .read_memory = aarch64_read_memory,

View File

@ -72,8 +72,8 @@ static const char *dap_reg_name(int instr, int reg_addr)
case DP_RDBUFF: case DP_RDBUFF:
reg_name = "RDBUFF"; reg_name = "RDBUFF";
break; break;
case DP_WCR: case DP_DLCR:
reg_name = "WCR"; reg_name = "DLCR";
break; break;
default: default:
reg_name = "UNK"; reg_name = "UNK";
@ -726,52 +726,3 @@ const struct dap_ops jtag_dp_ops = {
.run = jtag_dp_run, .run = jtag_dp_run,
.sync = jtag_dp_sync, .sync = jtag_dp_sync,
}; };
static const uint8_t swd2jtag_bitseq[] = {
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching equence disables SWD and enables JTAG
* NOTE: bits in the DP's IDCODE can expose the need for
* the old/deprecated sequence (0xae 0xde).
*/
0x3c, 0xe7,
/* At least 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
* NOTE: some docs say "at least 5".
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/** Put the debug link into JTAG mode, if the target supports it.
* The link's initial mode may be either SWD or JTAG.
*
* @param target Enters JTAG mode (if possible).
*
* Note that targets implemented with SW-DP do not support JTAG, and
* that some targets which could otherwise support it may have been
* configured to disable JTAG signaling
*
* @return ERROR_OK or else a fault code.
*/
int dap_to_jtag(struct target *target)
{
int retval;
LOG_DEBUG("Enter JTAG mode");
/* REVISIT it's nasty to need to make calls to a "jtag"
* subsystem if the link isn't in JTAG mode...
*/
retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq),
swd2jtag_bitseq, TAP_RESET);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
/* REVISIT set up the DAP's ops vector for JTAG mode. */
return retval;
}

View File

@ -297,71 +297,6 @@ const struct dap_ops swd_dap_ops = {
.quit = swd_quit, .quit = swd_quit,
}; };
/*
* This represents the bits which must be sent out on TMS/SWDIO to
* switch a DAP implemented using an SWJ-DP module into SWD mode.
* These bits are stored (and transmitted) LSB-first.
*
* See the DAP-Lite specification, section 2.2.5 for information
* about making the debug link select SWD or JTAG. (Similar info
* is in a few other ARM documents.)
*/
static const uint8_t jtag2swd_bitseq[] = {
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* Switching sequence enables SWD and disables JTAG
* NOTE: bits in the DP's IDCODE may expose the need for
* an old/obsolete/deprecated sequence (0xb6 0xed).
*/
0x9e, 0xe7,
/* More than 50 TCK/SWCLK cycles with TMS/SWDIO high,
* putting both JTAG and SWD logic into reset state.
*/
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
/**
* Put the debug link into SWD mode, if the target supports it.
* The link's initial mode may be either JTAG (for example,
* with SWJ-DP after reset) or SWD.
*
* @param target Enters SWD mode (if possible).
*
* Note that targets using the JTAG-DP do not support SWD, and that
* some targets which could otherwise support it may have have been
* configured to disable SWD signaling
*
* @return ERROR_OK or else a fault code.
*/
int dap_to_swd(struct target *target)
{
struct arm *arm = target_to_arm(target);
int retval;
if (!arm->dap) {
LOG_ERROR("SWD mode is not available");
return ERROR_FAIL;
}
LOG_DEBUG("Enter SWD mode");
/* REVISIT it's ugly to need to make calls to a "jtag"
* subsystem if the link may not be in JTAG mode...
*/
retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq),
jtag2swd_bitseq, TAP_INVALID);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
/* set up the DAP's ops vector for SWD mode. */
arm->dap->ops = &swd_dap_ops;
return retval;
}
static const struct command_registration swd_commands[] = { static const struct command_registration swd_commands[] = {
{ {
/* /*

View File

@ -263,9 +263,11 @@ struct reg_cache *armv8_build_reg_cache(struct target *target);
extern const struct command_registration arm_command_handlers[]; extern const struct command_registration arm_command_handlers[];
int arm_arch_state(struct target *target); int arm_arch_state(struct target *target);
const char *arm_get_gdb_arch(struct target *target);
int arm_get_gdb_reg_list(struct target *target, int arm_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size, struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class); enum target_register_class reg_class);
const char *armv8_get_gdb_arch(struct target *target);
int armv8_get_gdb_reg_list(struct target *target, int armv8_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size, struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class); enum target_register_class reg_class);

View File

@ -1362,6 +1362,7 @@ struct target_type arm11_target = {
.assert_reset = arm11_assert_reset, .assert_reset = arm11_assert_reset,
.deassert_reset = arm11_deassert_reset, .deassert_reset = arm11_deassert_reset,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm11_read_memory, .read_memory = arm11_read_memory,

View File

@ -560,6 +560,7 @@ struct target_type arm720t_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm720t_soft_reset_halt, .soft_reset_halt = arm720t_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm720t_read_memory, .read_memory = arm720t_read_memory,

View File

@ -699,6 +699,7 @@ struct target_type arm7tdmi_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt, .soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory, .read_memory = arm7_9_read_memory,

View File

@ -1693,6 +1693,7 @@ struct target_type arm920t_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm920t_soft_reset_halt, .soft_reset_halt = arm920t_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm920t_read_memory, .read_memory = arm920t_read_memory,

View File

@ -804,6 +804,7 @@ struct target_type arm926ejs_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm926ejs_soft_reset_halt, .soft_reset_halt = arm926ejs_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory, .read_memory = arm7_9_read_memory,

View File

@ -756,6 +756,7 @@ struct target_type arm946e_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt, .soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
/* .read_memory = arm7_9_read_memory, */ /* .read_memory = arm7_9_read_memory, */

View File

@ -259,6 +259,7 @@ struct target_type arm966e_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt, .soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory, .read_memory = arm7_9_read_memory,

View File

@ -902,6 +902,7 @@ struct target_type arm9tdmi_target = {
.deassert_reset = arm7_9_deassert_reset, .deassert_reset = arm7_9_deassert_reset,
.soft_reset_halt = arm7_9_soft_reset_halt, .soft_reset_halt = arm7_9_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory, .read_memory = arm7_9_read_memory,

View File

@ -59,7 +59,7 @@
/* /*
* Relevant specifications from ARM include: * Relevant specifications from ARM include:
* *
* ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031A * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031E
* CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B
* *
* CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D
@ -73,6 +73,8 @@
#include "jtag/interface.h" #include "jtag/interface.h"
#include "arm.h" #include "arm.h"
#include "arm_adi_v5.h" #include "arm_adi_v5.h"
#include "jtag/swd.h"
#include "transport/transport.h"
#include <helper/jep106.h> #include <helper/jep106.h>
#include <helper/time_support.h> #include <helper/time_support.h>
#include <helper/list.h> #include <helper/list.h>
@ -788,6 +790,77 @@ int mem_ap_init(struct adiv5_ap *ap)
return ERROR_OK; return ERROR_OK;
} }
/**
* Put the debug link into SWD mode, if the target supports it.
* The link's initial mode may be either JTAG (for example,
* with SWJ-DP after reset) or SWD.
*
* Note that targets using the JTAG-DP do not support SWD, and that
* some targets which could otherwise support it may have been
* configured to disable SWD signaling
*
* @param dap The DAP used
* @return ERROR_OK or else a fault code.
*/
int dap_to_swd(struct adiv5_dap *dap)
{
int retval;
LOG_DEBUG("Enter SWD mode");
if (transport_is_jtag()) {
retval = jtag_add_tms_seq(swd_seq_jtag_to_swd_len,
swd_seq_jtag_to_swd, TAP_INVALID);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
return retval;
}
if (transport_is_swd()) {
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
return swd->switch_seq(JTAG_TO_SWD);
}
LOG_ERROR("Nor JTAG nor SWD transport");
return ERROR_FAIL;
}
/**
* Put the debug link into JTAG mode, if the target supports it.
* The link's initial mode may be either SWD or JTAG.
*
* Note that targets implemented with SW-DP do not support JTAG, and
* that some targets which could otherwise support it may have been
* configured to disable JTAG signaling
*
* @param dap The DAP used
* @return ERROR_OK or else a fault code.
*/
int dap_to_jtag(struct adiv5_dap *dap)
{
int retval;
LOG_DEBUG("Enter JTAG mode");
if (transport_is_jtag()) {
retval = jtag_add_tms_seq(swd_seq_swd_to_jtag_len,
swd_seq_swd_to_jtag, TAP_RESET);
if (retval == ERROR_OK)
retval = jtag_execute_queue();
return retval;
}
if (transport_is_swd()) {
const struct swd_driver *swd = adiv5_dap_swd_driver(dap);
return swd->switch_seq(SWD_TO_JTAG);
}
LOG_ERROR("Nor JTAG nor SWD transport");
return ERROR_FAIL;
}
/* CID interpretation -- see ARM IHI 0029B section 3 /* CID interpretation -- see ARM IHI 0029B section 3
* and ARM IHI 0031A table 13-3. * and ARM IHI 0031A table 13-3.
*/ */

View File

@ -516,10 +516,10 @@ int dap_lookup_cs_component(struct adiv5_ap *ap,
struct target; struct target;
/* Put debug link into SWD mode */ /* Put debug link into SWD mode */
int dap_to_swd(struct target *target); int dap_to_swd(struct adiv5_dap *dap);
/* Put debug link into JTAG mode */ /* Put debug link into JTAG mode */
int dap_to_jtag(struct target *target); int dap_to_jtag(struct adiv5_dap *dap);
extern const struct command_registration dap_instance_commands[]; extern const struct command_registration dap_instance_commands[];

View File

@ -173,7 +173,7 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel)
return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel));
} }
static uint32_t cti_regs[26]; static uint32_t cti_regs[28];
static const struct { static const struct {
uint32_t offset; uint32_t offset;
@ -206,6 +206,8 @@ static const struct {
{ CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] },
{ CTI_APPSET, "APPSET", &cti_regs[24] }, { CTI_APPSET, "APPSET", &cti_regs[24] },
{ CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, { CTI_APPCLEAR, "APPCLR", &cti_regs[25] },
{ CTI_APPPULSE, "APPPULSE", &cti_regs[26] },
{ CTI_INACK, "INACK", &cti_regs[27] },
}; };
static int cti_find_reg_offset(const char *name) static int cti_find_reg_offset(const char *name)
@ -216,6 +218,8 @@ static int cti_find_reg_offset(const char *name)
if (!strcmp(name, cti_names[i].label)) if (!strcmp(name, cti_names[i].label))
return cti_names[i].offset; return cti_names[i].offset;
} }
LOG_ERROR("unknown CTI register %s", name);
return -1; return -1;
} }
@ -297,7 +301,7 @@ COMMAND_HANDLER(handle_cti_write)
uint32_t value; uint32_t value;
if (CMD_ARGC != 2) { if (CMD_ARGC != 2) {
Jim_SetResultString(interp, "Wrong numer of args", -1); Jim_SetResultString(interp, "Wrong number of args", -1);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -320,7 +324,7 @@ COMMAND_HANDLER(handle_cti_read)
uint32_t value; uint32_t value;
if (CMD_ARGC != 1) { if (CMD_ARGC != 1) {
Jim_SetResultString(interp, "Wrong numer of args", -1); Jim_SetResultString(interp, "Wrong number of args", -1);
return ERROR_FAIL; return ERROR_FAIL;
} }

View File

@ -313,6 +313,11 @@ COMMAND_HANDLER(handle_dap_info_command)
struct adiv5_dap *dap = arm->dap; struct adiv5_dap *dap = arm->dap;
uint32_t apsel; uint32_t apsel;
if (dap == NULL) {
LOG_ERROR("DAP instance not available. Probably a HLA target...");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
switch (CMD_ARGC) { switch (CMD_ARGC) {
case 0: case 0:
apsel = dap->apsel; apsel = dap->apsel;

View File

@ -213,7 +213,7 @@
/* Breakpoint instruction (ARMv5) /* Breakpoint instruction (ARMv5)
* Im: 16-bit immediate * Im: 16-bit immediate
*/ */
#define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 8) | (Im & 0xf)) #define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 4) | (Im & 0xf))
/* Thumb mode instructions /* Thumb mode instructions

View File

@ -1134,6 +1134,7 @@ static const struct command_registration arm_exec_command_handlers[] = {
}, },
{ {
.name = "mrc", .name = "mrc",
.mode = COMMAND_EXEC,
.jim_handler = &jim_mcrmrc, .jim_handler = &jim_mcrmrc,
.help = "read coprocessor register", .help = "read coprocessor register",
.usage = "cpnum op1 CRn CRm op2", .usage = "cpnum op1 CRn CRm op2",
@ -1179,6 +1180,20 @@ const struct command_registration arm_command_handlers[] = {
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };
/*
* gdb for arm targets (e.g. arm-none-eabi-gdb) supports several variants
* of arm architecture. You can list them using the autocompletion of gdb
* command prompt by typing "set architecture " and then press TAB key.
* The default, selected automatically, is "arm".
* Let's use the default value, here, to make gdb-multiarch behave in the
* same way as a gdb for arm. This can be changed later on. User can still
* set the specific architecture variant with the gdb command.
*/
const char *arm_get_gdb_arch(struct target *target)
{
return "arm";
}
int arm_get_gdb_reg_list(struct target *target, int arm_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size, struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class) enum target_register_class reg_class)
@ -1340,6 +1355,8 @@ int armv4_5_run_algorithm_inner(struct target *target,
cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr = buf_get_u32(arm->cpsr->value, 0, 32);
for (i = 0; i < num_mem_params; i++) { for (i = 0; i < num_mem_params; i++) {
if (mem_params[i].direction == PARAM_IN)
continue;
retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size,
mem_params[i].value); mem_params[i].value);
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -1347,6 +1364,9 @@ int armv4_5_run_algorithm_inner(struct target *target,
} }
for (i = 0; i < num_reg_params; i++) { for (i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction == PARAM_IN)
continue;
struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0);
if (!reg) { if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);

View File

@ -72,7 +72,8 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
if ((first_lvl_descriptor & 0x3) == 0) { if ((first_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure"); /* Avoid LOG_ERROR, probably GDB is guessing the stack frame */
LOG_WARNING("Address translation failure [1]: va %8.8" PRIx32 "", va);
return ERROR_TARGET_TRANSLATION_FAULT; return ERROR_TARGET_TRANSLATION_FAULT;
} }
@ -103,7 +104,8 @@ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
if ((second_lvl_descriptor & 0x3) == 0) { if ((second_lvl_descriptor & 0x3) == 0) {
LOG_ERROR("Address translation failure"); /* Avoid LOG_ERROR, probably GDB is guessing the stack frame */
LOG_WARNING("Address translation failure [2]: va %8.8" PRIx32 "", va);
return ERROR_TARGET_TRANSLATION_FAULT; return ERROR_TARGET_TRANSLATION_FAULT;
} }

View File

@ -379,7 +379,8 @@ int armv7m_start_algorithm(struct target *target,
} }
for (int i = 0; i < num_mem_params; i++) { for (int i = 0; i < num_mem_params; i++) {
/* TODO: Write only out params */ if (mem_params[i].direction == PARAM_IN)
continue;
retval = target_write_buffer(target, mem_params[i].address, retval = target_write_buffer(target, mem_params[i].address,
mem_params[i].size, mem_params[i].size,
mem_params[i].value); mem_params[i].value);
@ -388,6 +389,9 @@ int armv7m_start_algorithm(struct target *target,
} }
for (int i = 0; i < num_reg_params; i++) { for (int i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction == PARAM_IN)
continue;
struct reg *reg = struct reg *reg =
register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0);
/* uint32_t regvalue; */ /* uint32_t regvalue; */
@ -407,6 +411,23 @@ int armv7m_start_algorithm(struct target *target,
armv7m_set_core_reg(reg, reg_params[i].value); armv7m_set_core_reg(reg, reg_params[i].value);
} }
{
/*
* Ensure xPSR.T is set to avoid trying to run things in arm
* (non-thumb) mode, which armv7m does not support.
*
* We do this by setting the entirety of xPSR, which should
* remove all the unknowns about xPSR state.
*
* Because xPSR.T is populated on reset from the vector table,
* it might be 0 if the vector table has "bad" data in it.
*/
struct reg *reg = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR];
buf_set_u32(reg->value, 0, 32, 0x01000000);
reg->valid = 1;
reg->dirty = 1;
}
if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY && if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY &&
armv7m_algorithm_info->core_mode != core_mode) { armv7m_algorithm_info->core_mode != core_mode) {

View File

@ -73,6 +73,10 @@ static const struct {
.name = "ABT", .name = "ABT",
.psr = ARM_MODE_ABT, .psr = ARM_MODE_ABT,
}, },
{
.name = "SYS",
.psr = ARM_MODE_SYS,
},
{ {
.name = "EL0T", .name = "EL0T",
.psr = ARMV8_64_EL0T, .psr = ARMV8_64_EL0T,
@ -1477,6 +1481,9 @@ static int armv8_get_core_reg32(struct reg *reg)
struct reg *reg64; struct reg *reg64;
int retval; int retval;
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
/* get the corresponding Aarch64 register */ /* get the corresponding Aarch64 register */
reg64 = cache->reg_list + armv8_reg->num; reg64 = cache->reg_list + armv8_reg->num;
if (reg64->valid) { if (reg64->valid) {
@ -1500,6 +1507,9 @@ static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf)
struct reg *reg64 = cache->reg_list + armv8_reg->num; struct reg *reg64 = cache->reg_list + armv8_reg->num;
uint32_t value = buf_get_u32(buf, 0, 32); uint32_t value = buf_get_u32(buf, 0, 32);
if (target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
if (reg64 == arm->cpsr) { if (reg64 == arm->cpsr) {
armv8_set_cpsr(arm, value); armv8_set_cpsr(arm, value);
} else { } else {
@ -1668,6 +1678,11 @@ const struct command_registration armv8_command_handlers[] = {
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };
const char *armv8_get_gdb_arch(struct target *target)
{
return "aarch64";
}
int armv8_get_gdb_reg_list(struct target *target, int armv8_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size, struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class) enum target_register_class reg_class)

View File

@ -573,6 +573,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
case ARM_MODE_ABT: case ARM_MODE_ABT:
case ARM_MODE_IRQ: case ARM_MODE_IRQ:
case ARM_MODE_FIQ: case ARM_MODE_FIQ:
case ARM_MODE_SYS:
target_el = 1; target_el = 1;
break; break;
/* /*
@ -790,6 +791,10 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm)
dpm->last_el != armv8_curel_from_core_mode(arm_reg->mode)) dpm->last_el != armv8_curel_from_core_mode(arm_reg->mode))
continue; continue;
/* Special case: ARM_MODE_SYS has no SPSR at EL1 */
if (r->number == ARMV8_SPSR_EL1 && arm->core_mode == ARM_MODE_SYS)
continue;
retval = dpmv8_read_reg(dpm, r, i); retval = dpmv8_read_reg(dpm, r, i);
if (retval != ERROR_OK) if (retval != ERROR_OK)
goto fail; goto fail;

View File

@ -202,6 +202,7 @@ static int cortex_a_mmu_modify(struct target *target, int enable)
static int cortex_a_init_debug_access(struct target *target) static int cortex_a_init_debug_access(struct target *target)
{ {
struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_common *armv7a = target_to_armv7a(target);
uint32_t dscr;
int retval; int retval;
/* lock memory-mapped access to debug registers to prevent /* lock memory-mapped access to debug registers to prevent
@ -231,6 +232,16 @@ static int cortex_a_init_debug_access(struct target *target)
/* Resync breakpoint registers */ /* Resync breakpoint registers */
/* Enable halt for breakpoint, watchpoint and vector catch */
retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR, &dscr);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE);
if (retval != ERROR_OK)
return retval;
/* Since this is likely called from init or reset, update target state information*/ /* Since this is likely called from init or reset, update target state information*/
return cortex_a_poll(target); return cortex_a_poll(target);
} }
@ -714,39 +725,26 @@ static int cortex_a_poll(struct target *target)
/* We have a halting debug event */ /* We have a halting debug event */
LOG_DEBUG("Target halted"); LOG_DEBUG("Target halted");
target->state = TARGET_HALTED; target->state = TARGET_HALTED;
if ((prev_target_state == TARGET_RUNNING)
|| (prev_target_state == TARGET_UNKNOWN) retval = cortex_a_debug_entry(target);
|| (prev_target_state == TARGET_RESET)) { if (retval != ERROR_OK)
retval = cortex_a_debug_entry(target); return retval;
if (target->smp) {
retval = update_halt_gdb(target);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
if (target->smp) { }
retval = update_halt_gdb(target);
if (retval != ERROR_OK)
return retval;
}
if (prev_target_state == TARGET_DEBUG_RUNNING) {
target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED);
} else { /* prev_target_state is RUNNING, UNKNOWN or RESET */
if (arm_semihosting(target, &retval) != 0) if (arm_semihosting(target, &retval) != 0)
return retval; return retval;
target_call_event_callbacks(target, target_call_event_callbacks(target,
TARGET_EVENT_HALTED); TARGET_EVENT_HALTED);
} }
if (prev_target_state == TARGET_DEBUG_RUNNING) {
LOG_DEBUG(" ");
retval = cortex_a_debug_entry(target);
if (retval != ERROR_OK)
return retval;
if (target->smp) {
retval = update_halt_gdb(target);
if (retval != ERROR_OK)
return retval;
}
target_call_event_callbacks(target,
TARGET_EVENT_DEBUG_HALTED);
}
} }
} else } else
target->state = TARGET_RUNNING; target->state = TARGET_RUNNING;
@ -769,19 +767,6 @@ static int cortex_a_halt(struct target *target)
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
/*
* enter halting debug mode
*/
retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR, &dscr);
if (retval != ERROR_OK)
return retval;
retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE);
if (retval != ERROR_OK)
return retval;
int64_t then = timeval_ms(); int64_t then = timeval_ms();
for (;; ) { for (;; ) {
retval = mem_ap_read_atomic_u32(armv7a->debug_ap, retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
@ -2889,7 +2874,20 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
static void cortex_a_deinit_target(struct target *target) static void cortex_a_deinit_target(struct target *target)
{ {
struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct arm_dpm *dpm = &cortex_a->armv7a_common.dpm; struct armv7a_common *armv7a = &cortex_a->armv7a_common;
struct arm_dpm *dpm = &armv7a->dpm;
uint32_t dscr;
int retval;
if (target_was_examined(target)) {
/* Disable halt for breakpoint, watchpoint and vector catch */
retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR, &dscr);
if (retval == ERROR_OK)
mem_ap_write_atomic_u32(armv7a->debug_ap,
armv7a->debug_base + CPUDBG_DSCR,
dscr & ~DSCR_HALT_DBG_MODE);
}
free(cortex_a->brp_list); free(cortex_a->brp_list);
free(dpm->dbp); free(dpm->dbp);
@ -3160,6 +3158,7 @@ struct target_type cortexa_target = {
.deassert_reset = cortex_a_deassert_reset, .deassert_reset = cortex_a_deassert_reset,
/* REVISIT allow exporting VFP3 registers ... */ /* REVISIT allow exporting VFP3 registers ... */
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = cortex_a_read_memory, .read_memory = cortex_a_read_memory,
@ -3239,6 +3238,7 @@ struct target_type cortexr4_target = {
.deassert_reset = cortex_a_deassert_reset, .deassert_reset = cortex_a_deassert_reset,
/* REVISIT allow exporting VFP3 registers ... */ /* REVISIT allow exporting VFP3 registers ... */
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = arm_get_gdb_reg_list, .get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = cortex_a_read_phys_memory, .read_memory = cortex_a_read_phys_memory,

View File

@ -510,7 +510,10 @@ static int cortex_m_poll(struct target *target)
} }
if (cortex_m->dcb_dhcsr & S_RESET_ST) { if (cortex_m->dcb_dhcsr & S_RESET_ST) {
target->state = TARGET_RESET; if (target->state != TARGET_RESET) {
target->state = TARGET_RESET;
LOG_INFO("%s: external reset detected", target_name(target));
}
return ERROR_OK; return ERROR_OK;
} }
@ -564,6 +567,17 @@ static int cortex_m_poll(struct target *target)
} }
} }
/* Check that target is truly halted, since the target could be resumed externally */
if ((prev_target_state == TARGET_HALTED) && !(cortex_m->dcb_dhcsr & S_HALT)) {
/* registers are now invalid */
register_cache_invalidate(armv7m->arm.core_cache);
target->state = TARGET_RUNNING;
LOG_WARNING("%s: external resume detected", target_name(target));
target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
retval = ERROR_OK;
}
/* Did we detect a failure condition that we cleared? */ /* Did we detect a failure condition that we cleared? */
if (detected_failure != ERROR_OK) if (detected_failure != ERROR_OK)
retval = detected_failure; retval = detected_failure;
@ -863,10 +877,17 @@ static int cortex_m_step(struct target *target, int current,
else { else {
/* Set a temporary break point */ /* Set a temporary break point */
if (breakpoint) if (breakpoint) {
retval = cortex_m_set_breakpoint(target, breakpoint); retval = cortex_m_set_breakpoint(target, breakpoint);
else } else {
retval = breakpoint_add(target, pc_value, 2, BKPT_HARD); enum breakpoint_type type = BKPT_HARD;
if (cortex_m->fp_rev == 0 && pc_value > 0x1FFFFFFF) {
/* FPB rev.1 cannot handle such addr, try BKPT instr */
type = BKPT_SOFT;
}
retval = breakpoint_add(target, pc_value, 2, type);
}
bool tmp_bp_set = (retval == ERROR_OK); bool tmp_bp_set = (retval == ERROR_OK);
/* No more breakpoints left, just do a step */ /* No more breakpoints left, just do a step */
@ -1041,10 +1062,18 @@ static int cortex_m_assert_reset(struct target *target)
retval = ERROR_OK; retval = ERROR_OK;
} else { } else {
/* Use a standard Cortex-M3 software reset mechanism. /* Use a standard Cortex-M3 software reset mechanism.
* We default to using VECRESET as it is supported on all current cores. * We default to using VECRESET as it is supported on all current cores
* (except Cortex-M0, M0+ and M1 which support SYSRESETREQ only!)
* This has the disadvantage of not resetting the peripherals, so a * This has the disadvantage of not resetting the peripherals, so a
* reset-init event handler is needed to perform any peripheral resets. * reset-init event handler is needed to perform any peripheral resets.
*/ */
if (!cortex_m->vectreset_supported
&& reset_config == CORTEX_M_RESET_VECTRESET) {
reset_config = CORTEX_M_RESET_SYSRESETREQ;
LOG_WARNING("VECTRESET is not supported on this Cortex-M core, using SYSRESETREQ instead.");
LOG_WARNING("Set 'cortex_m reset_config sysresetreq'.");
}
LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ) LOG_DEBUG("Using Cortex-M %s", (reset_config == CORTEX_M_RESET_SYSRESETREQ)
? "SYSRESETREQ" : "VECTRESET"); ? "SYSRESETREQ" : "VECTRESET");
@ -2027,6 +2056,9 @@ int cortex_m_examine(struct target *target)
} }
LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid);
/* VECTRESET is not supported on Cortex-M0, M0+ and M1 */
cortex_m->vectreset_supported = i > 1;
if (i == 4) { if (i == 4) {
target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR0, &mvfr0);
target_read_u32(target, MVFR1, &mvfr1); target_read_u32(target, MVFR1, &mvfr1);
@ -2244,14 +2276,19 @@ static int cortex_m_init_arch_info(struct target *target,
static int cortex_m_target_create(struct target *target, Jim_Interp *interp) static int cortex_m_target_create(struct target *target, Jim_Interp *interp)
{ {
struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
cortex_m->common_magic = CORTEX_M_COMMON_MAGIC;
struct adiv5_private_config *pc; struct adiv5_private_config *pc;
pc = (struct adiv5_private_config *)target->private_config; pc = (struct adiv5_private_config *)target->private_config;
if (adiv5_verify_config(pc) != ERROR_OK) if (adiv5_verify_config(pc) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
struct cortex_m_common *cortex_m = calloc(1, sizeof(struct cortex_m_common));
if (cortex_m == NULL) {
LOG_ERROR("No memory creating target");
return ERROR_FAIL;
}
cortex_m->common_magic = CORTEX_M_COMMON_MAGIC;
cortex_m->apsel = pc->ap_num; cortex_m->apsel = pc->ap_num;
cortex_m_init_arch_info(target, cortex_m, pc->dap); cortex_m_init_arch_info(target, cortex_m, pc->dap);
@ -2418,8 +2455,16 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command)
if (CMD_ARGC > 0) { if (CMD_ARGC > 0) {
if (strcmp(*CMD_ARGV, "sysresetreq") == 0) if (strcmp(*CMD_ARGV, "sysresetreq") == 0)
cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ;
else if (strcmp(*CMD_ARGV, "vectreset") == 0)
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; else if (strcmp(*CMD_ARGV, "vectreset") == 0) {
if (target_was_examined(target)
&& !cortex_m->vectreset_supported)
LOG_WARNING("VECTRESET is not supported on your Cortex-M core!");
else
cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET;
} else
return ERROR_COMMAND_SYNTAX_ERROR;
} }
switch (cortex_m->soft_reset_config) { switch (cortex_m->soft_reset_config) {
@ -2461,7 +2506,7 @@ static const struct command_registration cortex_m_exec_command_handlers[] = {
.handler = handle_cortex_m_reset_config_command, .handler = handle_cortex_m_reset_config_command,
.mode = COMMAND_ANY, .mode = COMMAND_ANY,
.help = "configure software reset handling", .help = "configure software reset handling",
.usage = "['srst'|'sysresetreq'|'vectreset']", .usage = "['sysresetreq'|'vectreset']",
}, },
COMMAND_REGISTRATION_DONE COMMAND_REGISTRATION_DONE
}; };
@ -2499,6 +2544,7 @@ struct target_type cortexm_target = {
.deassert_reset = cortex_m_deassert_reset, .deassert_reset = cortex_m_deassert_reset,
.soft_reset_halt = cortex_m_soft_reset_halt, .soft_reset_halt = cortex_m_soft_reset_halt,
.get_gdb_arch = arm_get_gdb_arch,
.get_gdb_reg_list = armv7m_get_gdb_reg_list, .get_gdb_reg_list = armv7m_get_gdb_reg_list,
.read_memory = cortex_m_read_memory, .read_memory = cortex_m_read_memory,

View File

@ -184,6 +184,7 @@ struct cortex_m_common {
struct reg_cache *dwt_cache; struct reg_cache *dwt_cache;
enum cortex_m_soft_reset_config soft_reset_config; enum cortex_m_soft_reset_config soft_reset_config;
bool vectreset_supported;
enum cortex_m_isrmasking_mode isrmasking_mode; enum cortex_m_isrmasking_mode isrmasking_mode;

View File

@ -1387,6 +1387,8 @@ static int dsp563xx_run_algorithm(struct target *target,
} }
for (i = 0; i < num_mem_params; i++) { for (i = 0; i < num_mem_params; i++) {
if (mem_params[i].direction == PARAM_IN)
continue;
retval = target_write_buffer(target, mem_params[i].address, retval = target_write_buffer(target, mem_params[i].address,
mem_params[i].size, mem_params[i].value); mem_params[i].size, mem_params[i].value);
if (retval != ERROR_OK) if (retval != ERROR_OK)
@ -1394,6 +1396,9 @@ static int dsp563xx_run_algorithm(struct target *target,
} }
for (i = 0; i < num_reg_params; i++) { for (i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction == PARAM_IN)
continue;
struct reg *reg = register_get_by_name(dsp563xx->core_cache, struct reg *reg = register_get_by_name(dsp563xx->core_cache,
reg_params[i].reg_name, reg_params[i].reg_name,
0); 0);

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