diff --git a/HACKING b/HACKING index b1d224dbf6..34d5745716 100644 --- a/HACKING +++ b/HACKING @@ -195,7 +195,9 @@ git remote add review https://USERNAME:PASSWORD@review.openocd.org/p/openocd.git Gerrit server, even if you plan to use several local branches for different topics. It is possible because @c for/master is not a traditional Git branch. - -# You will need to install this hook, we will look into a better solution: + -# You will need to install this hook to automatically add the + field "Change-Id:" in the commit message, as required by Gerrit. + We will look into a better solution: @code wget https://review.openocd.org/tools/hooks/commit-msg mv commit-msg .git/hooks @@ -272,6 +274,12 @@ doc: fix typos @code git pull --rebase origin master @endcode + +-# When you create a new version of an old patch, check that the new patch + keeps the same 'Change-Id:' field of the old patch. + This allows the Gerrit server to recognize the patch as a new version of + the older one and keeps track of the history and the review process. + -# Send the patches to the Gerrit server for review: @code git push review diff --git a/LICENSES/dual/CC-BY-4.0 b/LICENSES/dual/CC-BY-4.0 new file mode 100644 index 0000000000..e20b7a455e --- /dev/null +++ b/LICENSES/dual/CC-BY-4.0 @@ -0,0 +1,409 @@ +Valid-License-Identifier: CC-BY-4.0 +SPDX-URL: https://spdx.org/licenses/CC-BY-4.0 +Usage-Guide: + Do NOT use on OpenOCD code. This license is not GPL2 compatible. It may only + be used for dual-licensed files where the other license is GPL2 compatible. + If you end up using this it MUST be used together with a GPL2 compatible + license using "OR". + To use the Creative Commons Attribution 4.0 International license put + the following SPDX tag/value pair into a comment according to the + placement guidelines in the licensing rules documentation: + SPDX-License-Identifier: CC-BY-4.0 +License-Text: + +Creative Commons Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the "Licensor." The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/LICENSES/license-rules.txt b/LICENSES/license-rules.txt index ecc8e4db16..66aaaa5b4d 100644 --- a/LICENSES/license-rules.txt +++ b/LICENSES/license-rules.txt @@ -187,7 +187,21 @@ OpenOCD, can be broken down into: License-Text: Full license text -2. Exceptions: +2. Dual Licensing Only: + + These licenses should only be used to dual license code with another + license in addition to a preferred license. These licenses are available + from the directory:: + + LICENSES/dual/ + + in the OpenOCD source tree. + + The files in this directory contain the full license text and + `Metatags`_. The file names are identical to the SPDX license + identifier which shall be used for the license in source files. + +3. Exceptions: Some licenses can be amended with exceptions which grant certain rights which the original license does not. These exceptions are available @@ -244,7 +258,7 @@ OpenOCD, can be broken down into: License-Text: Full license text -3. Stand-alone licenses: +4. Stand-alone licenses: These licenses should only be used for stand-alone applications that are distributed with OpenOCD but are not included in the OpenOCD binary. diff --git a/LICENSES/preferred/GFDL-1.2 b/LICENSES/preferred/GFDL-1.2 index 9217d9c8ec..ded6f4d453 100644 --- a/LICENSES/preferred/GFDL-1.2 +++ b/LICENSES/preferred/GFDL-1.2 @@ -18,7 +18,7 @@ License-Text: Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/LICENSES/preferred/GPL-2.0 b/LICENSES/preferred/GPL-2.0 index 687bdddb11..25d8343cd0 100644 --- a/LICENSES/preferred/GPL-2.0 +++ b/LICENSES/preferred/GPL-2.0 @@ -15,7 +15,7 @@ License-Text: Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -317,8 +317,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + with this program; if not, see . Also add information on how to contact you by electronic and paper mail. diff --git a/LICENSES/preferred/LGPL-2.1 b/LICENSES/preferred/LGPL-2.1 index 8738a8d578..b19c23d17c 100644 --- a/LICENSES/preferred/LGPL-2.1 +++ b/LICENSES/preferred/LGPL-2.1 @@ -16,7 +16,7 @@ GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -486,9 +486,9 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License -along with this library; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add -information on how to contact you by electronic and paper mail. +along with this library; if not, see . + +Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if diff --git a/Makefile.am b/Makefile.am index 271a2c1654..845543721d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# not a GNU package. You can remove this line, if -# have all needed files, that a GNU package needs -AUTOMAKE_OPTIONS = gnu 1.6 +AUTOMAKE_OPTIONS = gnu 1.14 .DELETE_ON_ERROR: @@ -10,7 +8,7 @@ AUTOMAKE_OPTIONS = gnu 1.6 AM_DISTCHECK_CONFIGURE_FLAGS = --disable-install-jim # do not run Jim Tcl tests (esp. during distcheck) -check-recursive: SUBDIRS := +check-recursive: SUBDIRS := $(SUBDIRS:jimtcl=) nobase_dist_pkgdata_DATA = \ contrib/libdcc/dcc_stdio.c \ @@ -36,6 +34,9 @@ EXTRA_DIST += jimtcl/configure.gnu DISTCLEANFILES += jimtcl/jsmn/jsmn.o endif +SUBDIRS += testing +DIST_SUBDIRS += testing + # common flags used in openocd build AM_CFLAGS = $(GCC_WARNINGS) AM_LDFLAGS = @@ -67,6 +68,7 @@ EXTRA_DIST += \ $(EXTRA_DIST_NEWS) \ Doxyfile.in \ LICENSES/license-rules.txt \ + LICENSES/dual/CC-BY-4.0 \ LICENSES/exceptions/eCos-exception-2.0 \ LICENSES/preferred/BSD-1-Clause \ LICENSES/preferred/BSD-2-Clause \ diff --git a/README b/README index 875c85de3b..73aa3a6301 100644 --- a/README +++ b/README @@ -191,6 +191,11 @@ and compiling the OpenOCD source code. That file is provided by default for all GNU autotools packages. If you are not familiar with the GNU autotools, then you should read those instructions first. +Note: if the INSTALL file is not present, it means you are using the +source code from a development branch, not from an OpenOCD release. +In this case, follow the instructions 'Compiling OpenOCD' below and +the file will be created by the first command './bootstrap'. + The remainder of this document tries to provide some instructions for those looking for a quick-install. diff --git a/README.Windows b/README.Windows index 64bf5c0c6f..293eed975c 100644 --- a/README.Windows +++ b/README.Windows @@ -10,18 +10,6 @@ host. See README for the generic instructions. Also, the MSYS2 project provides both ready-made binaries and an easy way to self-compile from their software repository out of the box. -Native MinGW-w64/MSYS compilation ------------------------------ - -As MSYS doesn't come with pkg-config pre-installed, you need to add it -manually. The easiest way to do that is to download pkg-config-lite -from: - - http://sourceforge.net/projects/pkgconfiglite/ - -Then simply unzip the archive to the root directory of your MinGW-w64 -installation. - USB adapters ------------ diff --git a/configure.ac b/configure.ac index c026e14a1c..d563f2b668 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,6 @@ AC_LANG([C]) AC_PROG_CC # autoconf 2.70 obsoletes AC_PROG_CC_C99 and includes it in AC_PROG_CC m4_version_prereq([2.70],[],[AC_PROG_CC_C99]) -AM_PROG_CC_C_O AC_PROG_RANLIB # If macro PKG_PROG_PKG_CONFIG is not available, Autoconf generates a misleading error message, @@ -63,11 +62,14 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int v = __GLIBC_ AC_MSG_RESULT($have_glibc) AC_CHECK_HEADERS([fcntl.h]) +AC_CHECK_HEADERS([linux/pci.h]) +AC_CHECK_HEADERS([linux/spi/spidev.h]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([poll.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) +AC_CHECK_HEADERS([sys/mman.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/select.h]) AC_CHECK_HEADERS([sys/stat.h]) @@ -129,6 +131,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], [-])]) m4_define([USB1_ADAPTERS], [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]], [[ftdi_cjtag], [cJTAG (OScan1, JScan3) tunneled thru MPSSE], [FTDI_CJTAG]], + [[ch347], [CH347 based devices], [CH347]], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], @@ -165,6 +168,9 @@ m4_define([LIBFTDI_USB1_ADAPTERS], m4_define([LIBGPIOD_ADAPTERS], [[[linuxgpiod], [Linux GPIO bitbang through libgpiod], [LINUXGPIOD]]]) +m4_define([DMEM_ADAPTER], + [[[dmem], [CoreSight Direct Memory], [DMEM]]]) + m4_define([SYSFSGPIO_ADAPTER], [[[sysfsgpio], [Linux GPIO bitbang through sysfs], [SYSFSGPIO]]]) @@ -174,12 +180,15 @@ m4_define([REMOTE_BITBANG_ADAPTER], m4_define([LIBJAYLINK_ADAPTERS], [[[jlink], [SEGGER J-Link Programmer], [JLINK]]]) -m4_define([PCIE_ADAPTERS], - [[[xlnx_pcie_xvc], [Xilinx XVC/PCIe], [XLNX_PCIE_XVC]]]) +m4_define([XVC_ADAPTERS], + [[[xlnx_xvc], [Xilinx XVC PCIe and AXI drives], [XLNX_XVC]]]) m4_define([SERIAL_PORT_ADAPTERS], [[[buspirate], [Bus Pirate], [BUS_PIRATE]]]) +m4_define([PARALLEL_PORT_ADAPTER], + [[[parport], [PC Parallel Port], [PARPORT]]]) + m4_define([LINUXSPIDEV_ADAPTER], [[[linuxspidev], [Linux spidev driver], [LINUXSPIDEV]]]) m4_define([VDEBUG_ADAPTER], @@ -197,8 +206,18 @@ m4_define([RSHIM_ADAPTER], m4_define([AMTJTAGACCEL_ADAPTER], [[[amtjtagaccel], [Amontec JTAG-Accelerator driver], [AMTJTAGACCEL]]]) -# The word 'Adapter' in "Dummy Adapter" below must begin with a capital letter -# because there is an M4 macro called 'adapter'. +m4_define([CMSIS_DAP_TCP_ADAPTER], + [[[cmsis_dap_tcp], [CMSIS-DAP v2 compliant dongle (TCP)], [CMSIS_DAP_TCP]]]) + +m4_define([HOST_ARM_BITBANG_ADAPTERS], + [[[ep93xx], [Bitbanging on EP93xx-based SBCs], [EP93XX]], + [[at91rm9200], [Bitbanging on AT91RM9200-based SBCs], [AT91RM9200]]]) + +m4_define([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], + [[[bcm2835gpio], [Bitbanging on BCM2835 (as found in Raspberry Pi)], [BCM2835GPIO]], + [[imx_gpio], [Bitbanging on NXP IMX processors], [IMX_GPIO]], + [[am335xgpio], [Bitbanging on AM335x (as found in Beaglebones)], [AM335XGPIO]]]) + m4_define([DUMMY_ADAPTER], [[[dummy], [Dummy Adapter], [DUMMY]]]) @@ -249,34 +268,21 @@ AS_IF([test "x$enable_gcov" = "xyes"], [ AC_DEFINE([USE_GCOV], [0], [0 to leave coverage collection disabled.]) ]) -# set default verbose options, overridden by following options -debug_usb_io=no +# set default for debug_usb_comms, overridden by following options debug_usb_comms=no AC_ARG_ENABLE([verbose], AS_HELP_STRING([--enable-verbose], [Enable verbose JTAG I/O messages (for debugging).]), [ - debug_usb_io=$enableval debug_usb_comms=$enableval ], []) -AC_ARG_ENABLE([verbose_usb_io], - AS_HELP_STRING([--enable-verbose-usb-io], - [Enable verbose USB I/O messages (for debugging)]), - [debug_usb_io=$enableval], []) - AC_ARG_ENABLE([verbose_usb_comms], AS_HELP_STRING([--enable-verbose-usb-comms], [Enable verbose USB communication messages (for debugging)]), [debug_usb_comms=$enableval], []) -AC_MSG_CHECKING([whether to enable verbose USB I/O messages]); -AC_MSG_RESULT([$debug_usb_io]) -AS_IF([test "x$debug_usb_io" = "xyes"], [ - AC_DEFINE([_DEBUG_USB_IO_],[1], [Print verbose USB I/O messages]) -]) - AC_MSG_CHECKING([whether to enable verbose USB communication messages]); AC_MSG_RESULT([$debug_usb_comms]) AS_IF([test "x$debug_usb_comms" = "xyes"], [ @@ -295,20 +301,16 @@ AS_IF([test "x$debug_malloc" = "xyes" -a "x$have_glibc" = "xyes"], [ AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging]) ]) -AC_ARG_ENABLE([dmem], - AS_HELP_STRING([--enable-dmem], [Enable building the dmem driver]), - [build_dmem=$enableval], [build_dmem=no]) - m4_define([AC_ARG_ADAPTERS], [ - m4_foreach([adapter], [$1], - [AC_ARG_ENABLE(ADAPTER_OPT([adapter]), - AS_HELP_STRING([--enable-ADAPTER_OPT([adapter])[[[=yes/no/auto]]]], - [Enable building support for the ]ADAPTER_DESC([adapter])[ (default is $2)]), + m4_foreach([adapter_driver], [$1], + [AC_ARG_ENABLE(ADAPTER_OPT([adapter_driver]), + AS_HELP_STRING([--enable-ADAPTER_OPT([adapter_driver])[[[=yes/no/auto]]]], + [Enable building support for the ]ADAPTER_DESC([adapter_driver])[ (default is $2)]), [case "${enableval}" in yes|no|auto) ;; - *) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapter]) has invalid value "${enableval}".]) ;; + *) AC_MSG_ERROR([Option --enable-ADAPTER_OPT([adapter_driver]) has invalid value "${enableval}".]) ;; esac], - [ADAPTER_VAR([adapter])=$2]) + [ADAPTER_VAR([adapter_driver])=$2]) ]) ]) @@ -319,6 +321,7 @@ AC_ARG_ADAPTERS([ LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + DMEM_ADAPTER, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, LINUXSPIDEV_ADAPTER, @@ -328,14 +331,25 @@ AC_ARG_ADAPTERS([ JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, - AMTJTAGACCEL_ADAPTER, - PCIE_ADAPTERS, - LIBJAYLINK_ADAPTERS + XVC_ADAPTERS, + LIBJAYLINK_ADAPTERS, + CMSIS_DAP_TCP_ADAPTER ],[auto]) -AC_ARG_ENABLE([parport], - AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), - [build_parport=$enableval], [build_parport=no]) +AC_ARG_ADAPTERS([ + PARALLEL_PORT_ADAPTER, + AMTJTAGACCEL_ADAPTER + ],[no]) + +# The following adapters use bitbanging and can actually be built on all architectures, +# which is useful to verify that they still build fine. +# We could enable them automatically only on the architectures where they actually occur: +# HOST_ARM_BITBANG_ADAPTERS: when ${host_cpu} matches arm* +# HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS: when ${host_cpu} matches arm*|aarch64 +# However, conditionally changing the meaning of 'auto' requires +# a more flexible logic around. +AC_ARG_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS],[no]) +AC_ARG_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS],[no]) AC_ARG_ENABLE([parport_ppdev], AS_HELP_STRING([--disable-parport-ppdev], @@ -344,42 +358,9 @@ AC_ARG_ENABLE([parport_ppdev], AC_ARG_ENABLE([parport_giveio], AS_HELP_STRING([--enable-parport-giveio], - [Enable use of giveio for parport (for CygWin only)]), + [Enable use of giveio for parport (deprecated, for CygWin only)]), [parport_use_giveio=$enableval], [parport_use_giveio=]) -AS_CASE(["${host_cpu}"], - [arm*|aarch64], [ - AC_ARG_ENABLE([bcm2835gpio], - AS_HELP_STRING([--enable-bcm2835gpio], [Enable building support for bitbanging on BCM2835 (as found in Raspberry Pi)]), - [build_bcm2835gpio=$enableval], [build_bcm2835gpio=no]) - AC_ARG_ENABLE([imx_gpio], - AS_HELP_STRING([--enable-imx_gpio], [Enable building support for bitbanging on NXP IMX processors]), - [build_imx_gpio=$enableval], [build_imx_gpio=no]) - AC_ARG_ENABLE([am335xgpio], - AS_HELP_STRING([--enable-am335xgpio], [Enable building support for bitbanging on AM335x (as found in Beaglebones)]), - [build_am335xgpio=$enableval], [build_am335xgpio=no]) - ], - [ - build_bcm2835gpio=no - build_imx_gpio=no - build_am335xgpio=no -]) - -AS_CASE(["${host_cpu}"], - [arm*], [ - AC_ARG_ENABLE([ep93xx], - AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]), - [build_ep93xx=$enableval], [build_ep93xx=no]) - - AC_ARG_ENABLE([at91rm9200], - AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]), - [build_at91rm9200=$enableval], [build_at91rm9200=no]) - ], - [ - build_ep93xx=no - build_at91rm9200=no -]) - AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) @@ -401,7 +382,7 @@ AS_CASE([$host_os], ]) ]) - AS_IF([test "x$build_dmem" = "xyes"], [ + AS_IF([test "x$enable_dmem" = "xyes"], [ AC_MSG_ERROR([dmem is only available on linux]) ]) ]) @@ -423,9 +404,8 @@ AS_CASE(["${host_cpu}"], [i?86|x86*], [], [ AS_IF([test "x$parport_use_ppdev" = "xno"], [ - AC_MSG_WARN([--disable-parport-ppdev is not supported by the host CPU]) + AC_MSG_ERROR([--disable-parport-ppdev is not supported by the host CPU]) ]) - parport_use_ppdev=yes ]) can_build_buspirate=yes @@ -446,7 +426,7 @@ AS_CASE([$host_os], ], [ is_cygwin=yes # sys/io.h needed under cygwin for parport access - AS_IF([test "x$build_parport" = "xyes"], [ + AS_IF([test "x$enable_parport" != "xno"], [ AC_CHECK_HEADERS([sys/io.h],[],AC_MSG_ERROR([Please install the cygwin ioperm package])) ]) ]) @@ -509,58 +489,10 @@ AS_IF([test "x$is_darwin" = "xyes"], [ AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ]) -AS_IF([test "x$build_parport" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_PARPORT], [1], [1 if you want parport.]) -], [ - AC_DEFINE([BUILD_PARPORT], [0], [0 if you don't want parport.]) -]) - -AS_IF([test "x$build_dmem" = "xyes"], [ - AC_DEFINE([BUILD_DMEM], [1], [1 if you want to debug via Direct Mem.]) -], [ - AC_DEFINE([BUILD_DMEM], [0], [0 if you don't want to debug via Direct Mem.]) -]) - AS_IF([test "x$ADAPTER_VAR([dummy])" != "xno"], [ build_bitbang=yes ]) -AS_IF([test "x$build_ep93xx" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_EP93XX], [1], [1 if you want ep93xx.]) -], [ - AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) -]) - -AS_IF([test "x$build_at91rm9200" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) -], [ - AC_DEFINE([BUILD_AT91RM9200], [0], [0 if you don't want at91rm9200.]) -]) - -AS_IF([test "x$build_bcm2835gpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_BCM2835GPIO], [1], [1 if you want bcm2835gpio.]) -], [ - AC_DEFINE([BUILD_BCM2835GPIO], [0], [0 if you don't want bcm2835gpio.]) -]) - -AS_IF([test "x$build_imx_gpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_IMX_GPIO], [1], [1 if you want imx_gpio.]) -], [ - AC_DEFINE([BUILD_IMX_GPIO], [0], [0 if you don't want imx_gpio.]) -]) - -AS_IF([test "x$build_am335xgpio" = "xyes"], [ - build_bitbang=yes - AC_DEFINE([BUILD_AM335XGPIO], [1], [1 if you want am335xgpio.]) -], [ - AC_DEFINE([BUILD_AM335XGPIO], [0], [0 if you don't want am335xgpio.]) -]) - AS_IF([test "x$parport_use_ppdev" = "xyes"], [ AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) ], [ @@ -653,11 +585,19 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBGPIOD], [libgpiod < 2.0], [ +PKG_CHECK_MODULES([LIBGPIOD], [libgpiod >= 2.0] , [ use_libgpiod=yes - PKG_CHECK_EXISTS([libgpiod >= 1.5], - [AC_DEFINE([HAVE_LIBGPIOD1_FLAGS_BIAS], [1], [define if libgpiod v1 has line request flags bias])]) -], [use_libgpiod=no]) +], [ + PKG_CHECK_MODULES([LIBGPIOD], [libgpiod], [ + use_libgpiod=yes + AC_DEFINE([HAVE_LIBGPIOD_V1], [1], [define if libgpiod is version v1.x]) + + PKG_CHECK_EXISTS([libgpiod >= 1.5], + [AC_DEFINE([HAVE_LIBGPIOD1_FLAGS_BIAS], [1], [define if libgpiod v1 has line request flags bias])]) + ], [ + use_libgpiod=no + ]) +]) PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) @@ -668,21 +608,24 @@ PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], # Arg $3: What prerequisites are missing, to be shown in an error message # if an adapter was requested but cannot be enabled. m4_define([PROCESS_ADAPTERS], [ - m4_foreach([adapter], [$1], [ + m4_foreach([adapter_driver], [$1], [ AS_IF([test $2], [ - AS_IF([test "x$ADAPTER_VAR([adapter])" != "xno"], [ - AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [1], [1 if you want the ]ADAPTER_DESC([adapter]).) + AS_IF([test "x$ADAPTER_VAR([adapter_driver])" != "xno"], [ + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [1], + [1 if you want the ]ADAPTER_DESC([adapter_driver]).) ], [ - AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0], + [0 if you do not want the ]ADAPTER_DESC([adapter_driver]).) ]) ], [ - AS_IF([test "x$ADAPTER_VAR([adapter])" = "xyes"], [ - AC_MSG_ERROR([$3 is required for [adapter] "ADAPTER_DESC([adapter])".]) + AS_IF([test "x$ADAPTER_VAR([adapter_driver])" = "xyes"], [ + AC_MSG_ERROR([$3 is required for [adapter_driver] "ADAPTER_DESC([adapter_driver])".]) ]) - ADAPTER_VAR([adapter])=no - AC_DEFINE([BUILD_]ADAPTER_SYM([adapter]), [0], [0 if you do not want the ]ADAPTER_DESC([adapter]).) + ADAPTER_VAR([adapter_driver])=no + AC_DEFINE([BUILD_]ADAPTER_SYM([adapter_driver]), [0], + [0 if you do not want the ]ADAPTER_DESC([adapter_driver]).) ]) - AM_CONDITIONAL(ADAPTER_SYM([adapter]), [test "x$ADAPTER_VAR([adapter])" != "xno"]) + AM_CONDITIONAL(ADAPTER_SYM([adapter_driver]), [test "x$ADAPTER_VAR([adapter_driver])" != "xno"]) ]) ]) @@ -692,19 +635,27 @@ PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libu PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) PROCESS_ADAPTERS([LIBFTDI_USB1_ADAPTERS], ["x$use_libftdi" = "xyes" -a "x$use_libusb1" = "xyes"], [libftdi and libusb-1.x]) PROCESS_ADAPTERS([LIBGPIOD_ADAPTERS], ["x$use_libgpiod" = "xyes"], [Linux libgpiod]) +PROCESS_ADAPTERS([DMEM_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"], [Linux /dev/mem]) PROCESS_ADAPTERS([SYSFSGPIO_ADAPTER], ["x$is_linux" = "xyes"], [Linux sysfs]) PROCESS_ADAPTERS([REMOTE_BITBANG_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([CMSIS_DAP_TCP_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.2]) -PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build]) +PROCESS_ADAPTERS([XVC_ADAPTERS], + ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_pci_h" = "xyes" -a "x$ac_cv_header_sys_mman_h" = "xyes"], + [Linux build with headers linux/pci.h and sys/mman.h]) PROCESS_ADAPTERS([SERIAL_PORT_ADAPTERS], ["x$can_build_buspirate" = "xyes"], [internal error: validation should happen beforehand]) -PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes"], [Linux spidev]) +PROCESS_ADAPTERS([PARALLEL_PORT_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([LINUXSPIDEV_ADAPTER], ["x$is_linux" = "xyes" -a "x$ac_cv_header_linux_spi_spidev_h" = "xyes"], + [Linux spidev]) PROCESS_ADAPTERS([VDEBUG_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_DPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([JTAG_VPI_ADAPTER], [true], [unused]) PROCESS_ADAPTERS([RSHIM_ADAPTER], ["x$can_build_rshim" = "xyes"], [internal error: validation should happen beforehand]) PROCESS_ADAPTERS([AMTJTAGACCEL_ADAPTER], [true], [unused]) +PROCESS_ADAPTERS([HOST_ARM_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h]) +PROCESS_ADAPTERS([HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS], ["x$ac_cv_header_sys_mman_h" = "xyes"], [header sys/mman.h]) PROCESS_ADAPTERS([DUMMY_ADAPTER], [true], [unused]) AS_IF([test "x$enable_linuxgpiod" != "xno"], [ @@ -719,6 +670,26 @@ AS_IF([test "x$enable_remote_bitbang" != "xno"], [ build_bitbang=yes ]) +AS_IF([test "x$enable_bcm2835gpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_imx_gpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_am335xgpio" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_ep93xx" != "xno"], [ + build_bitbang=yes +]) + +AS_IF([test "x$enable_at91rm9200" != "xno"], [ + build_bitbang=yes +]) + AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enable_nulink" != "xno"], [ AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) AM_CONDITIONAL([HLADAPTER], [true]) @@ -729,6 +700,8 @@ AS_IF([test "x$enable_stlink" != "xno" -o "x$enable_ti_icdi" != "xno" -o "x$enab AM_CONDITIONAL([HLADAPTER_STLINK], [test "x$enable_stlink" != "xno"]) AM_CONDITIONAL([HLADAPTER_ICDI], [test "x$enable_ti_icdi" != "xno"]) AM_CONDITIONAL([HLADAPTER_NULINK], [test "x$enable_nulink" != "xno"]) +AM_CONDITIONAL([CMSIS_DAP_CORE], + [test "x$enable_cmsis_dap" != "xno" -o "x$enable_cmsis_dap_v2" != "xno" -o "x$enable_cmsis_dap_tcp" != "xno"]) AS_IF([test "x$enable_jlink" != "xno"], [ AS_IF([test "x$use_internal_libjaylink" = "xyes"], [ @@ -752,13 +725,7 @@ AS_IF([test "x$enable_esp_usb_jtag" != "xno"], [ ]) AM_CONDITIONAL([RELEASE], [test "x$build_release" = "xyes"]) -AM_CONDITIONAL([PARPORT], [test "x$build_parport" = "xyes"]) AM_CONDITIONAL([GIVEIO], [test "x$parport_use_giveio" = "xyes"]) -AM_CONDITIONAL([EP93XX], [test "x$build_ep93xx" = "xyes"]) -AM_CONDITIONAL([AT91RM9200], [test "x$build_at91rm9200" = "xyes"]) -AM_CONDITIONAL([BCM2835GPIO], [test "x$build_bcm2835gpio" = "xyes"]) -AM_CONDITIONAL([IMX_GPIO], [test "x$build_imx_gpio" = "xyes"]) -AM_CONDITIONAL([AM335XGPIO], [test "x$build_am335xgpio" = "xyes"]) AM_CONDITIONAL([BITBANG], [test "x$build_bitbang" = "xyes"]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test "x$enable_usb_blaster" != "xno" -o "x$enable_usb_blaster_2" != "xno"]) AM_CONDITIONAL([GW16012], [test "x$build_gw16012" = "xyes"]) @@ -772,13 +739,13 @@ AM_CONDITIONAL([USE_LIBFTDI], [test "x$use_libftdi" = "xyes"]) AM_CONDITIONAL([USE_LIBGPIOD], [test "x$use_libgpiod" = "xyes"]) AM_CONDITIONAL([USE_HIDAPI], [test "x$use_hidapi" = "xyes"]) AM_CONDITIONAL([USE_LIBJAYLINK], [test "x$use_libjaylink" = "xyes"]) -AM_CONDITIONAL([DMEM], [test "x$build_dmem" = "xyes"]) AM_CONDITIONAL([HAVE_CAPSTONE], [test "x$enable_capstone" != "xno"]) AM_CONDITIONAL([INTERNAL_JIMTCL], [test "x$use_internal_jimtcl" = "xyes"]) AM_CONDITIONAL([HAVE_JIMTCL_PKG_CONFIG], [test "x$have_jimtcl_pkg_config" = "xyes"]) AM_CONDITIONAL([INTERNAL_LIBJAYLINK], [test "x$use_internal_libjaylink" = "xyes"]) + AM_CONDITIONAL([USE_GCOV], [test "x$enable_gcov" = "xyes"]) # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? @@ -836,7 +803,9 @@ AS_IF([test "x$gcc_warnings" = "xyes"], [ AC_SUBST(EXTRA_DIST_NEWS, ["$(echo $srcdir/NEWS-*)"]) AC_CONFIG_FILES([ - Makefile + Makefile \ + testing/Makefile \ + testing/tcl_commands/Makefile ]) AC_OUTPUT @@ -850,28 +819,51 @@ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AC_MSG_WARN([Using the internal jimtcl is deprecated and will not be possible in the future.]) ]) +AS_IF([test "x$enable_amtjtagaccel" != "xno"], [ + echo + echo + AC_MSG_WARN([Amontec JTAG-Accelerator adapter is deprecated and support will be removed in the next release!]) +]) +AS_IF([test "x$build_gw16012" = "xyes"], [ + echo + echo + AC_MSG_WARN([Gateworks GW16012 JTAG adapter is deprecated and support will be removed in the next release!]) +]) + +AS_IF([test "x$parport_use_giveio" = "xyes" || test [ "x$enable_parport" != "xno" -a "x$parport_use_ppdev" = "xno"]], [ + echo + echo + AC_MSG_WARN([Parallel port access with direct I/O is deprecated and support will be removed in the next release!]) +]) + echo echo echo OpenOCD configuration summary echo --------------------------------------------------- -m4_foreach([adapter], [USB1_ADAPTERS, +m4_foreach([adapter_driver], [USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, + DMEM_ADAPTER, SYSFSGPIO_ADAPTER, REMOTE_BITBANG_ADAPTER, - LIBJAYLINK_ADAPTERS, PCIE_ADAPTERS, SERIAL_PORT_ADAPTERS, + LIBJAYLINK_ADAPTERS, XVC_ADAPTERS, + SERIAL_PORT_ADAPTERS, + PARALLEL_PORT_ADAPTER, LINUXSPIDEV_ADAPTER, VDEBUG_ADAPTER, JTAG_DPI_ADAPTER, JTAG_VPI_ADAPTER, RSHIM_ADAPTER, AMTJTAGACCEL_ADAPTER, + HOST_ARM_BITBANG_ADAPTERS, + HOST_ARM_OR_AARCH64_BITBANG_ADAPTERS, + CMSIS_DAP_TCP_ADAPTER, DUMMY_ADAPTER, OPTIONAL_LIBRARIES, COVERAGE], - [s=m4_format(["%-41s"], ADAPTER_DESC([adapter])) - AS_CASE([$ADAPTER_VAR([adapter])], + [s=m4_format(["%-49s"], ADAPTER_DESC([adapter_driver])) + AS_CASE([$ADAPTER_VAR([adapter_driver])], [auto], [ echo "$s"yes '(auto)' ], @@ -883,8 +875,8 @@ m4_foreach([adapter], [USB1_ADAPTERS, ], [ AC_MSG_ERROR(m4_normalize([ - Error in [adapter] "ADAPTER_ARG([adapter])": Variable "ADAPTER_VAR([adapter])" - has invalid value "$ADAPTER_VAR([adapter])".])) + Error in [adapter_driver] "ADAPTER_ARG([adapter_driver])": Variable "ADAPTER_VAR([adapter_driver])" + has invalid value "$ADAPTER_VAR([adapter_driver])".])) ]) ]) echo diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules index 29f8d7a6d4..151b4e2c06 100644 --- a/contrib/60-openocd.rules +++ b/contrib/60-openocd.rules @@ -190,6 +190,10 @@ ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="660", GROUP="plugdev", # Debug Board for Neo1973 ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="660", GROUP="plugdev", TAG+="uaccess" +# Microchip RISC-V Debug +ATTRS{idVendor}=="1514", ATTRS{idProduct}=="2008", MODE="660", GROUP="plugdev", TAG+="uaccess" +ATTRS{idVendor}=="1514", ATTRS{idProduct}=="200a", MODE="660", GROUP="plugdev", TAG+="uaccess" + # OSBDM ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0042", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0058", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -216,6 +220,11 @@ ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="06ad", MODE="660", GROUP="plugdev", # USBprog with OpenOCD firmware ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev", TAG+="uaccess" +# WCH CH347T chip in mode 3 +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55dd", MODE="660", GROUP="plugdev", TAG+="uaccess" +# WCH CH347F chip +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55de", MODE="660", GROUP="plugdev", TAG+="uaccess" + # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" @@ -248,8 +257,6 @@ ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", # ANGIE USB-JTAG Adapter ATTRS{idVendor}=="584e", ATTRS{idProduct}=="414f", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="584e", ATTRS{idProduct}=="424e", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4255", MODE="660", GROUP="plugdev", TAG+="uaccess" -ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4355", MODE="660", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="584e", ATTRS{idProduct}=="4a55", MODE="660", GROUP="plugdev", TAG+="uaccess" # Marvell Sheevaplug diff --git a/contrib/firmware/angie/c/Makefile b/contrib/firmware/angie/c/Makefile index 1bcc1f7d1e..21873da6bf 100644 --- a/contrib/firmware/angie/c/Makefile +++ b/contrib/firmware/angie/c/Makefile @@ -38,10 +38,8 @@ LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \ --xram-size $(XRAM_SIZE) --iram-size 256 --model-small # list of base object files -OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel serial.rel gpif.rel i2c.rel +OBJECTS = main.rel usb.rel delay.rel USBJmpTb.rel gpif.rel i2c.rel serial.rel HEADERS = $(INCLUDE_DIR)/usb.h \ - $(INCLUDE_DIR)/protocol.h \ - $(INCLUDE_DIR)/jtag.h \ $(INCLUDE_DIR)/delay.h \ $(INCLUDE_DIR)/reg_ezusb.h \ $(INCLUDE_DIR)/io.h \ diff --git a/contrib/firmware/angie/c/include/i2c.h b/contrib/firmware/angie/c/include/i2c.h index d0404923b3..7a199c15a5 100644 --- a/contrib/firmware/angie/c/include/i2c.h +++ b/contrib/firmware/angie/c/include/i2c.h @@ -14,6 +14,7 @@ #include #include +bool get_status(void); void start_cd(void); void repeated_start(void); void stop_cd(void); diff --git a/contrib/firmware/angie/c/include/io.h b/contrib/firmware/angie/c/include/io.h index 19289d11d8..447aec3b4c 100644 --- a/contrib/firmware/angie/c/include/io.h +++ b/contrib/firmware/angie/c/include/io.h @@ -14,44 +14,26 @@ #include "reg_ezusb.h" -/*************************************************************************** - * JTAG Signals: * - *************************************************************************** - * TMS ....... Test Mode Select * - * TCK ....... Test Clock * - * TDI ....... Test Data Input (from device point of view, not JTAG * - * adapter point of view!) * - * TDO ....... Test Data Output (from device point of view, not JTAG * - * adapter point of view!) * - * TRST ...... Test Reset: Used to reset the TAP Finite State Machine * - * into the Test Logic Reset state * - * SRST ..... Chip Reset * - ***************************************************************************/ - /* PORT A */ -/* PA0 Not Connected */ +#define PIN_SDA_DIR IOA0 /* PA1 Not Connected */ -#define PIN_RDWR_B IOA2 -#define PIN_CSI_B IOA3 -#define PIN_INIT_B IOA4 -#define PIN_PROGRAM_B IOA5 +#define PIN_RDWR_B IOA2 +#define PIN_SDA IOA3 +#define PIN_SCL IOA4 +#define PIN_PROGRAM_B IOA5 /* PA6 Not Connected */ /* PA7 Not Connected */ /* PORT B */ -#define PIN_TRST IOB0 -#define PIN_TMS IOB1 -#define PIN_TCK IOB2 -#define PIN_TDI IOB3 -#define PIN_TDO IOB4 -#define PIN_SRST IOB5 +/* PB0 Not Connected */ +/* PB1 Not Connected */ +/* PB2 Not Connected */ +/* PB3 Not Connected */ +/* PB4 Not Connected */ +/* PB5 Not Connected */ /* PB6 Not Connected */ /* PB7 Not Connected */ -/* JTAG Signals with direction 'OUT' on port B */ -/* PIN_TDI - PIN_TCK - PIN_TMS - PIN_TRST - PIN_SRST */ -#define MASK_PORTB_DIRECTION_OUT (bmbit0 | bmbit1 | bmbit2 | bmbit3 | bmbit5) - /* PORT C */ #define PIN_T0 IOC0 #define PIN_T1 IOC1 @@ -63,10 +45,10 @@ /* PC7 Not Connected */ /* PORT D */ -#define PIN_SDA IOD0 -#define PIN_SCL IOD1 -#define PIN_SDA_DIR IOD2 -#define PIN_SCL_DIR IOD3 +/* PD0 Not Connected */ +/* PD1 Not Connected */ +/* PD2 Not Connected */ +/* PD3 Not Connected */ /* PD4 Not Connected */ /* PD5 Not Connected */ /* PD6 Not Connected */ diff --git a/contrib/firmware/angie/c/include/jtag.h b/contrib/firmware/angie/c/include/jtag.h deleted file mode 100644 index 6d5df64805..0000000000 --- a/contrib/firmware/angie/c/include/jtag.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/**************************************************************************** - File : jtag.h * - Contents : Jtag handling functions header file for NanoXplore * - USB-JTAG ANGIE adapter hardware. * - Based on openULINK project code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * -*****************************************************************************/ - -#ifndef __JTAG_H -#define __JTAG_H - -#include - -uint16_t jtag_get_signals(void); -void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, - uint8_t scan_io, uint8_t tck, uint8_t tms); -void jtag_clock_tms(uint8_t count, uint8_t sequence); -void jtag_slow_clock_tms(uint8_t count, uint8_t sequence); -void jtag_set_signals(uint8_t low, uint8_t high); -void jtag_clock_tck(uint16_t count); -void jtag_slow_clock_tck(uint16_t count); -void jtag_scan_in(uint8_t out_offset, uint8_t in_offset); -void jtag_scan_out(uint8_t out_offset); -void jtag_scan_io(uint8_t out_offset, uint8_t in_offset); -void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset); -void jtag_slow_scan_out(uint8_t out_offset); -void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset); -#endif diff --git a/contrib/firmware/angie/c/include/protocol.h b/contrib/firmware/angie/c/include/protocol.h deleted file mode 100644 index a12644b27d..0000000000 --- a/contrib/firmware/angie/c/include/protocol.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/**************************************************************************** - File : protocol.h * - Contents : Jtag commands handling protocol header file for NanoXplore * - USB-JTAG ANGIE adapter hardware. * - Based on openULINK project code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * -*****************************************************************************/ - -#ifndef __PROTOCOL_H -#define __PROTOCOL_H - -#include - -bool execute_command(void); -void command_loop(void); - -#endif diff --git a/contrib/firmware/angie/c/include/reg_ezusb.h b/contrib/firmware/angie/c/include/reg_ezusb.h index c22476a1a6..735ccaa8a7 100644 --- a/contrib/firmware/angie/c/include/reg_ezusb.h +++ b/contrib/firmware/angie/c/include/reg_ezusb.h @@ -634,10 +634,10 @@ SFRX(CT4, 0xE6FE); SFRX(EP0BUF[64], 0xE740); SFRX(EP1INBUF[64], 0xE7C0); SFRX(EP1OUTBUF[64], 0xE780); -SFRX(EP2FIFOBUF[512], 0xF000); -SFRX(EP4FIFOBUF[512], 0xF400); -SFRX(EP6FIFOBUF[512], 0xF800); -SFRX(EP8FIFOBUF[512], 0xFC00); +SFRX(EP2FIFOBUF[1024], 0xF000); +SFRX(EP4FIFOBUF[1024], 0xF400); +SFRX(EP6FIFOBUF[1024], 0xF800); +SFRX(EP8FIFOBUF[1024], 0xFC00); /* Error Correction Code (ECC) Registers (FX2LP/FX1 only) */ SFRX(ECCCFG, 0xE628); diff --git a/contrib/firmware/angie/c/include/usb.h b/contrib/firmware/angie/c/include/usb.h index ad8be787e4..dbf41fe8e5 100644 --- a/contrib/firmware/angie/c/include/usb.h +++ b/contrib/firmware/angie/c/include/usb.h @@ -104,7 +104,7 @@ struct usb_endpoint_descriptor { struct usb_language_descriptor { uint8_t blength; /**< Size of this descriptor in bytes. */ uint8_t bdescriptortype; /**< STRING descriptor type. */ - uint16_t wlangid[]; /**< LANGID codes. */ + uint16_t wlangid; /**< LANGID codes. */ }; /** USB String Descriptor. See USB 2.0 Spec */ @@ -125,12 +125,6 @@ struct setup_data { uint16_t wlength; /**< Number of bytes to transfer in data stage. */ }; -/* External declarations for variables that need to be accessed outside of - * the USB module */ -extern volatile bool ep1_out; -extern volatile bool ep1_in; -extern volatile bool ep6_out; - extern volatile __xdata __at 0xE6B8 struct setup_data setup_data; /* @@ -278,8 +272,8 @@ bool usb_handle_set_feature(void); bool usb_handle_get_descriptor(void); void usb_handle_set_interface(void); void usb_handle_setup_data(void); -void usb_handle_i2c_in(void); -void usb_handle_i2c_out(void); +bool usb_handle_vcommands(void); +void set_gpif_cnt(uint32_t count); void i2c_recieve(void); void ep_init(void); diff --git a/contrib/firmware/angie/c/src/gpif.c b/contrib/firmware/angie/c/src/gpif.c index f4028be400..0e0d01300d 100644 --- a/contrib/firmware/angie/c/src/gpif.c +++ b/contrib/firmware/angie/c/src/gpif.c @@ -19,15 +19,15 @@ const char wavedata[128] = { /* Output*/ 0x04, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, /* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, // Wave 1 -/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, -/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* Output*/ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +/* LenBr */ 0x01, 0x3F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x02, 0x07, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, // Wave 2 -/* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, -/* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* Output*/ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -/* LFun */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, +/* LenBr */ 0x01, 0xBF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, +/* Opcode*/ 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* Output*/ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +/* LFun */ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, // Wave 3 /* LenBr */ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, /* Opcode*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -47,7 +47,7 @@ const char flowstates[36] = { /* DO NOT EDIT ... */ const char initdata[7] = { -/* Regs */ 0xE0, 0x00, 0x00, 0x07, 0xEE, 0xF2, 0x00 +/* Regs */ 0xE0, 0x00, 0x00, 0x03, 0xEE, 0xF1, 0x00 }; /* END DO NOT EDIT */ diff --git a/contrib/firmware/angie/c/src/i2c.c b/contrib/firmware/angie/c/src/i2c.c index 10a463bf7d..4cf82955fc 100644 --- a/contrib/firmware/angie/c/src/i2c.c +++ b/contrib/firmware/angie/c/src/i2c.c @@ -12,14 +12,26 @@ #include "delay.h" #include "reg_ezusb.h" +bool get_status(void) +{ + PIN_SDA_DIR = 1; + OEA = 0xF7; + delay_us(1); + bool sda_state = PIN_SDA; + PIN_T0 = sda_state; + delay_us(1); + OEA = 0xFF; + delay_us(1); + return sda_state; +} + void start_cd(void) { - PIN_SCL_DIR = 0; - PIN_SDA_DIR = 0; + PIN_SDA_DIR = 0; // SP6 SDA: OUT delay_us(10); - PIN_SDA = 0; //SDA = 1; + PIN_SDA = 0; delay_us(1); - PIN_SCL = 0; //SCL = 1; + PIN_SCL = 0; delay_us(1); } @@ -43,9 +55,7 @@ void stop_cd(void) delay_us(1); PIN_SDA = 1; delay_us(1); - PIN_SDA_DIR = 1; - delay_us(1); - PIN_SCL_DIR = 1; + PIN_SDA_DIR = 1; // SP6 SDA: IN delay_us(1); } @@ -79,16 +89,16 @@ void send_nack(void) bool get_ack(void) { - PIN_SDA_DIR = 1; + PIN_SDA_DIR = 1; // SP6 SDA: IN delay_us(1); - OED = 0xFE; + OEA = 0xF7; // FX2 SDA: IN PIN_SCL = 1; delay_us(1); bool ack = PIN_SDA; PIN_SCL = 0; delay_us(1); - OED = 0xFF; - PIN_SDA_DIR = 0; + OEA = 0xFF; // FX2 SDA: OUT + PIN_SDA_DIR = 0; // SP6 SDA: OUT delay_us(1); return ack; } @@ -123,8 +133,8 @@ void send_byte(uint8_t input) uint8_t receive_byte(void) { - PIN_SDA_DIR = 1; //FX2 <-- FPGA - OED = 0xFE; + PIN_SDA_DIR = 1; // SP6 SDA: IN + OEA = 0xF7; // FX2 SDA: IN uint8_t input = 0x00; for (uint8_t i = 0; i < 8; i++) { PIN_SCL = 1; @@ -138,7 +148,7 @@ uint8_t receive_byte(void) PIN_SCL = 0; delay_us(1); } - OED = 0xFF; - PIN_SDA_DIR = 0; + OEA = 0xFF; // FX2 SDA: OUT + PIN_SDA_DIR = 0; // SP6 SDA: OUT return input; } diff --git a/contrib/firmware/angie/c/src/jtag.c b/contrib/firmware/angie/c/src/jtag.c deleted file mode 100644 index 9a44cd0bfc..0000000000 --- a/contrib/firmware/angie/c/src/jtag.c +++ /dev/null @@ -1,674 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -/**************************************************************************** - File : jtag.c * - Contents : Jtag handling functions code for NanoXplore * - USB-JTAG ANGIE adapter hardware. * - Based on openULINK project code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * -*****************************************************************************/ - -#include "jtag.h" -#include "io.h" -#include "msgtypes.h" -#include "reg_ezusb.h" -#include -#include -#include - -/** Delay value for SCAN_IN operations with less than maximum TCK frequency */ -uint8_t delay_scan_in; - -/** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ -uint8_t delay_scan_out; - -/** Delay value for SCAN_IO operations with less than maximum TCK frequency */ -uint8_t delay_scan_io; - -/** Delay value for CLOCK_TCK operations with less than maximum frequency */ -uint8_t delay_tck; - -/** Delay value for CLOCK_TMS operations with less than maximum frequency */ -uint8_t delay_tms; - -/** - * Perform JTAG SCAN-IN operation at maximum TCK frequency. - * - * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and - * stored in the EP2 IN buffer. - * - * Maximum achievable TCK frequency is 182 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - * @param in_offset - */ -void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdo_data, i, j; - - uint8_t outb_buffer; - - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_clock_tms(tms_count_start, tms_sequence_start); - - outb_buffer = IOB & ~(bmbit1 | bmbit2 | bmbit3); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdo_data = 0; - - for (j = 0; j < 8; j++) { - IOB = outb_buffer; /* TCK changes here */ - tdo_data = tdo_data >> 1; - IOB = (outb_buffer | bmbit2); - - if (PIN_TDO) - tdo_data |= 0x80; - } - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - } - tdo_data = 0; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - - IOB = outb_buffer; /* TCK changes here */ - tdo_data = tdo_data >> 1; - IOB = (outb_buffer | bmbit2); - - if (PIN_TDO) - tdo_data |= 0x80; - } - tdo_data = tdo_data >> (8 - bits_last_byte); - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_clock_tms(tms_count_end, tms_sequence_end); -} - - -/** - * Perform JTAG SCAN-IN operation at variable TCK frequency. - * - * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and - * stored in the EP2 IN buffer. - * - * Maximum achievable TCK frequency is 113 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - * @param in_offset - */ -void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdo_data, i, j, k; - uint8_t outb_buffer; - - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_slow_clock_tms(tms_count_start, tms_sequence_start); - - outb_buffer = IOB & ~(bmbit3 | bmbit2 | bmbit1); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdo_data = 0; - - for (j = 0; j < 8; j++) { - IOB = outb_buffer; /* TCK changes here */ - for (k = 0; k < delay_scan_in; k++) - ; - tdo_data = tdo_data >> 1; - - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_in; k++) - ; - - if (PIN_TDO) - tdo_data |= 0x80; - } - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - } - - tdo_data = 0; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - - IOB = outb_buffer; /* TCK changes here */ - for (k = 0; k < delay_scan_in; k++) - ; - tdo_data = tdo_data >> 1; - - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_in; k++) - ; - - if (PIN_TDO) - tdo_data |= 0x80; - } - tdo_data = tdo_data >> (8 - bits_last_byte); - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_slow_clock_tms(tms_count_end, tms_sequence_end); -} - - -/** - * Perform JTAG SCAN-OUT operation at maximum TCK frequency. - * - * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO - * data is not sampled. - * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. - * - * Maximum achievable TCK frequency is 142 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - */ -void jtag_scan_out(uint8_t out_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdi_data, i, j; - uint8_t outb_buffer; - - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_clock_tms(tms_count_start, tms_sequence_start); - outb_buffer = IOB & ~(bmbit2 | bmbit1); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdi_data = EP1OUTBUF[i + out_offset + 5]; - - for (j = 0; j < 8; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - - IOB = outb_buffer; /* TDI and TCK change here */ - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - } - } - tdi_data = EP1OUTBUF[i + out_offset + 5]; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - IOB = outb_buffer; /* TDI and TCK change here */ - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - } - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_clock_tms(tms_count_end, tms_sequence_end); -} - -/** - * Perform JTAG SCAN-OUT operation at maximum TCK frequency. - * - * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO - * data is not sampled. - * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. - * - * Maximum achievable TCK frequency is 97 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - */ -void jtag_slow_scan_out(uint8_t out_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdi_data, i, j, k; - uint8_t outb_buffer; - - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_slow_clock_tms(tms_count_start, tms_sequence_start); - outb_buffer = IOB & ~(bmbit2 | bmbit1); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdi_data = EP1OUTBUF[i + out_offset + 5]; - - for (j = 0; j < 8; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - IOB = outb_buffer; /* TDI and TCK change here */ - for (k = 0; k < delay_scan_out; k++) - ; - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_out; k++) - ; - } - } - tdi_data = EP1OUTBUF[i + out_offset + 5]; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - IOB = outb_buffer; /* TDI and TCK change here */ - for (k = 0; k < delay_scan_out; k++) - ; - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_out; k++) - ; - } - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_slow_clock_tms(tms_count_end, tms_sequence_end); -} - - -/** - * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. - * - * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO - * data is sampled and stored in the EP2 IN buffer. - * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. - * - * Maximum achievable TCK frequency is 100 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - * @param in_offset - */ -int it; -void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdi_data, tdo_data, i, j; - uint8_t outb_buffer; - - it++; - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_clock_tms(tms_count_start, tms_sequence_start); - outb_buffer = IOB & ~(bmbit2 | bmbit1); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdi_data = EP1OUTBUF[i + out_offset + 5]; - tdo_data = 0; - for (j = 0; j < 8; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - IOB = outb_buffer; /* TDI and TCK change here */ - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - tdo_data = tdo_data >> 1; - if (PIN_TDO) - tdo_data |= 0x80; - } - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - } - tdi_data = EP1OUTBUF[i + out_offset + 5]; - tdo_data = 0; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - IOB = outb_buffer; /* TDI and TCK change here */ - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - tdo_data = tdo_data >> 1; - if (PIN_TDO) - tdo_data |= 0x80; - } - tdo_data = tdo_data >> (8 - bits_last_byte); - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_clock_tms(tms_count_end, tms_sequence_end); -} - -/** - * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. - * - * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO - * data is sampled and stored in the EP2 IN buffer. - * The TAP-FSM state is always left in the PAUSE-DR/PAUSE-IR state. - * - * Maximum achievable TCK frequency is 78 kHz for ANGIE clocked at 24 MHz. - * - * @param out_offset offset in EP1OUTBUF where payload data starts - * @param in_offset - */ -void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) -{ - uint8_t scan_size_bytes, bits_last_byte; - uint8_t tms_count_start, tms_count_end; - uint8_t tms_sequence_start, tms_sequence_end; - uint8_t tdi_data, tdo_data, i, j, k; - uint8_t outb_buffer; - - /* Get parameters from EP1OUTBUF */ - scan_size_bytes = EP1OUTBUF[out_offset]; - bits_last_byte = EP1OUTBUF[out_offset + 1]; - tms_count_start = (EP1OUTBUF[out_offset + 2] >> 4) & 0x0F; - tms_count_end = EP1OUTBUF[out_offset + 2] & 0x0F; - tms_sequence_start = EP1OUTBUF[out_offset + 3]; - tms_sequence_end = EP1OUTBUF[out_offset + 4]; - - if (tms_count_start > 0) - jtag_slow_clock_tms(tms_count_start, tms_sequence_start); - outb_buffer = IOB & ~(bmbit2 | bmbit1); - - /* Shift all bytes except the last byte */ - for (i = 0; i < scan_size_bytes - 1; i++) { - tdi_data = EP1OUTBUF[i + out_offset + 5]; - tdo_data = 0; - for (j = 0; j < 8; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - IOB = outb_buffer; /* TDI and TCK change here */ - for (k = 0; k < delay_scan_io; k++) - ; - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_io; k++) - ; - tdo_data = tdo_data >> 1; - if (PIN_TDO) - tdo_data |= 0x80; - } - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - } - tdi_data = EP1OUTBUF[i + out_offset + 5]; - tdo_data = 0; - - /* Shift the last byte */ - for (j = 0; j < bits_last_byte; j++) { - if (tdi_data & 0x01) - outb_buffer |= bmbit3; - else - outb_buffer &= ~bmbit3; - - /* Assert TMS signal if requested and this is the last bit */ - if (j == (bits_last_byte - 1) && tms_count_end > 0) { - outb_buffer |= bmbit1; - tms_count_end--; - tms_sequence_end = tms_sequence_end >> 1; - } - IOB = outb_buffer; /* TDI and TCK change here */ - for (k = 0; k < delay_scan_io; k++) - ; - tdi_data = tdi_data >> 1; - IOB = (outb_buffer | bmbit2); - for (k = 0; k < delay_scan_io; k++) - ; - tdo_data = tdo_data >> 1; - if (PIN_TDO) - tdo_data |= 0x80; - } - tdo_data = tdo_data >> (8 - bits_last_byte); - - /* Copy TDO data to EP1INBUF */ - EP1INBUF[i + in_offset] = tdo_data; - - /* Move to correct end state */ - if (tms_count_end > 0) - jtag_slow_clock_tms(tms_count_end, tms_sequence_end); -} - -/** - * Generate TCK clock cycles. - * - * Maximum achievable TCK frequency is 375 kHz for ANGIE clocked at 24 MHz. - * - * @param count number of TCK clock cycles to generate. - */ -void jtag_clock_tck(uint16_t count) -{ - uint16_t i; - uint8_t outb_buffer = IOB & ~(bmbit2); - - for (i = 0; i < count; i++) { - IOB = outb_buffer; - IOB = outb_buffer | bmbit2; - } -} - -/** - * Generate TCK clock cycles at variable frequency. - * - * Maximum achievable TCK frequency is 166.6 kHz for ANGIE clocked at 24 MHz. - * - * @param count number of TCK clock cycles to generate. - */ -void jtag_slow_clock_tck(uint16_t count) -{ - uint16_t i; - uint8_t j; - uint8_t outb_buffer = IOB & ~(bmbit2); - - for (i = 0; i < count; i++) { - IOB = outb_buffer; - for (j = 0; j < delay_tck; j++) - ; - IOB = outb_buffer | bmbit2; - for (j = 0; j < delay_tck; j++) - ; - } -} - -/** - * Perform TAP FSM state transitions at maximum TCK frequency. - * - * Maximum achievable TCK frequency is 176 kHz for ANGIE clocked at 24 MHz. - * - * @param count the number of state transitions to perform. - * @param sequence the TMS pin levels for each state transition, starting with - * the least-significant bit. - */ -void jtag_clock_tms(uint8_t count, uint8_t sequence) -{ - uint8_t outb_buffer = IOB & ~(bmbit2); - uint8_t i; - - for (i = 0; i < count; i++) { - /* Set TMS pin according to sequence parameter */ - if (sequence & 0x1) - outb_buffer |= bmbit1; - else - outb_buffer &= ~bmbit1; - IOB = outb_buffer; - sequence = sequence >> 1; - IOB = outb_buffer | bmbit2; - } -} - -/** - * Perform TAP-FSM state transitions at less than maximum TCK frequency. - * - * Maximum achievable TCK frequency is 117 kHz for ANGIE clocked at 24 MHz. - * - * @param count the number of state transitions to perform. - * @param sequence the TMS pin levels for each state transition, starting with - * the least-significant bit. - */ -void jtag_slow_clock_tms(uint8_t count, uint8_t sequence) -{ - uint8_t outb_buffer = IOB & ~(bmbit2); - uint8_t i, j; - - for (i = 0; i < count; i++) { - /* Set TMS pin according to sequence parameter */ - if (sequence & 0x1) - outb_buffer |= bmbit1; - else - outb_buffer &= ~bmbit1; - IOB = outb_buffer; - for (j = 0; j < delay_tms; j++) - ; - sequence = sequence >> 1; - IOB = outb_buffer | bmbit2; - for (j = 0; j < delay_tms; j++) - ; - } -} - -uint16_t jtag_get_signals(void) -{ - uint8_t input_signal_state, output_signal_state; - input_signal_state = 0; - output_signal_state = 0; - - /* Get states of input pins */ - if (PIN_TDO) - input_signal_state |= SIGNAL_TDO; - - /* Get states of output pins */ - output_signal_state = IOB & MASK_PORTB_DIRECTION_OUT; - - return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state); -} - -/** - * Set state of JTAG output signals. - * - * @param low signals which should be de-asserted. - * @param high signals which should be asserted. - */ -void jtag_set_signals(uint8_t low, uint8_t high) -{ - IOB &= ~(low & MASK_PORTB_DIRECTION_OUT); - IOB |= (high & MASK_PORTB_DIRECTION_OUT); -} - -/** - * Configure TCK delay parameters. - * - * @param scan_in number of delay cycles in scan_in operations. - * @param scan_out number of delay cycles in scan_out operations. - * @param scan_io number of delay cycles in scan_io operations. - * @param tck number of delay cycles in clock_tck operations. - * @param tms number of delay cycles in clock_tms operations. - */ -void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, - uint8_t scan_io, uint8_t tck, uint8_t tms) -{ - delay_scan_in = scan_in; - delay_scan_out = scan_out; - delay_scan_io = scan_io; - delay_tck = tck; - delay_tms = tms; -} diff --git a/contrib/firmware/angie/c/src/main.c b/contrib/firmware/angie/c/src/main.c index 9290af2ab5..657694b6c1 100644 --- a/contrib/firmware/angie/c/src/main.c +++ b/contrib/firmware/angie/c/src/main.c @@ -11,10 +11,9 @@ *****************************************************************************/ #include "usb.h" +#include "serial.h" #include "delay.h" -#include "protocol.h" #include "reg_ezusb.h" -#include #include extern void sudav_isr(void)__interrupt SUDAV_ISR; @@ -65,7 +64,7 @@ void gpif_init(void); int main(void) { CPUCS = ((CPUCS & ~bmclkspd) | (CLK_48M << 3) | CLKOE); /* required for sio0_init */ - sio0_init(57600); /* needed for printf */ + sio0_init(115200); /* needed for printf */ ep_init(); gpif_init(); @@ -74,12 +73,10 @@ int main(void) /* Perform ReNumeration */ USBCS |= (DISCON | RENUM); - delay_ms(250); + delay_ms(50); USBCS &= ~DISCON; - /* Begin executing command(s). This function never returns. */ - command_loop(); - - /* Never reached, but SDCC complains about missing return statement */ - return 0; + /* stay here */ + while (1) + ; } diff --git a/contrib/firmware/angie/c/src/protocol.c b/contrib/firmware/angie/c/src/protocol.c deleted file mode 100644 index e32808db8f..0000000000 --- a/contrib/firmware/angie/c/src/protocol.c +++ /dev/null @@ -1,192 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -/**************************************************************************** - File : protocol.c * - Contents : Jtag commands handling protocol code for NanoXplore * - USB-JTAG ANGIE adapter hardware. * - Based on openULINK project code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * -*****************************************************************************/ - -#include "usb.h" -#include "protocol.h" -#include "jtag.h" -#include "delay.h" -#include "io.h" -#include "msgtypes.h" -#include "reg_ezusb.h" -#include -#include - -/** Index in EP1 Bulk-OUT data buffer that contains the current command ID */ -volatile uint8_t cmd_id_index; - -/** Number of data bytes already in EP1 Bulk-IN buffer */ -volatile uint8_t payload_index_in; - -/** - * Executes one command and updates global command indexes. - * - * @return true if this command was the last command. - * @return false if there are more commands within the current contents of the - * Bulk EP1-OUT data buffer. - */ -bool execute_command(void) -{ - uint8_t usb_out_bytecount, usb_in_bytecount; - uint16_t signal_state = 0; - uint16_t count; - - /* Most commands do not transfer IN data. To save code space, we write 0 to - * usb_in_bytecount here, then modify it in the switch statement below where - * necessary */ - usb_in_bytecount = 0; - - switch (EP1OUTBUF[cmd_id_index] /* Command ID */) { - case CMD_SCAN_IN: - usb_out_bytecount = 5; - usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; - jtag_scan_in((cmd_id_index + 1), payload_index_in); - break; - case CMD_SCAN_OUT: - usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; - jtag_scan_out(cmd_id_index + 1); - break; - case CMD_SCAN_IO: - usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; - usb_out_bytecount = usb_in_bytecount + 5; - jtag_scan_io((cmd_id_index + 1), payload_index_in); - break; - case CMD_CLOCK_TMS: - usb_out_bytecount = 2; - jtag_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); - break; - case CMD_CLOCK_TCK: - usb_out_bytecount = 2; - count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; - count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; - jtag_clock_tck(count); - break; - case CMD_SLOW_SCAN_IN: - usb_out_bytecount = 5; - usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; - jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); - break; - case CMD_SLOW_SCAN_OUT: - usb_out_bytecount = EP1OUTBUF[cmd_id_index + 1] + 5; - jtag_slow_scan_out(cmd_id_index + 1); - break; - case CMD_SLOW_SCAN_IO: - usb_in_bytecount = EP1OUTBUF[cmd_id_index + 1]; - usb_out_bytecount = usb_in_bytecount + 5; - jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); - break; - case CMD_SLOW_CLOCK_TMS: - usb_out_bytecount = 2; - jtag_slow_clock_tms(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); - break; - case CMD_SLOW_CLOCK_TCK: - usb_out_bytecount = 2; - count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; - count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; - jtag_slow_clock_tck(count); - break; - case CMD_SLEEP_US: - usb_out_bytecount = 2; - count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; - count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; - delay_us(count); - break; - case CMD_SLEEP_MS: - usb_out_bytecount = 2; - count = (uint16_t)EP1OUTBUF[cmd_id_index + 1]; - count |= ((uint16_t)EP1OUTBUF[cmd_id_index + 2]) << 8; - delay_ms(count); - break; - case CMD_GET_SIGNALS: - usb_out_bytecount = 0; - usb_in_bytecount = 2; - signal_state = jtag_get_signals(); - EP1INBUF[payload_index_in] = (signal_state >> 8); - EP1INBUF[payload_index_in + 1] = (signal_state & 0xFF); - break; - case CMD_SET_SIGNALS: - usb_out_bytecount = 2; - jtag_set_signals(EP1OUTBUF[cmd_id_index + 1], EP1OUTBUF[cmd_id_index + 2]); - break; - case CMD_CONFIGURE_TCK_FREQ: - usb_out_bytecount = 5; - jtag_configure_tck_delay(EP1OUTBUF[cmd_id_index + 1], /* scan_in */ - EP1OUTBUF[cmd_id_index + 2], /* scan_out */ - EP1OUTBUF[cmd_id_index + 3], /* scan_io */ - EP1OUTBUF[cmd_id_index + 4], /* clock_tck */ - EP1OUTBUF[cmd_id_index + 5]); /* clock_tms */ - break; - case CMD_TEST: - usb_out_bytecount = 1; - /* Do nothing... This command is only used to test if the device is ready - * to accept new commands */ - break; - default: - /* Should never be reached */ - usb_out_bytecount = 0; - break; - } - - /* Update EP1 Bulk-IN data byte count */ - payload_index_in += usb_in_bytecount; - - /* Determine if this was the last command */ - if ((cmd_id_index + usb_out_bytecount + 1) >= EP1OUTBC) - return true; - - /* Not the last command, update cmd_id_index */ - cmd_id_index += (usb_out_bytecount + 1); - return false; -} - -/** - * Forever wait for commands and execute them as they arrive. - */ -void command_loop(void) -{ - bool last_command; - while (1) { - cmd_id_index = 0; - payload_index_in = 0; - - /* Wait until host sends Bulk-OUT packet */ - while ((!ep1_out) && (!ep6_out)) - ; - if (ep6_out) { - /* Execute I2C command */ - i2c_recieve(); - ep6_out = false; - } - if (ep1_out) { - ep1_out = false; - /* Execute the commands */ - last_command = false; - while (!last_command) - last_command = execute_command(); - - /* Send back EP1 Bulk-IN packet if required */ - if (payload_index_in > 0) { - EP1INBC = payload_index_in; - syncdelay(3); - - while (!ep1_in) - ; - ep1_in = false; - } - - /* Re-arm EP1-OUT after command execution */ - EP1OUTBC = 0; - syncdelay(3); - EP1OUTBC = 0; - syncdelay(3); - } - } -} diff --git a/contrib/firmware/angie/c/src/usb.c b/contrib/firmware/angie/c/src/usb.c index ed23dcfa5a..6a07cc5d32 100644 --- a/contrib/firmware/angie/c/src/usb.c +++ b/contrib/firmware/angie/c/src/usb.c @@ -11,133 +11,119 @@ *****************************************************************************/ #include "usb.h" -#include "stdint.h" #include "delay.h" #include "io.h" #include "reg_ezusb.h" -#include -#include -#include +#include "fx2macros.h" +#include "serial.h" #include "i2c.h" +#include +#include +#include -/* Also update external declarations in "include/usb.h" if making changes to - * these variables! - */ -volatile bool ep1_out; -volatile bool ep1_in; -volatile bool ep6_out; +// #define PRINTF_DEBUG volatile __xdata __at 0xE6B8 struct setup_data setup_data; /* Define number of endpoints (except Control Endpoint 0) in a central place. * Be sure to include the necessary endpoint descriptors! */ -#define NUM_ENDPOINTS 3 +#define NUM_ENDPOINTS 2 __code struct usb_device_descriptor device_descriptor = { - .blength = sizeof(struct usb_device_descriptor), - .bdescriptortype = DESCRIPTOR_TYPE_DEVICE, - .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */ - .bdeviceclass = 0xEF, - .bdevicesubclass = 0x02, - .bdeviceprotocol = 0x01, - .bmaxpacketsize0 = 64, - .idvendor = 0x584e, - .idproduct = 0x414f, - .bcddevice = 0x0000, - .imanufacturer = 1, - .iproduct = 2, - .iserialnumber = 3, + .blength = sizeof(struct usb_device_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_DEVICE, + .bcdusb = 0x0200, /* BCD: 02.00 (Version 2.0 USB spec) */ + .bdeviceclass = 0xEF, + .bdevicesubclass = 0x02, + .bdeviceprotocol = 0x01, + .bmaxpacketsize0 = 64, + .idvendor = 0x584e, + .idproduct = 0x414f, + .bcddevice = 0x0000, + .imanufacturer = 1, + .iproduct = 2, + .iserialnumber = 3, .bnumconfigurations = 1 }; /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */ - __code struct usb_config_descriptor config_descriptor = { - .blength = sizeof(struct usb_config_descriptor), - .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION, - .wtotallength = sizeof(struct usb_config_descriptor) + - 3 * sizeof(struct usb_interface_descriptor) + - ((NUM_ENDPOINTS + 2) * sizeof(struct usb_endpoint_descriptor)), - .bnuminterfaces = 2, + .blength = sizeof(struct usb_config_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_CONFIGURATION, + .wtotallength = sizeof(struct usb_config_descriptor) + + 2 * sizeof(struct usb_interface_descriptor) + + ((NUM_ENDPOINTS * 2) * sizeof(struct usb_endpoint_descriptor)), + .bnuminterfaces = 2, .bconfigurationvalue = 1, - .iconfiguration = 1, /* String describing this configuration */ - .bmattributes = 0x80, /* Only MSB set according to USB spec */ - .maxpower = 50 /* 100 mA */ + .iconfiguration = 2, /* String describing this configuration */ + .bmattributes = 0x80, /* Only MSB set according to USB spec */ + .maxpower = 50 /* 100 mA */ }; __code struct usb_interface_descriptor interface_descriptor00 = { - .blength = sizeof(struct usb_interface_descriptor), - .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, - .binterfacenumber = 0, + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 0, .balternatesetting = 0, - .bnumendpoints = NUM_ENDPOINTS, - .binterfaceclass = 0XFF, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0XFF, .binterfacesubclass = 0x00, .binterfaceprotocol = 0x00, - .iinterface = 4 + .iinterface = 0 }; -__code struct usb_endpoint_descriptor bulk_ep1_out_endpoint_descriptor = { - .blength = sizeof(struct usb_endpoint_descriptor), - .bdescriptortype = 0x05, - .bendpointaddress = (1 | USB_DIR_OUT), - .bmattributes = 0x02, - .wmaxpacketsize = 64, - .binterval = 0 +__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (2 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 }; -__code struct usb_endpoint_descriptor bulk_ep1_in_endpoint_descriptor = { - .blength = sizeof(struct usb_endpoint_descriptor), - .bdescriptortype = 0x05, - .bendpointaddress = (1 | USB_DIR_IN), - .bmattributes = 0x02, - .wmaxpacketsize = 64, - .binterval = 0 -}; - -__code struct usb_endpoint_descriptor bulk_ep2_endpoint_descriptor = { - .blength = sizeof(struct usb_endpoint_descriptor), - .bdescriptortype = 0x05, - .bendpointaddress = (2 | USB_DIR_OUT), - .bmattributes = 0x02, - .wmaxpacketsize = 512, - .binterval = 0 +__code struct usb_endpoint_descriptor bulk_ep4_endpoint_descriptor = { + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (4 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 }; __code struct usb_interface_descriptor interface_descriptor01 = { - .blength = sizeof(struct usb_interface_descriptor), - .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, - .binterfacenumber = 1, + .blength = sizeof(struct usb_interface_descriptor), + .bdescriptortype = DESCRIPTOR_TYPE_INTERFACE, + .binterfacenumber = 1, .balternatesetting = 0, - .bnumendpoints = 2, - .binterfaceclass = 0x0A, + .bnumendpoints = NUM_ENDPOINTS, + .binterfaceclass = 0x0A, .binterfacesubclass = 0x00, .binterfaceprotocol = 0x00, - .iinterface = 0x00 + .iinterface = 0 }; __code struct usb_endpoint_descriptor bulk_ep6_out_endpoint_descriptor = { - .blength = sizeof(struct usb_endpoint_descriptor), - .bdescriptortype = 0x05, - .bendpointaddress = (6 | USB_DIR_OUT), - .bmattributes = 0x02, - .wmaxpacketsize = 512, - .binterval = 0 + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (6 | USB_DIR_OUT), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 }; __code struct usb_endpoint_descriptor bulk_ep8_in_endpoint_descriptor = { - .blength = sizeof(struct usb_endpoint_descriptor), - .bdescriptortype = 0x05, - .bendpointaddress = (8 | USB_DIR_IN), - .bmattributes = 0x02, - .wmaxpacketsize = 512, - .binterval = 0 + .blength = sizeof(struct usb_endpoint_descriptor), + .bdescriptortype = 0x05, + .bendpointaddress = (8 | USB_DIR_IN), + .bmattributes = 0x02, + .wmaxpacketsize = 512, + .binterval = 0 }; __code struct usb_language_descriptor language_descriptor = { - .blength = 4, - .bdescriptortype = DESCRIPTOR_TYPE_STRING, - .wlangid = {0x0409} /* US English */ + .blength = 4, + .bdescriptortype = DESCRIPTOR_TYPE_STRING, + .wlangid = 0x0409 /* US English */ }; __code struct usb_string_descriptor strmanufacturer = @@ -149,15 +135,11 @@ __code struct usb_string_descriptor strproduct = __code struct usb_string_descriptor strserialnumber = STR_DESCR(6, '0', '0', '0', '0', '0', '1'); -__code struct usb_string_descriptor strconfigdescr = - STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); - /* Table containing pointers to string descriptors */ -__code struct usb_string_descriptor *__code en_string_descriptors[4] = { +__code struct usb_string_descriptor *__code en_string_descriptors[3] = { &strmanufacturer, &strproduct, - &strserialnumber, - &strconfigdescr + &strserialnumber }; void sudav_isr(void)__interrupt SUDAV_ISR { @@ -195,15 +177,9 @@ void ep0out_isr(void)__interrupt EP0OUT_ISR } void ep1in_isr(void)__interrupt EP1IN_ISR { - ep1_in = true; - EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ - EPIRQ = 0x04; /* Clear individual EP1IN IRQ */ } void ep1out_isr(void)__interrupt EP1OUT_ISR { - ep1_out = true; - EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ - EPIRQ = 0x08; /* Clear individual EP1OUT IRQ */ } void ep2_isr(void)__interrupt EP2_ISR { @@ -213,15 +189,15 @@ void ep4_isr(void)__interrupt EP4_ISR } void ep6_isr(void)__interrupt EP6_ISR { - ep6_out = true; + REVCTL = 0; /* REVCTL.0 and REVCTL.1 set to 0 */ + i2c_recieve(); /* Execute I2C communication */ EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ EPIRQ = 0x40; /* Clear individual EP6OUT IRQ */ - } void ep8_isr(void)__interrupt EP8_ISR { - EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ - EPIRQ = 0x80; /* Clear individual EP8IN IRQ */ + EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */ + EPIRQ = 0x80; /* Clear individual EP8IN IRQ */ } void ibn_isr(void)__interrupt IBN_ISR { @@ -348,63 +324,6 @@ void usb_reset_data_toggle(uint8_t ep) TOGCTL |= BMRESETTOGGLE; } -/** - * Handle GET_STATUS request. - * - * @return on success: true - * @return on failure: false - */ -bool usb_handle_get_status(void) -{ - uint8_t *ep_cs; - switch (setup_data.bmrequesttype) { - case GS_DEVICE: - /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup. - * Byte 1: reserved, reset to zero */ - EP0BUF[0] = 0; - EP0BUF[1] = 0; - - /* Send response */ - EP0BCH = 0; - syncdelay(3); - EP0BCL = 2; - syncdelay(3); - break; - case GS_INTERFACE: - /* Always return two zero bytes according to USB 1.1 spec, p. 191 */ - EP0BUF[0] = 0; - EP0BUF[1] = 0; - - /* Send response */ - EP0BCH = 0; - syncdelay(3); - EP0BCL = 2; - syncdelay(3); - break; - case GS_ENDPOINT: - /* Get stall bit for endpoint specified in low byte of wIndex */ - ep_cs = usb_get_endpoint_cs_reg(setup_data.windex & 0xff); - - if (*ep_cs & EPSTALL) - EP0BUF[0] = 0x01; - else - EP0BUF[0] = 0x00; - - /* Second byte sent has to be always zero */ - EP0BUF[1] = 0; - - /* Send response */ - EP0BCH = 0; - syncdelay(3); - EP0BCL = 2; - syncdelay(3); - break; - default: - return false; - } - return true; -} - /** * Handle CLEAR_FEATURE request. * @@ -500,12 +419,17 @@ bool usb_handle_get_descriptor(void) case DESCRIPTOR_TYPE_STRING: if (setup_data.windex == 0) { /* Supply language descriptor */ - SUDPTRH = HI8(&language_descriptor); - SUDPTRL = LO8(&language_descriptor); + __xdata struct usb_language_descriptor temp_descriptor; + memcpy(&temp_descriptor, &language_descriptor, sizeof(language_descriptor)); + SUDPTRH = HI8(&temp_descriptor); + SUDPTRL = LO8(&temp_descriptor); } else if (setup_data.windex == 0x0409 /* US English */) { /* Supply string descriptor */ - SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]); - SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]); + __xdata uint8_t temp_descriptors[3]; + memcpy(temp_descriptors, en_string_descriptors[descriptor_index - 1], + ((struct usb_string_descriptor *)en_string_descriptors[descriptor_index - 1])->blength); + SUDPTRH = HI8(temp_descriptors); + SUDPTRL = LO8(temp_descriptors); } else { return false; } @@ -523,15 +447,28 @@ bool usb_handle_get_descriptor(void) void usb_handle_set_interface(void) { /* Reset Data Toggle */ - usb_reset_data_toggle(USB_DIR_IN | 4); usb_reset_data_toggle(USB_DIR_OUT | 2); - - /* Unstall & clear busy flag of all valid IN endpoints */ - EP1INCS = 0 | EPBSY; + usb_reset_data_toggle(USB_DIR_IN | 4); + usb_reset_data_toggle(USB_DIR_OUT | 6); + usb_reset_data_toggle(USB_DIR_IN | 8); /* Unstall all valid OUT endpoints, reset bytecounts */ - EP1OUTCS = 0; - EP1OUTBC = 0; + EP2CS = 0; + EP4CS = 0; + EP6CS = 0; + EP8CS = 0; + syncdelay(3); + EP2BCH = 0; + EP2BCL = 0x80; + syncdelay(3); + EP4BCH = 0; + EP4BCL = 0x80; + syncdelay(3); + EP6BCH = 0; + EP6BCL = 0x80; + syncdelay(3); + EP8BCH = 0; + EP8BCL = 0x80; syncdelay(3); } @@ -551,14 +488,14 @@ void set_gpif_cnt(uint32_t count) * Vendor commands handling: */ #define VR_CFGOPEN 0xB0 -#define VR_CFGCLOSE 0xB1 +#define VR_DATAOUTOPEN 0xB2 uint8_t ix; uint8_t bcnt; uint8_t __xdata *eptr; uint16_t wcnt; uint32_t __xdata gcnt; -bool usb_handle_send_bitstream(void) +bool usb_handle_vcommands(void) { eptr = EP0BUF; /* points to EP0BUF 64-byte register */ wcnt = setup_data.wlength; /* total transfer count */ @@ -582,43 +519,69 @@ bool usb_handle_send_bitstream(void) /* Angie board FPGA bitstream download */ switch ((setup_data.wvalue) & 0x00C0) { case 0x00: - PIN_PROGRAM_B = 0; /* Apply RPGM- pulse */ - GPIFWFSELECT = 0xF2; /* Restore Config mode waveforms select */ - syncdelay(3); - EP2FIFOCFG = BMAUTOOUT; /* and Automatic 8-bit GPIF OUT mode */ - syncdelay(3); - PIN_PROGRAM_B = 1; /* Negate RPGM- pulse */ - delay_ms(10); /* FPGA init time < 10mS */ - set_gpif_cnt(gcnt); /* Initialize GPIF interface transfer count */ + /* Apply RPGM- pulse */ + PIN_PROGRAM_B = 0; + syncdelay(1); + /* Negate RPGM- pulse */ + PIN_PROGRAM_B = 1; + /* FPGA init time < 10mS */ + delay_ms(10); + /* Initialize GPIF interface transfer count */ + set_gpif_cnt(gcnt); PIN_RDWR_B = 0; - PIN_CSI_B = 0; - GPIFTRIG = GPIF_EP2; /* Trigger GPIF OUT transfer on EP2 */ - syncdelay(3); + PIN_SDA = 0; + /* Trigger GPIF OUT transfer on EP2 */ + GPIFTRIG = GPIF_EP2; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + PIN_SDA = 1; + PIN_RDWR_B = 1; + #ifdef PRINTF_DEBUG + printf("Program SP6 Done.\n"); + #endif + /* Choose wich Waveform to use */ + GPIFWFSELECT = 0xF6; break; default: break; } break; - case VR_CFGCLOSE: - ix = 10; - /* wait until GPIF transaction has been completed */ - while ((GPIFTRIG & BMGPIFDONE) == 0) { - if (ix-- == 0) { - break; - } - delay_ms(1); - } - switch ((setup_data.wvalue) & 0x00C0) { - case 0x00: - PIN_CSI_B = 1; - PIN_RDWR_B = 1; - IFCONFIG &= 0xFC; /* Exit gpif mode */ - break; - default: - break; - } + case VR_DATAOUTOPEN: + /* Clear bytecount / to allow new data in / to stops NAKing */ EP0BCH = 0; - EP0BCL = (uint8_t)(setup_data.wlength); /* Signal buffer is filled */ + EP0BCL = 0; + while (EP0CS & EPBSY) + ; /* wait to finish transferring in EP0BUF, until not busy */ + gcnt = ((uint32_t)(eptr[0]) << 24) | ((uint32_t)(eptr[1]) << 16) + | ((uint32_t)(eptr[2]) << 8) | (uint32_t)(eptr[3]); + /* REVCTL.0 and REVCTL.1 set to 1 */ + REVCTL = 0x3; + /* Angie board FPGA bitstream download */ + PIN_RDWR_B = 0; + /* Initialize GPIF interface transfer count */ + GPIFTCB3 = (uint8_t)(((uint32_t)(gcnt) >> 24) & 0x000000ff); + GPIFTCB2 = (uint8_t)(((uint32_t)(gcnt) >> 16) & 0x000000ff); + GPIFTCB1 = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + GPIFTCB0 = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Trigger GPIF OUT transfer on EP2 */ + GPIFTRIG = GPIF_EP2; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + PIN_RDWR_B = 1; + /* Initialize GPIF interface transfer count */ + GPIFTCB3 = (uint8_t)(((uint32_t)(gcnt) >> 24) & 0x000000ff); + GPIFTCB2 = (uint8_t)(((uint32_t)(gcnt) >> 16) & 0x000000ff); + GPIFTCB1 = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + GPIFTCB0 = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Initialize AUTOIN transfer count */ + EP4AUTOINLENH = (uint8_t)(((uint32_t)(gcnt) >> 8) & 0x000000ff); + EP4AUTOINLENL = (uint8_t)((uint32_t)(gcnt) & 0x000000ff); + /* Trigger GPIF IN transfer on EP4 */ + GPIFTRIG = BMGPIFREAD | GPIF_EP4; + while (!(GPIFTRIG & BMGPIFDONE)) // poll GPIFTRIG.7 GPIF Done bit + ; + /* REVCTL.0 and REVCTL.1 set to 0 */ + REVCTL = 0; break; default: return true; /* Error: unknown VR command */ @@ -633,8 +596,12 @@ void usb_handle_setup_data(void) { switch (setup_data.brequest) { case GET_STATUS: - if (!usb_handle_get_status()) - STALL_EP0(); + EP0BUF[0] = 0; + EP0BUF[1] = 0; + /* Send response */ + EP0BCH = 0; + EP0BCL = 2; + syncdelay(3); break; case CLEAR_FEATURE: if (!usb_handle_clear_feature()) @@ -672,8 +639,9 @@ void usb_handle_setup_data(void) case GET_INTERFACE: /* ANGIE only has one interface, return its number */ EP0BUF[0] = interface_descriptor00.binterfacenumber; + EP0BUF[1] = interface_descriptor01.binterfacenumber; EP0BCH = 0; - EP0BCL = 1; + EP0BCL = 2; syncdelay(3); break; case SET_INTERFACE: @@ -684,7 +652,7 @@ void usb_handle_setup_data(void) break; default: /* if not Vendor command, Stall EndPoint 0 */ - if (usb_handle_send_bitstream()) + if (usb_handle_vcommands()) STALL_EP0(); break; } @@ -695,29 +663,21 @@ void usb_handle_setup_data(void) */ void ep_init(void) { - EP1INCFG = 0xA0; - syncdelay(3); - EP1OUTCFG = 0xA0; - syncdelay(3); - EP2CFG = 0xA0; - syncdelay(3); - EP4CFG = 0x00; + EP1INCFG = 0x00; /* non VALID */ syncdelay(3); - EP6CFG = 0xA2; - syncdelay(3); - EP8CFG = 0xE2; + EP1OUTCFG = 0x00; /* non VALID */ syncdelay(3); - /* arm EP1-OUT */ - EP1OUTBC = 0; + /* JTAG */ + EP2CFG = 0xA2; /* VALID | OUT | BULK | 512 Bytes | Double buffer */ syncdelay(3); - EP1OUTBC = 0; + EP4CFG = 0xE2; /* VALID | IN | BULK | 512 Bytes | Double buffer */ syncdelay(3); - /* arm EP1-IN */ - EP1INBC = 0; + /* I2C */ + EP6CFG = 0xA2; /* VALID | OUT | BULK | 512 Bytes | Double buffer */ syncdelay(3); - EP1INBC = 0; + EP8CFG = 0xE2; /* VALID | IN | BULK | 512 Bytes | Double buffer */ syncdelay(3); /* arm EP6-OUT */ @@ -726,31 +686,45 @@ void ep_init(void) EP6BCL = 0x80; syncdelay(3); + /* REVCTL.0 and REVCTL.1 set to 1 */ + REVCTL = 0x3; + /* Arm both EP2 buffers to “prime the pump” */ + OUTPKTEND = 0x82; + syncdelay(3); + OUTPKTEND = 0x82; + syncdelay(3); + /* Standard procedure to reset FIFOs */ FIFORESET = BMNAKALL; /* NAK all transfers during the reset */ syncdelay(3); - FIFORESET = 0x02; /* reset EP2 FIFO */ + FIFORESET = BMNAKALL | 0x02; /* reset EP2 FIFO */ + syncdelay(3); + FIFORESET = BMNAKALL | 0x04; /* reset EP4 FIFO */ syncdelay(3); FIFORESET = 0x00; /* deactivate the NAK all */ syncdelay(3); + + /* configure EP2 in AUTO mode with 8-bit interface */ EP2FIFOCFG = 0x00; syncdelay(3); - EP2FIFOCFG = BMAUTOOUT; /* Automatic 8-bit GPIF OUT mode */ + EP2FIFOCFG = BMAUTOOUT; /* 8-bit Auto OUT mode */ + syncdelay(3); + EP4FIFOCFG = BMAUTOIN | BMZEROLENIN; /* 8-bit Auto IN mode */ syncdelay(3); } void i2c_recieve(void) { - PIN_SDA_DIR = 0; if (EP6FIFOBUF[0] == 1) { - uint8_t rdwr = EP6FIFOBUF[0]; //read - uint8_t data_count = EP6FIFOBUF[1]; //data sent count + uint8_t rdwr = EP6FIFOBUF[0]; //read: 1 + uint8_t reg_byte_check = EP6FIFOBUF[1]; //register given: 1 else: 0 uint8_t count = EP6FIFOBUF[2]; //requested data count uint8_t adr = EP6FIFOBUF[3]; //address uint8_t address = get_address(adr, rdwr); //address byte (read command) uint8_t address_2 = get_address(adr, 0); //address byte 2 (write command) - printf("%d\n", address - 1); + /* i2c bus state byte */ + EP8FIFOBUF[0] = get_status(); /* start: */ start_cd(); @@ -760,12 +734,10 @@ void i2c_recieve(void) uint8_t ack = get_ack(); /* send data */ - if (data_count) { //if there is a byte reg - for (uint8_t i = 0; i < data_count; i++) { - send_byte(EP6FIFOBUF[i + 4]); - /* ack(): */ - ack = get_ack(); - } + for (int i = 0; i < reg_byte_check; i++) { + send_byte(EP6FIFOBUF[i + 4]); + /* ack(): */ + ack = get_ack(); } /* repeated start: */ @@ -776,14 +748,14 @@ void i2c_recieve(void) ack = get_ack(); /* receive data */ - for (uint8_t i = 0; i < count - 1; i++) { + for (int i = 1; i < count; i++) { EP8FIFOBUF[i] = receive_byte(); /* send ack: */ send_ack(); } - EP8FIFOBUF[count - 1] = receive_byte(); + EP8FIFOBUF[count] = receive_byte(); /* send Nack: */ send_nack(); @@ -791,44 +763,46 @@ void i2c_recieve(void) /* stop */ stop_cd(); - EP8BCH = 0; //EP8 + EP8BCH = (count + 1) >> 8; //EP8 syncdelay(3); - EP8BCL = count; //EP8 + EP8BCL = count + 1; //EP8 EP6BCL = 0x80; //EP6 syncdelay(3); EP6BCL = 0x80; //EP6 } else { - uint8_t rdwr = EP6FIFOBUF[0]; //write + uint8_t rdwr = EP6FIFOBUF[0]; //write: 0 uint8_t count = EP6FIFOBUF[1]; //data count uint8_t adr = EP6FIFOBUF[2]; //address uint8_t address = get_address(adr, rdwr); //address byte (read command) uint8_t ack_cnt = 0; -/* start(): */ + // i2c bus state byte + EP8FIFOBUF[0] = get_status(); + + /* start(): */ start_cd(); -/* address: */ + /* address: */ send_byte(address); //write -/* ack(): */ + /* ack(): */ if (!get_ack()) ack_cnt++; -/* send data */ - for (uint8_t i = 0; i < count; i++) { + /* send data */ + for (int i = 0; i < count; i++) { send_byte(EP6FIFOBUF[i + 3]); - /* get ack: */ if (!get_ack()) ack_cnt++; } -/* stop */ + /* stop */ stop_cd(); - EP8FIFOBUF[0] = ack_cnt; + EP8FIFOBUF[1] = ack_cnt; EP8BCH = 0; //EP8 syncdelay(3); - EP8BCL = 1; //EP8 + EP8BCL = 2; //EP8 EP6BCL = 0x80; //EP6 syncdelay(3); @@ -841,9 +815,6 @@ void i2c_recieve(void) **/ void interrupt_init(void) { - /* Enable Interrupts */ - EA = 1; - /* Enable USB interrupt (EIE register) */ EUSB = 1; EICON |= 0x20; @@ -851,17 +822,22 @@ void interrupt_init(void) /* Enable INT 2 & 4 Autovectoring */ INTSETUP |= (AV2EN | AV4EN); - /* Enable individual EP1OUT&IN & EP6&8 interrupts */ - EPIE |= 0xCC; + /* Enable individual EP6&8 interrupts */ + EPIE |= 0xC0; /* Clear individual USB interrupt IRQ */ - EPIRQ = 0xCC; + EPIRQ = 0xC0; /* Enable SUDAV interrupt */ USBIEN |= SUDAVI; /* Clear SUDAV interrupt */ USBIRQ = SUDAVI; + + /* Enable Interrupts (Do not confuse this with + * EA External Access pin, see ANGIE Schematic) + */ + EA = 1; } /** @@ -870,25 +846,12 @@ void interrupt_init(void) void io_init(void) { /* PORT A */ - PORTACFG = 0x01; /* 0: normal ou 1: alternate function (each bit) */ - OEA = 0xEF; /* all OUT exept INIT_B IN */ + PORTACFG = 0x0; /* 0: normal ou 1: alternate function (each bit) */ + OEA = 0xEF; IOA = 0xFF; - /* PORT B */ - OEB = 0xEF; /* all OUT exept TDO */ - IOB = 0xFF; - PIN_TRST = 1; - PIN_TMS = 0; - PIN_TCK = 0; - PIN_TDI = 0; - PIN_SRST = 1; - /* PORT C */ - PORTCCFG = 0x00; /* 0: normal ou 1: alternate function (each bit) */ + PORTCCFG = 0x0; /* 0: normal ou 1: alternate function (each bit) */ OEC = 0xFF; IOC = 0xFF; - - /* PORT D */ - OED = 0xFF; - IOD = 0xFF; } diff --git a/contrib/firmware/angie/hdl/src/angie_bitstream.ucf b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf index 9eb0c85c39..48c5b94079 100644 --- a/contrib/firmware/angie/hdl/src/angie_bitstream.ucf +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.ucf @@ -1,8 +1,8 @@ ## SPDX-License-Identifier: BSD-3-Clause ##-------------------------------------------------------------------------- -## Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 -## Design Name: NJTAG USB-JTAG Adapter FPGA source code -## Module Name: _angie_openocd.ucf +## Project Context: nanoXplore USB to JTAG/I2C Adapter Board, Spartan6 +## Design Name: ANGIE USB to JTAG/I2C Adapter FPGA source code +## Module Name: angie_bitstream.ucf ## Target Device: XC6SLX9-2 TQ144 ## Tool versions: ISE Webpack 13.2 -> 14.2 ## Author: Ahmed BOUDJELIDA nanoXplore SAS @@ -10,41 +10,65 @@ # WARNING: PullUps on JTAG inputs should be enabled after configuration # (bitgen option) since the pins are not connected. -net TRST LOC = 'P48' ; -net TMS LOC = 'P43' ; -net TCK LOC = 'P44' ; -net TDI LOC = 'P45' ; -net TDO LOC = 'P46' ; -net SRST LOC = 'P61' ; - -net SDA LOC = 'P50' ; -net SCL LOC = 'P51' ; -net SDA_DIR LOC = 'P56' ; -net SCL_DIR LOC = 'P57' ; - -net SI_TDO LOC = 'P16' ; -net SO_TRST LOC = 'P32' ; -net SO_TMS LOC = 'P27' ; -net SO_TCK LOC = 'P30' ; -net SO_TDI LOC = 'P26' ; -net SO_SRST LOC = 'P12' ; - -net SO_SDA_OUT LOC = 'P140' ; -net SO_SDA_IN LOC = 'P1' ; -net SO_SCL LOC = 'P137'; - -net ST_0 LOC = 'P29' ; -net ST_1 LOC = 'P21' ; -net ST_2 LOC = 'P11' ; - -net ST_4 LOC = 'P134' ; -net ST_5 LOC = 'P139' ; - -net FTP<0> LOC = 'P121' ; -net FTP<1> LOC = 'P120' ; -net FTP<2> LOC = 'P119' ; -net FTP<3> LOC = 'P116' ; -net FTP<4> LOC = 'P111' ; -net FTP<5> LOC = 'P112' ; -net FTP<6> LOC = 'P115' ; -net FTP<7> LOC = 'P114' ; +CONFIG VCCAUX = "3.3"; + +# Timing +# net IH24 period = 40; # Constrain at 25MHz +# net IH40 period = 25; # Constrain at 40MHz +# DCMs placement on Spartan6 +# INST S6MOD_CKMUL.H48_DCM LOC = DCM0; + +# Clock 48MHz +net IFCLK_I LOC = 'P123' ; + +net GD_IO<0> LOC = 'P48' ; +net GD_IO<1> LOC = 'P43' ; +net GD_IO<2> LOC = 'P44' ; +net GD_IO<3> LOC = 'P45' ; +net GD_IO<4> LOC = 'P46' ; +net GD_IO<5> LOC = 'P61' ; +net GD_IO<6> LOC = 'P62' ; +net GD_IO<7> LOC = 'P65' ; + +net PA2_I LOC = 'P47' ; +#net PA3_I LOC = 'P64' ; +net JPW_I LOC = 'P14' ; + +net GCTL0_I LOC = 'P70' ; +#net GCTL1_I LOC = 'P55' ; +#net GCTL2_I LOC = 'P67' ; +net GRDY1_I LOC = 'P118' ; + +#net SDA_IO LOC = 'P50' ; +net SDA_IO LOC = 'P64' ; #PA3 +#net SCL_I LOC = 'P51' ; +net SCL_I LOC = 'P39' ; #PA4 switch +net SDA_DIR_I LOC = 'P66' ; #PA0 switch +#net SCL_DIR_I LOC = 'P57' ; + +net SO_SDA_OUT_O LOC = 'P140' ; +net SO_SDA_IN_I LOC = 'P1' ; +net SO_SCL_O LOC = 'P137' ; + +net SO_TRST_O LOC = 'P32' ; +net SO_TMS_O LOC = 'P27' ; +net SO_TCK_O LOC = 'P30' ; +net SO_TDI_O LOC = 'P26' ; +net SO_SRST_O LOC = 'P12' ; +net SI_TDO_I LOC = 'P16' ; + +net ST_0_O LOC = 'P29' ; +net ST_1_O LOC = 'P21' ; +net ST_2_O LOC = 'P11' ; +net ST_3_O LOC = 'P7' ; +net ST_4_O LOC = 'P134' ; +net ST_5_O LOC = 'P139' ; + +net FTP_O<0> LOC = 'P121' ; +net FTP_O<1> LOC = 'P120' ; +net FTP_O<2> LOC = 'P119' ; +net FTP_O<3> LOC = 'P116' ; +net FTP_O<4> LOC = 'P111' ; +net FTP_O<5> LOC = 'P112' ; +net FTP_O<6> LOC = 'P115' ; +net FTP_O<7> LOC = 'P114' ; diff --git a/contrib/firmware/angie/hdl/src/angie_bitstream.vhd b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd index 6004bf2ff5..737a84ce58 100644 --- a/contrib/firmware/angie/hdl/src/angie_bitstream.vhd +++ b/contrib/firmware/angie/hdl/src/angie_bitstream.vhd @@ -1,103 +1,415 @@ -- SPDX-License-Identifier: BSD-3-Clause ---------------------------------------------------------------------------- --- Project Context: nanoXplore USB-JTAG Adapter Board, Spartan6 --- Design Name: NJTAG USB-JTAG Adapter FPGA source code --- Module Name: _angie_openocd.vhd +-- Project Context: nanoXplore USB to JTAG/I2C Adapter Board, Spartan6 +-- Design Name: ANGIE USB to JTAG/I2C Adapter FPGA source code +-- Module Name: angie_bitstream.vhd -- Target Device: XC6SLX9-2 TQ144 -- Tool versions: ISE Webpack 13.2 -> 14.2 -- Author: Ahmed BOUDJELIDA nanoXplore SAS ---------------------------------------------------------------------------- - +library work; +use work.all; library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; -library UNISIM; -use UNISIM.VComponents.all; - -entity S609 is port( - TRST : in std_logic; - TMS : in std_logic; - TCK : in std_logic; - TDI : in std_logic; - TDO : out std_logic; - SRST : in std_logic; - - SDA : inout std_logic; - SDA_DIR : in std_logic; - SCL : in std_logic; - SCL_DIR : in std_logic; - - FTP : out std_logic_vector(7 downto 0); -- Test points - SI_TDO : in std_logic; - ST_0 : out std_logic; - ST_1 : out std_logic; - ST_2 : out std_logic; - - ST_4 : out std_logic; - ST_5 : out std_logic; - - SO_SDA_OUT : out std_logic; - SO_SDA_IN : in std_logic; - SO_SCL : out std_logic; - - SO_TRST : out std_logic; - SO_TMS : out std_logic; - SO_TCK : out std_logic; - SO_TDI : out std_logic; - SO_SRST : out std_logic + +entity angie_bitstream is port( + SDA_IO : inout std_logic; + SDA_DIR_I : in std_logic; + SCL_I : in std_logic; + + JPW_I : in std_logic; --Devkit power + + SO_SDA_OUT_O : out std_logic; + SO_SDA_IN_I : in std_logic; + SO_SCL_O : out std_logic; + + ST_0_O : out std_logic; + ST_1_O : out std_logic; + ST_2_O : out std_logic; + ST_3_O : out std_logic; + ST_4_O : out std_logic; + ST_5_O : out std_logic; + + SO_TRST_O : out std_logic; + SO_TMS_O : out std_logic; + SO_TCK_O : out std_logic; + SO_TDI_O : out std_logic; + SO_SRST_O : out std_logic; + SI_TDO_I : in std_logic; + + PA2_I : in std_logic; -- GPIF IN + + -- Clock 48MHz + IFCLK_I : in std_logic; + + GCTL0_I : in std_logic; + GRDY1_I : out std_logic; + GD_IO : inout std_logic_vector(7 downto 0); + FTP_O : out std_logic_vector(15 downto 0) +); +end angie_bitstream; + +architecture A_angie_bitstream of angie_bitstream is +----------------------------------------Fifo out (PC to devkit) +signal rst_o, clk_wr_o, clk_rd_o : std_logic; +signal write_en_o, read_en_o : std_logic; +signal data_in_o, data_out_o : std_logic_vector(7 downto 0); +signal empty_o, full_o : std_logic; + +----------------------------------------Fifo in (devkit to PC) +signal rst_i, clk_wr_i, clk_rd_i : std_logic; +signal write_en_i, read_en_i : std_logic; +signal data_in_i, data_out_i : std_logic_vector(7 downto 0); +signal empty_i, full_i : std_logic; + +signal wr_o, rd_i : std_logic; + +----------------------------------------MAE +signal transit1, transit2 : std_logic; + +----------------------------------------DFF +signal pa2_dff_clk, pa2_dff_rst, pa2_dff_d, pa2_dff_q : std_logic; +signal trst_clk, trst_rst, trst_d, trst_q : std_logic; +signal tms_clk, tms_rst, tms_d, tms_q : std_logic; +signal tdi_clk, tdi_rst, tdi_d, tdi_q : std_logic; +signal tdo_clk, tdo_rst, tdo_d, tdo_q : std_logic; + +----------------------------------------clk_div +signal clk_div_in, clk_div_out, reset_clk_div : std_logic; +signal clk_div2_in, clk_div2_out, reset_clk_div2 : std_logic; + +----------------------------------------MAE +type State_Type is (IDLE, WRITE_OUT, WRITE_IN, DELAY, READ_IN); +signal state, state2 : State_Type; +signal reset_mae, reset_mae2 : std_logic; + +-- Add Component DFF +component DFF + Port ( + clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic + ); +end component; + +-- Add Component Clk_div +component clk_div +Port ( + clk_in : in std_logic; + reset : in std_logic; + clk_out : out std_logic ); -end S609; +end component; + +-- Add component FIFO 64B +component fifo_generator_v9_3 +PORT ( + rst : IN STD_LOGIC; + wr_clk : IN STD_LOGIC; + rd_clk : IN STD_LOGIC; + din : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + wr_en : IN STD_LOGIC; + rd_en : IN STD_LOGIC; + dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + full : OUT STD_LOGIC; + empty : OUT STD_LOGIC + ); +end component; + +signal state1_debug, state2_debug : std_logic; -architecture A_S609 of S609 is begin +-------------------------------------------------------------I2C : +SDA_IO <= not(SO_SDA_IN_I) when (SDA_DIR_I = '1') else 'Z'; +SO_SDA_OUT_O <= SDA_IO; +ST_5_O <= SDA_DIR_I; ---Directions: -ST_0 <= '0'; -ST_1 <= '1'; +SO_SCL_O <= SCL_I when (JPW_I = '1') else '0'; +ST_4_O <= '0'; ---TDO: -TDO <= not SI_TDO; +------------------------------------------------------------JTAG : +-- Instantiate the Clk div by 10 +clk_div_inst : clk_div +port map ( + clk_in => clk_div_in, + reset => reset_clk_div, + clk_out => clk_div_out +); +-- Instantiate the Clk div by 10 +clk_div2_inst : clk_div +port map ( + clk_in => clk_div2_in, + reset => reset_clk_div2, + clk_out => clk_div2_out +); ---TRST - TCK - TMS - TDI: -SO_TRST <= TRST; -SO_TMS <= TMS; -SO_TCK <= TCK; -SO_TDI <= TDI; -ST_2 <= SRST; -SO_SRST <= '0'; +-- Instantiate DFFs +DFF_inst_PA2 : DFF +port map ( + clk => pa2_dff_clk, + reset => pa2_dff_rst, + d => pa2_dff_d, + q => pa2_dff_q +); + +DFF_inst_TRST : DFF +port map ( + clk => trst_clk, + reset => trst_rst, + d => trst_d, + q => trst_q +); -SO_SCL <= SCL; +DFF_inst_TMS : DFF +port map ( + clk => tms_clk, + reset => tms_rst, + d => tms_d, + q => tms_q +); -SDA <= not(SO_SDA_IN) when (SDA_DIR = '1') else 'Z'; -SO_SDA_OUT <= SDA; +DFF_inst_TDI : DFF +port map ( + clk => tdi_clk, + reset => tdi_rst, + d => tdi_d, + q => tdi_q +); + +DFF_inst_TDO : DFF +port map ( + clk => tdo_clk, + reset => tdo_rst, + d => tdo_d, + q => tdo_q +); -process(SDA_DIR) +-- Instantiate the FIFO OUT +U0 : fifo_generator_v9_3 +port map ( + rst => rst_o, + wr_clk => clk_wr_o, + rd_clk => clk_rd_o, + din => data_in_o, + wr_en => write_en_o, + rd_en => read_en_o, + dout => data_out_o, + full => full_o, + empty => empty_o +); +-- Instantiate the FIFO IN +U1 : fifo_generator_v9_3 +port map ( + rst => rst_i, + wr_clk => clk_wr_i, + rd_clk => clk_rd_i, + din => data_in_i, + wr_en => write_en_i, + rd_en => read_en_i, + dout => data_out_i, + full => full_i, + empty => empty_i +); + +--------------- clock dividers +clk_div_in <= IFCLK_I; -- 48Mhz +clk_div2_in <= clk_div_out; -- 24Mhz + +--------------- DFFs +pa2_dff_clk <= IFCLK_I; +trst_clk <= IFCLK_I; +tms_clk <= IFCLK_I; +tdi_clk <= IFCLK_I; +tdo_clk <= IFCLK_I; + +--------------- FIFOs +clk_wr_o <= IFCLK_I; +clk_rd_o <= clk_div2_out; +clk_wr_i <= clk_div2_out; +clk_rd_i <= IFCLK_I; + +--------------------------- GPIF ready : +GRDY1_I <= '1'; + +-------------------------------PA2 DFF : +pa2_dff_rst <= '0'; +pa2_dff_d <= PA2_I; + +-------------------- FX2<->Fifo Enable pins : +write_en_o <= not(wr_o) and not(GCTL0_I); +read_en_i <= not(rd_i) and not(GCTL0_I); + +---------------- FX2->Fifo Data : +data_in_o <= GD_IO; + +------------ FIFO_OUT->Devkit : +SO_TRST_O <= trst_q; +trst_d <= data_out_o(4); +SO_TMS_O <= tms_q; +tms_d <= data_out_o(3); +SO_TDI_O <= tdi_q; +tdi_d <= data_out_o(1); +------------ +SO_TCK_O <= data_out_o(0); + +-------------------- FIFO_OUT->FIFO_IN : +--data_in_i <= data_out_o; + +-------------------- FIFO_IN<-Devkit : +data_in_i(0) <= '0'; +data_in_i(1) <= '0'; +data_in_i(2) <= tdo_q; +tdo_d <= not SI_TDO_I; +data_in_i(3) <= '0'; +data_in_i(4) <= '0'; +data_in_i(5) <= '0'; +data_in_i(6) <= '0'; +data_in_i(7) <= '0'; + +-------------------- FX2<-FIFO_IN : +GD_IO <= data_out_i when (state = READ_IN) else "ZZZZZZZZ"; + +state1_debug <= '1' when state = READ_IN else '0'; +state2_debug <= '1' when state2 = WRITE_IN else '0'; + +--Points de test: +FTP_O(0) <= IFCLK_I; +FTP_O(1) <= GCTL0_I; +FTP_O(2) <= GD_IO(0); +FTP_O(3) <= GD_IO(1); +FTP_O(4) <= JPW_I; +FTP_O(5) <= PA2_I; +FTP_O(6) <= empty_o; +FTP_O(7) <= not SI_TDO_I; + +process(pa2_dff_d, pa2_dff_q) begin - if(SDA_DIR = '0') then - ST_5 <= '0'; - else - ST_5 <= '1'; - end if; + if pa2_dff_d = '0' and pa2_dff_q = '1' then + reset_mae <= '1'; -- Reset State Machine + reset_mae2 <= '1'; -- Reset State Machine + rst_o <= '1'; -- Reset OUT + rst_i <= '1'; -- Reset IN + reset_clk_div <= '1'; + reset_clk_div2 <= '1'; + trst_rst <= '1'; + tms_rst <= '1'; + tdi_rst <= '1'; + tdo_rst <= '1'; + else + reset_mae <= '0'; -- No Reset State Machine + reset_mae2 <= '0'; -- Reset State Machine + rst_o <= '0'; -- No Reset OUT + rst_i <= '0'; -- No Reset IN + reset_clk_div <= '0'; + reset_clk_div2 <= '0'; + trst_rst <= '0'; + tms_rst <= '0'; + tdi_rst <= '0'; + tdo_rst <= '0'; + end if; end process; -process(SCL_DIR) +process(clk_div2_out, reset_mae2) begin - if(SCL_DIR = '0') then - ST_4 <= '0'; - else - ST_4 <= '1'; - end if; + if reset_mae2 = '1' then + state2 <= IDLE; + elsif rising_edge(clk_div2_out) then + case state2 is + when IDLE => + read_en_o <= '0'; -- Disable read OUT + write_en_i <= '0'; -- Disable write IN + transit2 <= '1'; + if transit1 = '0' and PA2_I = '0' then + state2 <= WRITE_IN; + else + state2 <= IDLE; + end if; + + when WRITE_IN => + read_en_o <= '1'; -- Enable read OUT + write_en_i <= '1'; -- Enable write IN + if PA2_I = '1' then + state2 <= DELAY; -- Change state to DELAY + else + state2 <= WRITE_IN; -- Stay in WRITE_IN state + end if; + + when DELAY => + transit2 <= '0'; -- Enable READ IN + if empty_o = '1' then + read_en_o <= '0'; -- Disable read OUT + write_en_i <= '0'; -- Disable write IN + state2 <= IDLE; -- Change state to IDLE + else + state2 <= DELAY; -- Stay in READ_IN state + end if; + + when others => + state2 <= IDLE; + end case; + end if; end process; ---Points de test: -FTP(0) <= SDA; -FTP(1) <= SCL; -FTP(2) <= not(SO_SDA_IN); -FTP(3) <= SDA_DIR; -FTP(5) <= SRST; -FTP(4) <= SI_TDO; -FTP(6) <= '1'; -FTP(7) <= '1'; - -end A_S609; +process(IFCLK_I, reset_mae) +begin + if reset_mae = '1' then + state <= IDLE; + elsif rising_edge(IFCLK_I) then + case state is + when IDLE => + wr_o <= '1'; -- Disable write OUT + rd_i <= '1'; -- Disable read IN + transit1 <= '1'; + if PA2_I = '0' then + state <= WRITE_OUT; -- Change state to RESET + else + state <= IDLE; -- Stay in IDLE state + end if; + + when WRITE_OUT => + wr_o <= '0'; -- Enable write OUT + if empty_o = '0' then + transit1 <= '0'; -- Enable Rd OUT & Wr IN + state <= DELAY; -- Change state to DELAY + else + state <= WRITE_OUT; -- Stay in WRITE_OUT state + end if; + + when DELAY => + if transit2 = '0' then + wr_o <= '1'; -- Disable write OUT + state <= READ_IN; + else + state <= DELAY; + end if; + + when READ_IN => + rd_i <= '0'; -- Enable read IN + if empty_i = '1' then + rd_i <= '1'; -- Enable read IN + state <= IDLE; -- Change state to IDLE + else + state <= READ_IN; -- Stay in READ_IN state + end if; + + when others => + state <= IDLE; + end case; + end if; +end process; + +-- OUT signals direction +-- TRST, TMS, TCK and TDI : out +ST_0_O <= '0'; +-- TDO : in +ST_1_O <= '1'; +-- SRST : out +ST_2_O <= '1'; +SO_SRST_O <= '0'; +-- MOD : in +ST_3_O <= '1'; + +end A_angie_bitstream; diff --git a/contrib/firmware/angie/hdl/src/clk_div.vhd b/contrib/firmware/angie/hdl/src/clk_div.vhd new file mode 100644 index 0000000000..e69850d572 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/clk_div.vhd @@ -0,0 +1,33 @@ +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.ALL; + +entity clk_div is + Port ( + clk_in : in std_logic; + reset : in std_logic; + clk_out : out std_logic + ); +end clk_div; + +architecture behavioral of clk_div is + -- Division factor N = 4, so we need a 2-bit counter (2^2 = 4) +-- signal counter : unsigned(1 downto 0) := (others => '0'); + signal tmp : std_logic; +begin + process(clk_in, reset) + begin + if reset = '1' then +-- counter <= (others => '0'); + tmp <= '0'; + elsif rising_edge(clk_in) then +-- if counter = (2**2 - 1) then +-- counter <= (others => '0'); + tmp <= NOT tmp; -- Toggle the output clock +-- else +-- counter <= counter + 1; +-- end if; + end if; + end process; + clk_out <= tmp; +end behavioral; \ No newline at end of file diff --git a/contrib/firmware/angie/hdl/src/dff.vhd b/contrib/firmware/angie/hdl/src/dff.vhd new file mode 100644 index 0000000000..c5ccf06d33 --- /dev/null +++ b/contrib/firmware/angie/hdl/src/dff.vhd @@ -0,0 +1,23 @@ +library ieee; +use ieee.std_logic_1164.ALL; +use ieee.std_logic_arith.ALL; +use ieee.std_logic_unsigned.ALL; + +entity DFF is +port ( clk : in std_logic; + reset : in std_logic; + d : in std_logic; + q : out std_logic); +end DFF; + +architecture Behavioral of DFF is +begin + process(clk, reset) + begin + if reset = '1' then + q <= '1'; -- Reset output to 0 + elsif rising_edge(clk) then + q <= d; -- Capture D at the rising edge of the clock + end if; + end process; +end Behavioral; \ No newline at end of file diff --git a/contrib/loaders/flash/at91sam7x/main.c b/contrib/loaders/flash/at91sam7x/main.c index a29c6e605b..e988e1848b 100644 --- a/contrib/loaders/flash/at91sam7x/main.c +++ b/contrib/loaders/flash/at91sam7x/main.c @@ -70,23 +70,23 @@ int main (void) for (;;) { cmd = dcc_rd(); switch (cmd&OCL_CMD_MASK) { - case OCL_PROBE: - dcc_wr(OCL_CMD_DONE | flash_init()); - dcc_wr(0x100000); /* base */ - dcc_wr(flash_page_count*flash_page_size); /* size */ - dcc_wr(1); /* num_sectors */ - dcc_wr(4096 | ((unsigned long) flash_page_size << 16)); /* buflen and bufalign */ - break; - case OCL_ERASE_ALL: - dcc_wr(OCL_CMD_DONE | flash_erase_all()); - break; - case OCL_FLASH_BLOCK: - cmd_flash(cmd); - break; - default: - /* unknown command */ - dcc_wr(OCL_CMD_ERR); - break; + case OCL_PROBE: + dcc_wr(OCL_CMD_DONE | flash_init()); + dcc_wr(0x100000); /* base */ + dcc_wr(flash_page_count * flash_page_size); /* size */ + dcc_wr(1); /* num_sectors */ + dcc_wr(4096 | ((unsigned long)flash_page_size << 16)); /* buflen and bufalign */ + break; + case OCL_ERASE_ALL: + dcc_wr(OCL_CMD_DONE | flash_erase_all()); + break; + case OCL_FLASH_BLOCK: + cmd_flash(cmd); + break; + default: + /* unknown command */ + dcc_wr(OCL_CMD_ERR); + break; } } diff --git a/contrib/loaders/flash/at91sam7x/samflash.c b/contrib/loaders/flash/at91sam7x/samflash.c index fcb76fbf98..8be0bdbb84 100644 --- a/contrib/loaders/flash/at91sam7x/samflash.c +++ b/contrib/loaders/flash/at91sam7x/samflash.c @@ -22,38 +22,38 @@ int flash_init(void) nvpsiz = (inr(DBGU_CIDR) >> 8)&0xf; switch (nvpsiz) { - case 3: - /* AT91SAM7x32 */ - flash_page_count = 256; - flash_page_size = 128; - flash_lock_pages = 256/8; - break; - case 5: - /* AT91SAM7x64 */ - flash_page_count = 512; - flash_page_size = 128; - flash_lock_pages = 512/16; - break; - case 7: - /* AT91SAM7x128*/ - flash_page_count = 512; - flash_page_size = 256; - flash_lock_pages = 512/8; - break; - case 9: - /* AT91SAM7x256 */ - flash_page_count = 1024; - flash_page_size = 256; - flash_lock_pages = 1024/16; - break; - case 10: - /* AT91SAM7x512 */ - flash_page_count = 2048; - flash_page_size = 256; - flash_lock_pages = 2048/32; - break; - default: - return FLASH_STAT_INITE; + case 3: + /* AT91SAM7x32 */ + flash_page_count = 256; + flash_page_size = 128; + flash_lock_pages = 256 / 8; + break; + case 5: + /* AT91SAM7x64 */ + flash_page_count = 512; + flash_page_size = 128; + flash_lock_pages = 512 / 16; + break; + case 7: + /* AT91SAM7x128*/ + flash_page_count = 512; + flash_page_size = 256; + flash_lock_pages = 512 / 8; + break; + case 9: + /* AT91SAM7x256 */ + flash_page_count = 1024; + flash_page_size = 256; + flash_lock_pages = 1024 / 16; + break; + case 10: + /* AT91SAM7x512 */ + flash_page_count = 2048; + flash_page_size = 256; + flash_lock_pages = 2048 / 32; + break; + default: + return FLASH_STAT_INITE; } return FLASH_STAT_OK; } diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c index 1bc72d5921..3c1988f112 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c @@ -52,7 +52,7 @@ static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t addres /* Clear the IRQ flags */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F; /* Load the flash address to write */ - *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2); + *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint32_t)((address + index - MFB_BOTTOM) >> 2); /* Prepare and load the data to flash */ *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0]; *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1]; diff --git a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc index ff05634bb2..146a6bedeb 100644 --- a/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc +++ b/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc @@ -1,17 +1,19 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x05,0x93,0x43,0x68,0x14,0x9e,0x09,0x93,0x05,0x9b,0x05,0x00,0x07,0x91,0x06,0x92, -0x01,0x24,0xb1,0x46,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, -0x2b,0x68,0x00,0x2b,0x61,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x5e,0xd9,0x6b,0x68, -0x07,0x9a,0xd3,0x1a,0x0f,0x2b,0xef,0xdd,0x4a,0x46,0x00,0x21,0x03,0x93,0xd1,0x60, -0x00,0x2b,0x42,0xd0,0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x00,0x92, -0x48,0x22,0x4a,0x44,0x93,0x46,0x4c,0x22,0x27,0x4f,0x4a,0x44,0xbc,0x46,0x4e,0x46, -0x92,0x46,0x06,0x99,0x4b,0x46,0x61,0x44,0x08,0x00,0x00,0x99,0x18,0x36,0x6a,0x68, -0x08,0x95,0x8c,0x46,0x55,0x46,0xda,0x46,0xb3,0x46,0x10,0x33,0x04,0x92,0x11,0x68, -0x5e,0x46,0x00,0x91,0x51,0x68,0x97,0x68,0x01,0x91,0xd1,0x68,0x02,0x91,0x3f,0x21, -0x19,0x60,0x81,0x03,0x09,0x0c,0x31,0x60,0x46,0x46,0x00,0x99,0x31,0x60,0x66,0x46, -0x01,0x99,0x31,0x60,0x56,0x46,0x02,0x99,0x37,0x60,0x29,0x60,0xcc,0x26,0x49,0x46, -0x0e,0x60,0x19,0x68,0x0c,0x42,0xfc,0xd0,0x04,0x99,0x03,0x9e,0x10,0x32,0x10,0x30, -0x51,0x1a,0x8e,0x42,0xdb,0xd8,0x08,0x9d,0x6a,0x60,0x03,0x9a,0x06,0x9b,0x94,0x46, -0x63,0x44,0x06,0x93,0x07,0x9a,0x6b,0x68,0x9a,0x42,0x01,0xd8,0x09,0x9b,0x6b,0x60, -0x05,0x9b,0x03,0x9a,0x9b,0x1a,0x05,0x93,0x96,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68, -0x9b,0x1a,0x9f,0xd5,0x90,0xe7,0xc0,0x46,0x00,0x00,0xfc,0xef, +0x16,0x9e,0x05,0x00,0x01,0x24,0xb1,0x46,0x06,0x93,0x43,0x68,0x08,0x91,0x07,0x92, +0x09,0x93,0x06,0x9b,0x00,0x2b,0x6f,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0xfb,0xd0, +0x2b,0x68,0x00,0x2b,0x68,0xd0,0x6a,0x68,0x2b,0x68,0x9a,0x42,0x65,0xd9,0x6b,0x68, +0x08,0x9a,0xd3,0x1a,0x0b,0x93,0x0b,0x9b,0x0f,0x2b,0xea,0xdd,0x4a,0x46,0x00,0x21, +0x0b,0x9b,0xd1,0x60,0x04,0x93,0x00,0x2b,0x43,0xd0,0x31,0x4a,0x07,0x9b,0x94,0x46, +0x40,0x22,0x4a,0x44,0x90,0x46,0x44,0x22,0x4a,0x44,0x63,0x44,0x94,0x46,0x48,0x22, +0x4a,0x44,0x93,0x46,0x05,0x93,0x4c,0x22,0x4b,0x46,0x4a,0x44,0x10,0x33,0x4e,0x46, +0x92,0x46,0x00,0x93,0x2b,0x00,0x18,0x36,0x6a,0x68,0x55,0x46,0xb2,0x46,0x5e,0x46, +0x9b,0x46,0x10,0x68,0x57,0x68,0x01,0x90,0x3f,0x20,0x00,0x9b,0x02,0x97,0x97,0x68, +0x03,0x97,0xd7,0x68,0x18,0x60,0x53,0x46,0x05,0x98,0x40,0x18,0x80,0x08,0x18,0x60, +0x43,0x46,0x01,0x98,0x18,0x60,0x63,0x46,0x02,0x98,0x18,0x60,0x03,0x98,0x4b,0x46, +0x30,0x60,0xcc,0x20,0x2f,0x60,0x18,0x60,0x00,0x9b,0x18,0x68,0x04,0x42,0xfc,0xd0, +0x58,0x46,0x10,0x32,0x42,0x60,0x04,0x98,0x10,0x31,0x00,0x93,0x88,0x42,0xd8,0xd8, +0x5d,0x46,0x07,0x9a,0x0b,0x9b,0x94,0x46,0x9c,0x44,0x63,0x46,0x08,0x9a,0x07,0x93, +0x6b,0x68,0x93,0x42,0x01,0xd3,0x09,0x9b,0x6b,0x60,0x06,0x9a,0x0b,0x9b,0xd3,0x1a, +0x06,0x93,0x06,0x9b,0x00,0x2b,0x8f,0xd1,0x00,0xbe,0x2b,0x68,0x6a,0x68,0x9b,0x1a, +0x0b,0x93,0x0b,0x9b,0x00,0x2b,0x00,0xdb,0x95,0xe7,0x00,0x23,0x0b,0x93,0x92,0xe7, +0x00,0x00,0xfc,0xef, diff --git a/contrib/loaders/flash/cc26xx/main.c b/contrib/loaders/flash/cc26xx/main.c index 6b626a3b84..bd5eaf3354 100644 --- a/contrib/loaders/flash/cc26xx/main.c +++ b/contrib/loaders/flash/cc26xx/main.c @@ -98,35 +98,32 @@ int main(void) /* Perform requested task */ switch (g_cfg[g_curr_buf].cmd) { - case CMD_ERASE_ALL: - status = flashloader_erase_all(); - break; - case CMD_PROGRAM: - status = - flashloader_program( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_AND_PROGRAM: - status = - flashloader_erase_and_program( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: - status = - flashloader_program_with_retain( - (uint8_t *)g_cfg[g_curr_buf].buf_addr, - g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); - break; - case CMD_ERASE_SECTORS: - status = - flashloader_erase_sectors(g_cfg[g_curr_buf].dest, - g_cfg[g_curr_buf].len); - break; - default: - status = STATUS_FAILED_UNKNOWN_COMMAND; - break; + case CMD_ERASE_ALL: + status = flashloader_erase_all(); + break; + case CMD_PROGRAM: + status = + flashloader_program((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM: + status = + flashloader_erase_and_program((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_AND_PROGRAM_WITH_RETAIN: + status = + flashloader_program_with_retain((uint8_t *)g_cfg[g_curr_buf].buf_addr, + g_cfg[g_curr_buf].dest, g_cfg[g_curr_buf].len); + break; + case CMD_ERASE_SECTORS: + status = + flashloader_erase_sectors(g_cfg[g_curr_buf].dest, + g_cfg[g_curr_buf].len); + break; + default: + status = STATUS_FAILED_UNKNOWN_COMMAND; + break; } restore_cache_state(); diff --git a/contrib/loaders/flash/max32xxx/Makefile b/contrib/loaders/flash/max32xxx/Makefile index 1565c811c1..fe7666f840 100644 --- a/contrib/loaders/flash/max32xxx/Makefile +++ b/contrib/loaders/flash/max32xxx/Makefile @@ -1,21 +1,30 @@ # SPDX-License-Identifier: GPL-2.0-or-later +TARGET=max32xxx_write +ENTRY=algo_write + BIN2C = ../../../../src/helper/bin2char.sh -CROSS_COMPILE ?= arm-none-eabi- -AS = $(CROSS_COMPILE)as -OBJCOPY = $(CROSS_COMPILE)objcopy +PREFIX=arm-none-eabi +CFLAGS=-mthumb -mcpu=cortex-m4 -Wa,-mimplicit-it=thumb + +all: $(TARGET).inc -all: max32xxx.inc +%.o: %.c + $(PREFIX)-gcc $(CFLAGS) -Os -Wall -c ${<} -o ${@} -%.elf: %.s - $(AS) $< -o $@ +%.elf: %.o + $(PREFIX)-ld -nostdlib --entry $(ENTRY) ${<} -o ${@} + $(PREFIX)-size ${@} %.bin: %.elf - $(OBJCOPY) -Obinary $< $@ + $(PREFIX)-objcopy -O binary ${<} ${@} %.inc: %.bin $(BIN2C) < $< > $@ +%.dasm: %.o + $(PREFIX)-objdump -S ${<} > ${TARGET}.dasm + clean: - -rm -f *.elf *.bin *.inc + rm -rf $(TARGET).bin $(TARGET).elf $(TARGET).o $(TARGET).dasm $(TARGET).inc diff --git a/contrib/loaders/flash/max32xxx/algo_options.h b/contrib/loaders/flash/max32xxx/algo_options.h new file mode 100644 index 0000000000..a4902e08a0 --- /dev/null +++ b/contrib/loaders/flash/max32xxx/algo_options.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#define OPTIONS_128 0x01 /* Perform 128 bit flash writes */ +#define OPTIONS_ENC 0x02 /* Encrypt the flash contents */ +#define OPTIONS_AUTH 0x04 /* Authenticate the flash contents */ +#define OPTIONS_COUNT 0x08 /* Add counter values to authentication */ +#define OPTIONS_INTER 0x10 /* Interleave the authentication and count values*/ +#define OPTIONS_RELATIVE_XOR 0x20 /* Only XOR the offset of the address when encrypting */ +#define OPTIONS_KEYSIZE 0x40 /* Use a 256 bit KEY */ diff --git a/contrib/loaders/flash/max32xxx/flc_regs.h b/contrib/loaders/flash/max32xxx/flc_regs.h new file mode 100644 index 0000000000..9179589ddd --- /dev/null +++ b/contrib/loaders/flash/max32xxx/flc_regs.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _FLC_REGS_H_ +#define _FLC_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup flc + * @defgroup flc_registers Registers + * @brief Registers, Bit Masks and Bit Positions for the FLC Peripheral Module. + * @description Flash Memory Control. + */ + +/** + * @ingroup flc_registers + * Structure type to access the FLC Registers. + */ +struct mxc_flc_regs { + __IO uint32_t addr; /**< \b 0x00:<\tt> FLC ADDR Register */ + __IO uint32_t clkdiv; /**< \b 0x04:<\tt> FLC CLKDIV Register */ + __IO uint32_t cn; /**< \b 0x08:<\tt> FLC CN Register */ + __R uint32_t rsv_0xc_0x23[6]; + __IO uint32_t intr; /**< \b 0x024:<\tt> FLC INTR Register */ + __R uint32_t rsv_0x28_0x2f[2]; + __IO uint32_t data[4]; /**< \b 0x30:<\tt> FLC DATA Register */ + __O uint32_t acntl; /**< \b 0x40:<\tt> FLC ACNTL Register */ +}; + +/* Register offsets for module FLC */ +/** + * @ingroup flc_registers + * @defgroup FLC_Register_Offsets Register Offsets + * @brief FLC Peripheral Register Offsets from the FLC Base Peripheral Address. + * @{ + */ +#define MXC_R_FLC_ADDR ((uint32_t)0x00000000UL) /**< Offset from FLC Base Address: 0x0x000 */ +#define MXC_R_FLC_CLKDIV ((uint32_t)0x00000004UL) /**< Offset from FLC Base Address: 0x0x004 */ +#define MXC_R_FLC_CN ((uint32_t)0x00000008UL) /**< Offset from FLC Base Address: 0x0x008 */ +#define MXC_R_FLC_INTR ((uint32_t)0x00000024UL) /**< Offset from FLC Base Address: 0x0x024 */ +#define MXC_R_FLC_DATA ((uint32_t)0x00000030UL) /**< Offset from FLC Base Address: 0x0x030 */ +#define MXC_R_FLC_ACNTL ((uint32_t)0x00000040UL) /**< Offset from FLC Base Address: 0x0x040 */ +/**@} end of group flc_registers */ + +/** + * @ingroup flc_registers + * @defgroup ADDR_Register + * @brief Flash Write Address. + * @{ + */ +#define MXC_F_FLC_ADDR_ADDR_POS 0 /**< ADDR_ADDR Position */ +#define MXC_F_FLC_ADDR_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_ADDR_ADDR_POS)) /**< ADDR_ADDR Mask */ + +/**@} end of group ADDR_Register */ + +/** + * @ingroup flc_registers + * @defgroup CLKDIV_Register + * @brief Flash Clock Divide. The clock (PLL0) is divided by this value to generate a 1 + * MHz clock for Flash controller. + * @{ + */ +#define MXC_F_FLC_CLKDIV_CLKDIV_POS 0 /**< CLKDIV_CLKDIV Position */ +#define MXC_F_FLC_CLKDIV_CLKDIV ((uint32_t)(0xFFUL << MXC_F_FLC_CLKDIV_CLKDIV_POS)) /**< CLKDIV_CLKDIV Mask */ + +/**@} end of group CLKDIV_Register */ + +/** + * @ingroup flc_registers + * @defgroup CN_Register + * @brief Flash Control Register. + * @{ + */ +#define MXC_F_FLC_CN_WR_POS 0 /**< CN_WR Position */ +#define MXC_F_FLC_CN_WR ((uint32_t)(0x1UL << MXC_F_FLC_CN_WR_POS)) /**< CN_WR Mask */ +#define MXC_V_FLC_CN_WR_COMPLETE ((uint32_t)0x0UL) /**< CN_WR_COMPLETE Value */ +#define MXC_S_FLC_CN_WR_COMPLETE (MXC_V_FLC_CN_WR_COMPLETE << MXC_F_FLC_CN_WR_POS) /**< CN_WR_COMPLETE Setting */ +#define MXC_V_FLC_CN_WR_START ((uint32_t)0x1UL) /**< CN_WR_START Value */ +#define MXC_S_FLC_CN_WR_START (MXC_V_FLC_CN_WR_START << MXC_F_FLC_CN_WR_POS) /**< CN_WR_START Setting */ + +#define MXC_F_FLC_CN_ME_POS 1 /**< CN_ME Position */ +#define MXC_F_FLC_CN_ME ((uint32_t)(0x1UL << MXC_F_FLC_CN_ME_POS)) /**< CN_ME Mask */ + +#define MXC_F_FLC_CN_PGE_POS 2 /**< CN_PGE Position */ +#define MXC_F_FLC_CN_PGE ((uint32_t)(0x1UL << MXC_F_FLC_CN_PGE_POS)) /**< CN_PGE Mask */ + +#define MXC_F_FLC_CN_WDTH_POS 4 /**< CN_WDTH Position */ +#define MXC_F_FLC_CN_WDTH ((uint32_t)(0x1UL << MXC_F_FLC_CN_WDTH_POS)) /**< CN_WDTH Mask */ +#define MXC_V_FLC_CN_WDTH_SIZE128 ((uint32_t)0x0UL) /**< CN_WDTH_SIZE128 Value */ +#define MXC_S_FLC_CN_WDTH_SIZE128 (MXC_V_FLC_CN_WDTH_SIZE128 << MXC_F_FLC_CN_WDTH_POS) /**< CN_WDTH_SIZE128 Setting */ +#define MXC_V_FLC_CN_WDTH_SIZE32 ((uint32_t)0x1UL) /**< CN_WDTH_SIZE32 Value */ +#define MXC_S_FLC_CN_WDTH_SIZE32 (MXC_V_FLC_CN_WDTH_SIZE32 << MXC_F_FLC_CN_WDTH_POS) /**< CN_WDTH_SIZE32 Setting */ + +#define MXC_F_FLC_CN_ERASE_CODE_POS 8 /**< CN_ERASE_CODE Position */ +#define MXC_F_FLC_CN_ERASE_CODE ((uint32_t)(0xFFUL << MXC_F_FLC_CN_ERASE_CODE_POS)) /**< CN_ERASE_CODE Mask */ +#define MXC_V_FLC_CN_ERASE_CODE_NOP ((uint32_t)0x0UL) /**< CN_ERASE_CODE_NOP Value */ +#define MXC_S_FLC_CN_ERASE_CODE_NOP \ + (MXC_V_FLC_CN_ERASE_CODE_NOP << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_NOP Setting */ +#define MXC_V_FLC_CN_ERASE_CODE_ERASEPAGE ((uint32_t)0x55UL) /**< CN_ERASE_CODE_ERASEPAGE Value */ +#define MXC_S_FLC_CN_ERASE_CODE_ERASEPAGE \ + (MXC_V_FLC_CN_ERASE_CODE_ERASEPAGE << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_ERASEPAGE Setting */ +#define MXC_V_FLC_CN_ERASE_CODE_ERASEALL ((uint32_t)0xAAUL) /**< CN_ERASE_CODE_ERASEALL Value */ +#define MXC_S_FLC_CN_ERASE_CODE_ERASEALL \ + (MXC_V_FLC_CN_ERASE_CODE_ERASEALL << MXC_F_FLC_CN_ERASE_CODE_POS) /**< CN_ERASE_CODE_ERASEALL Setting */ + +#define MXC_F_FLC_CN_PEND_POS 24 /**< CN_PEND Position */ +#define MXC_F_FLC_CN_PEND ((uint32_t)(0x1UL << MXC_F_FLC_CN_PEND_POS)) /**< CN_PEND Mask */ +#define MXC_V_FLC_CN_PEND_IDLE ((uint32_t)0x0UL) /**< CN_PEND_IDLE Value */ +#define MXC_S_FLC_CN_PEND_IDLE (MXC_V_FLC_CN_PEND_IDLE << MXC_F_FLC_CN_PEND_POS) /**< CN_PEND_IDLE Setting */ +#define MXC_V_FLC_CN_PEND_BUSY ((uint32_t)0x1UL) /**< CN_PEND_BUSY Value */ +#define MXC_S_FLC_CN_PEND_BUSY (MXC_V_FLC_CN_PEND_BUSY << MXC_F_FLC_CN_PEND_POS) /**< CN_PEND_BUSY Setting */ + +#define MXC_F_FLC_CN_LVE_POS 25 /**< CN_LVE Position */ +#define MXC_F_FLC_CN_LVE ((uint32_t)(0x1UL << MXC_F_FLC_CN_LVE_POS)) /**< CN_LVE Mask */ +#define MXC_V_FLC_CN_LVE_DIS ((uint32_t)0x0UL) /**< CN_LVE_DIS Value */ +#define MXC_S_FLC_CN_LVE_DIS (MXC_V_FLC_CN_LVE_DIS << MXC_F_FLC_CN_LVE_POS) /**< CN_LVE_DIS Setting */ +#define MXC_V_FLC_CN_LVE_EN ((uint32_t)0x1UL) /**< CN_LVE_EN Value */ +#define MXC_S_FLC_CN_LVE_EN (MXC_V_FLC_CN_LVE_EN << MXC_F_FLC_CN_LVE_POS) /**< CN_LVE_EN Setting */ + +#define MXC_F_FLC_CN_BRST_POS 27 /**< CN_BRST Position */ +#define MXC_F_FLC_CN_BRST ((uint32_t)(0x1UL << MXC_F_FLC_CN_BRST_POS)) /**< CN_BRST Mask */ +#define MXC_V_FLC_CN_BRST_DISABLE ((uint32_t)0x0UL) /**< CN_BRST_DISABLE Value */ +#define MXC_S_FLC_CN_BRST_DISABLE (MXC_V_FLC_CN_BRST_DISABLE << MXC_F_FLC_CN_BRST_POS) /**< CN_BRST_DISABLE Setting */ +#define MXC_V_FLC_CN_BRST_ENABLE ((uint32_t)0x1UL) /**< CN_BRST_ENABLE Value */ +#define MXC_S_FLC_CN_BRST_ENABLE (MXC_V_FLC_CN_BRST_ENABLE << MXC_F_FLC_CN_BRST_POS) /**< CN_BRST_ENABLE Setting */ + +#define MXC_F_FLC_CN_UNLOCK_POS 28 /**< CN_UNLOCK Position */ +#define MXC_F_FLC_CN_UNLOCK ((uint32_t)(0xFUL << MXC_F_FLC_CN_UNLOCK_POS)) /**< CN_UNLOCK Mask */ +#define MXC_V_FLC_CN_UNLOCK_UNLOCKED ((uint32_t)0x2UL) /**< CN_UNLOCK_UNLOCKED Value */ +#define MXC_S_FLC_CN_UNLOCK_UNLOCKED \ + (MXC_V_FLC_CN_UNLOCK_UNLOCKED << MXC_F_FLC_CN_UNLOCK_POS) /**< CN_UNLOCK_UNLOCKED Setting */ +#define MXC_V_FLC_CN_UNLOCK_LOCKED ((uint32_t)0x3UL) /**< CN_UNLOCK_LOCKED Value */ +#define MXC_S_FLC_CN_UNLOCK_LOCKED \ + (MXC_V_FLC_CN_UNLOCK_LOCKED << MXC_F_FLC_CN_UNLOCK_POS) /**< CN_UNLOCK_LOCKED Setting */ + +/**@} end of group CN_Register */ + +/** + * @ingroup flc_registers + * @defgroup INTR_Register + * @brief Flash Interrupt Register. + * @{ + */ +#define MXC_F_FLC_INTR_DONE_POS 0 /**< INTR_DONE Position */ +#define MXC_F_FLC_INTR_DONE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_DONE_POS)) /**< INTR_DONE Mask */ +#define MXC_V_FLC_INTR_DONE_INACTIVE ((uint32_t)0x0UL) /**< INTR_DONE_INACTIVE Value */ +#define MXC_S_FLC_INTR_DONE_INACTIVE \ + (MXC_V_FLC_INTR_DONE_INACTIVE << MXC_F_FLC_INTR_DONE_POS) /**< INTR_DONE_INACTIVE Setting */ +#define MXC_V_FLC_INTR_DONE_PENDING ((uint32_t)0x1UL) /**< INTR_DONE_PENDING Value */ +#define MXC_S_FLC_INTR_DONE_PENDING \ + (MXC_V_FLC_INTR_DONE_PENDING << MXC_F_FLC_INTR_DONE_POS) /**< INTR_DONE_PENDING Setting */ + +#define MXC_F_FLC_INTR_AF_POS 1 /**< INTR_AF Position */ +#define MXC_F_FLC_INTR_AF ((uint32_t)(0x1UL << MXC_F_FLC_INTR_AF_POS)) /**< INTR_AF Mask */ +#define MXC_V_FLC_INTR_AF_NOERROR ((uint32_t)0x0UL) /**< INTR_AF_NOERROR Value */ +#define MXC_S_FLC_INTR_AF_NOERROR (MXC_V_FLC_INTR_AF_NOERROR << MXC_F_FLC_INTR_AF_POS) /**< INTR_AF_NOERROR Setting */ +#define MXC_V_FLC_INTR_AF_ERROR ((uint32_t)0x1UL) /**< INTR_AF_ERROR Value */ +#define MXC_S_FLC_INTR_AF_ERROR (MXC_V_FLC_INTR_AF_ERROR << MXC_F_FLC_INTR_AF_POS) /**< INTR_AF_ERROR Setting */ + +#define MXC_F_FLC_INTR_DONEIE_POS 8 /**< INTR_DONEIE Position */ +#define MXC_F_FLC_INTR_DONEIE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_DONEIE_POS)) /**< INTR_DONEIE Mask */ +#define MXC_V_FLC_INTR_DONEIE_DISABLE ((uint32_t)0x0UL) /**< INTR_DONEIE_DISABLE Value */ +#define MXC_S_FLC_INTR_DONEIE_DISABLE \ + (MXC_V_FLC_INTR_DONEIE_DISABLE << MXC_F_FLC_INTR_DONEIE_POS) /**< INTR_DONEIE_DISABLE Setting */ +#define MXC_V_FLC_INTR_DONEIE_ENABLE ((uint32_t)0x1UL) /**< INTR_DONEIE_ENABLE Value */ +#define MXC_S_FLC_INTR_DONEIE_ENABLE \ + (MXC_V_FLC_INTR_DONEIE_ENABLE << MXC_F_FLC_INTR_DONEIE_POS) /**< INTR_DONEIE_ENABLE Setting */ + +#define MXC_F_FLC_INTR_AFIE_POS 9 /**< INTR_AFIE Position */ +#define MXC_F_FLC_INTR_AFIE ((uint32_t)(0x1UL << MXC_F_FLC_INTR_AFIE_POS)) /**< INTR_AFIE Mask */ + +/**@} end of group INTR_Register */ + +/** + * @ingroup flc_registers + * @defgroup DATA_Register + * @brief Flash Write Data. + * @{ + */ +#define MXC_F_FLC_DATA_DATA_POS 0 /**< DATA_DATA Position */ +#define MXC_F_FLC_DATA_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_DATA_DATA_POS)) /**< DATA_DATA Mask */ + +/**@} end of group DATA_Register */ + +/** + * @ingroup flc_registers + * @defgroup ACNTL_Register + * @brief Access Control Register. Writing the ACNTL register with the following values in + * the order shown, allows read and write access to the system and user Information + * block: pflc-acntl = 0x3a7f5ca3; pflc-acntl = 0xa1e34f20; pflc-acntl = + * 0x9608b2c1. When unlocked, a write of any word will disable access to system and + * user information block. Readback of this register is always zero. + * @{ + */ +#define MXC_F_FLC_ACNTL_ACNTL_POS 0 /**< ACNTL_ACNTL Position */ +#define MXC_F_FLC_ACNTL_ACNTL ((uint32_t)(0xFFFFFFFFUL << MXC_F_FLC_ACNTL_ACNTL_POS)) /**< ACNTL_ACNTL Mask */ + +/**@} end of group ACNTL_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _FLC_REGS_H_ */ diff --git a/contrib/loaders/flash/max32xxx/gcr_regs.h b/contrib/loaders/flash/max32xxx/gcr_regs.h new file mode 100644 index 0000000000..0c5ccdbf3e --- /dev/null +++ b/contrib/loaders/flash/max32xxx/gcr_regs.h @@ -0,0 +1,777 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _GCR_REGS_H_ +#define _GCR_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +#if defined(__CC_ARM) +#pragma anon_unions +#endif +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup gcr + * @defgroup gcr_registers GCR_Registers + * @brief Registers, Bit Masks and Bit Positions for the GCR Peripheral Module. + * @details Global Control Registers. + */ + +/** + * @ingroup gcr_registers + * Structure type to access the GCR Registers. + */ +struct mxc_gcr_regs { + __IO uint32_t scon; /**< \b 0x00: GCR SCON Register */ + __IO uint32_t rstr0; /**< \b 0x04: GCR RSTR0 Register */ + __IO uint32_t clkcn; /**< \b 0x08: GCR CLKCN Register */ + __IO uint32_t pm; /**< \b 0x0C: GCR PM Register */ + __R uint32_t rsv_0x10_0x17[2]; + __IO uint32_t pckdiv; /**< \b 0x18: GCR PCKDIV Register */ + __R uint32_t rsv_0x1c_0x23[2]; + __IO uint32_t perckcn0; /**< \b 0x24: GCR PERCKCN0 Register */ + __IO uint32_t memckcn; /**< \b 0x28: GCR MEMCKCN Register */ + __IO uint32_t memzcn; /**< \b 0x2C: GCR MEMZCN Register */ + __R uint32_t rsv_0x30_0x3f[4]; + __IO uint32_t sysst; /**< \b 0x40: GCR SYSST Register */ + __IO uint32_t rstr1; /**< \b 0x44: GCR RSTR1 Register */ + __IO uint32_t perckcn1; /**< \b 0x48: GCR PERCKCN1 Register */ + __IO uint32_t evten; /**< \b 0x4C: GCR EVTEN Register */ + __I uint32_t revision; /**< \b 0x50: GCR REVISION Register */ + __IO uint32_t syssie; /**< \b 0x54: GCR SYSSIE Register */ + __R uint32_t rsv_0x58_0x63[3]; + __IO uint32_t eccerr; /**< \b 0x64: GCR ECCERR Register */ + __IO uint32_t eccnded; /**< \b 0x68: GCR ECCNDED Register */ + __IO uint32_t eccirqen; /**< \b 0x6C: GCR ECCIRQEN Register */ + __IO uint32_t eccerrad; /**< \b 0x70: GCR ECCERRAD Register */ +}; + +/* Register offsets for module GCR */ +/** + * @ingroup gcr_registers + * @defgroup GCR_Register_Offsets Register Offsets + * @brief GCR Peripheral Register Offsets from the GCR Base Peripheral Address. + * @{ + */ +#define MXC_R_GCR_SCON ((uint32_t)0x00000000UL) /**< Offset from GCR Base Address: 0x0000 */ +#define MXC_R_GCR_RSTR0 ((uint32_t)0x00000004UL) /**< Offset from GCR Base Address: 0x0004 */ +#define MXC_R_GCR_CLKCN ((uint32_t)0x00000008UL) /**< Offset from GCR Base Address: 0x0008 */ +#define MXC_R_GCR_PM ((uint32_t)0x0000000CUL) /**< Offset from GCR Base Address: 0x000C */ +#define MXC_R_GCR_PCKDIV ((uint32_t)0x00000018UL) /**< Offset from GCR Base Address: 0x0018 */ +#define MXC_R_GCR_PERCKCN0 ((uint32_t)0x00000024UL) /**< Offset from GCR Base Address: 0x0024 */ +#define MXC_R_GCR_MEMCKCN ((uint32_t)0x00000028UL) /**< Offset from GCR Base Address: 0x0028 */ +#define MXC_R_GCR_MEMZCN ((uint32_t)0x0000002CUL) /**< Offset from GCR Base Address: 0x002C */ +#define MXC_R_GCR_SYSST ((uint32_t)0x00000040UL) /**< Offset from GCR Base Address: 0x0040 */ +#define MXC_R_GCR_RSTR1 ((uint32_t)0x00000044UL) /**< Offset from GCR Base Address: 0x0044 */ +#define MXC_R_GCR_PERCKCN1 ((uint32_t)0x00000048UL) /**< Offset from GCR Base Address: 0x0048 */ +#define MXC_R_GCR_EVTEN ((uint32_t)0x0000004CUL) /**< Offset from GCR Base Address: 0x004C */ +#define MXC_R_GCR_REVISION ((uint32_t)0x00000050UL) /**< Offset from GCR Base Address: 0x0050 */ +#define MXC_R_GCR_SYSSIE ((uint32_t)0x00000054UL) /**< Offset from GCR Base Address: 0x0054 */ +#define MXC_R_GCR_ECCERR ((uint32_t)0x00000064UL) /**< Offset from GCR Base Address: 0x0064 */ +#define MXC_R_GCR_ECCNDED ((uint32_t)0x00000068UL) /**< Offset from GCR Base Address: 0x0068 */ +#define MXC_R_GCR_ECCIRQEN ((uint32_t)0x0000006CUL) /**< Offset from GCR Base Address: 0x006C */ +#define MXC_R_GCR_ECCERRAD ((uint32_t)0x00000070UL) /**< Offset from GCR Base Address: 0x0070 */ + /**@} end of group gcr_registers */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SCON GCR_SCON + * @brief System Control. + * @{ + */ +#define MXC_F_GCR_SCON_BSTAPEN_POS 0 /**< SCON_BSTAPEN Position */ +#define MXC_F_GCR_SCON_BSTAPEN ((uint32_t)(0x1UL << MXC_F_GCR_SCON_BSTAPEN_POS)) /**< SCON_BSTAPEN Mask */ +#define MXC_V_GCR_SCON_BSTAPEN_DIS ((uint32_t)0x0UL) /**< SCON_BSTAPEN_DIS Value */ +#define MXC_S_GCR_SCON_BSTAPEN_DIS \ + (MXC_V_GCR_SCON_BSTAPEN_DIS << MXC_F_GCR_SCON_BSTAPEN_POS) /**< SCON_BSTAPEN_DIS Setting */ +#define MXC_V_GCR_SCON_BSTAPEN_EN ((uint32_t)0x1UL) /**< SCON_BSTAPEN_EN Value */ +#define MXC_S_GCR_SCON_BSTAPEN_EN \ + (MXC_V_GCR_SCON_BSTAPEN_EN << MXC_F_GCR_SCON_BSTAPEN_POS) /**< SCON_BSTAPEN_EN Setting */ + +#define MXC_F_GCR_SCON_SBUSARB_POS 1 /**< SCON_SBUSARB Position */ +#define MXC_F_GCR_SCON_SBUSARB ((uint32_t)(0x3UL << MXC_F_GCR_SCON_SBUSARB_POS)) /**< SCON_SBUSARB Mask */ +#define MXC_V_GCR_SCON_SBUSARB_FIX ((uint32_t)0x0UL) /**< SCON_SBUSARB_FIX Value */ +#define MXC_S_GCR_SCON_SBUSARB_FIX \ + (MXC_V_GCR_SCON_SBUSARB_FIX << MXC_F_GCR_SCON_SBUSARB_POS) /**< SCON_SBUSARB_FIX Setting */ +#define MXC_V_GCR_SCON_SBUSARB_ROUND ((uint32_t)0x1UL) /**< SCON_SBUSARB_ROUND Value */ +#define MXC_S_GCR_SCON_SBUSARB_ROUND \ + (MXC_V_GCR_SCON_SBUSARB_ROUND << MXC_F_GCR_SCON_SBUSARB_POS) /**< SCON_SBUSARB_ROUND Setting */ + +#define MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS 4 /**< SCON_FLASH_PAGE_FLIP Position */ +#define MXC_F_GCR_SCON_FLASH_PAGE_FLIP \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS)) /**< SCON_FLASH_PAGE_FLIP Mask */ +#define MXC_V_GCR_SCON_FLASH_PAGE_FLIP_NORMAL ((uint32_t)0x0UL) /**< SCON_FLASH_PAGE_FLIP_NORMAL Value */ +#define MXC_S_GCR_SCON_FLASH_PAGE_FLIP_NORMAL \ + (MXC_V_GCR_SCON_FLASH_PAGE_FLIP_NORMAL \ + << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS) /**< SCON_FLASH_PAGE_FLIP_NORMAL Setting */ +#define MXC_V_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED ((uint32_t)0x1UL) /**< SCON_FLASH_PAGE_FLIP_SWAPPED Value */ +#define MXC_S_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED \ + (MXC_V_GCR_SCON_FLASH_PAGE_FLIP_SWAPPED \ + << MXC_F_GCR_SCON_FLASH_PAGE_FLIP_POS) /**< SCON_FLASH_PAGE_FLIP_SWAPPED Setting */ + +#define MXC_F_GCR_SCON_CCACHE_FLUSH_POS 6 /**< SCON_CCACHE_FLUSH Position */ +#define MXC_F_GCR_SCON_CCACHE_FLUSH \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CCACHE_FLUSH_POS)) /**< SCON_CCACHE_FLUSH Mask */ +#define MXC_V_GCR_SCON_CCACHE_FLUSH_NORMAL ((uint32_t)0x0UL) /**< SCON_CCACHE_FLUSH_NORMAL Value */ +#define MXC_S_GCR_SCON_CCACHE_FLUSH_NORMAL \ + (MXC_V_GCR_SCON_CCACHE_FLUSH_NORMAL << MXC_F_GCR_SCON_CCACHE_FLUSH_POS) /**< SCON_CCACHE_FLUSH_NORMAL Setting */ +#define MXC_V_GCR_SCON_CCACHE_FLUSH_FLUSH ((uint32_t)0x1UL) /**< SCON_CCACHE_FLUSH_FLUSH Value */ +#define MXC_S_GCR_SCON_CCACHE_FLUSH_FLUSH \ + (MXC_V_GCR_SCON_CCACHE_FLUSH_FLUSH << MXC_F_GCR_SCON_CCACHE_FLUSH_POS) /**< SCON_CCACHE_FLUSH_FLUSH Setting */ + +#define MXC_F_GCR_SCON_CCHK_POS 13 /**< SCON_CCHK Position */ +#define MXC_F_GCR_SCON_CCHK ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CCHK_POS)) /**< SCON_CCHK Mask */ +#define MXC_V_GCR_SCON_CCHK_COMPLETE ((uint32_t)0x0UL) /**< SCON_CCHK_COMPLETE Value */ +#define MXC_S_GCR_SCON_CCHK_COMPLETE \ + (MXC_V_GCR_SCON_CCHK_COMPLETE << MXC_F_GCR_SCON_CCHK_POS) /**< SCON_CCHK_COMPLETE Setting */ +#define MXC_V_GCR_SCON_CCHK_START ((uint32_t)0x1UL) /**< SCON_CCHK_START Value */ +#define MXC_S_GCR_SCON_CCHK_START (MXC_V_GCR_SCON_CCHK_START << MXC_F_GCR_SCON_CCHK_POS) /**< SCON_CCHK_START Setting \ + */ + +#define MXC_F_GCR_SCON_CHKRES_POS 15 /**< SCON_CHKRES Position */ +#define MXC_F_GCR_SCON_CHKRES ((uint32_t)(0x1UL << MXC_F_GCR_SCON_CHKRES_POS)) /**< SCON_CHKRES Mask */ +#define MXC_V_GCR_SCON_CHKRES_PASS ((uint32_t)0x0UL) /**< SCON_CHKRES_PASS Value */ +#define MXC_S_GCR_SCON_CHKRES_PASS \ + (MXC_V_GCR_SCON_CHKRES_PASS << MXC_F_GCR_SCON_CHKRES_POS) /**< SCON_CHKRES_PASS Setting */ +#define MXC_V_GCR_SCON_CHKRES_FAIL ((uint32_t)0x1UL) /**< SCON_CHKRES_FAIL Value */ +#define MXC_S_GCR_SCON_CHKRES_FAIL \ + (MXC_V_GCR_SCON_CHKRES_FAIL << MXC_F_GCR_SCON_CHKRES_POS) /**< SCON_CHKRES_FAIL Setting */ + +#define MXC_F_GCR_SCON_OVR_POS 16 /**< SCON_OVR Position */ +#define MXC_F_GCR_SCON_OVR ((uint32_t)(0x3UL << MXC_F_GCR_SCON_OVR_POS)) /**< SCON_OVR Mask */ +#define MXC_V_GCR_SCON_OVR_0_9V ((uint32_t)0x0UL) /**< SCON_OVR_0_9V Value */ +#define MXC_S_GCR_SCON_OVR_0_9V (MXC_V_GCR_SCON_OVR_0_9V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_0_9V Setting */ +#define MXC_V_GCR_SCON_OVR_1_0V ((uint32_t)0x1UL) /**< SCON_OVR_1_0V Value */ +#define MXC_S_GCR_SCON_OVR_1_0V (MXC_V_GCR_SCON_OVR_1_0V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_1_0V Setting */ +#define MXC_V_GCR_SCON_OVR_1_1V ((uint32_t)0x2UL) /**< SCON_OVR_1_1V Value */ +#define MXC_S_GCR_SCON_OVR_1_1V (MXC_V_GCR_SCON_OVR_1_1V << MXC_F_GCR_SCON_OVR_POS) /**< SCON_OVR_1_1V Setting */ + +#define MXC_F_GCR_SCON_MEMPROT_EN_POS 20 /**< SCON_MEMPROT_EN Position */ +#define MXC_F_GCR_SCON_MEMPROT_EN ((uint32_t)(0x1UL << MXC_F_GCR_SCON_MEMPROT_EN_POS)) /**< SCON_MEMPROT_EN Mask */ +#define MXC_V_GCR_SCON_MEMPROT_EN_DIS ((uint32_t)0x0UL) /**< SCON_MEMPROT_EN_DIS Value */ +#define MXC_S_GCR_SCON_MEMPROT_EN_DIS \ + (MXC_V_GCR_SCON_MEMPROT_EN_DIS << MXC_F_GCR_SCON_MEMPROT_EN_POS) /**< SCON_MEMPROT_EN_DIS Setting */ +#define MXC_V_GCR_SCON_MEMPROT_EN_EN ((uint32_t)0x1UL) /**< SCON_MEMPROT_EN_EN Value */ +#define MXC_S_GCR_SCON_MEMPROT_EN_EN \ + (MXC_V_GCR_SCON_MEMPROT_EN_EN << MXC_F_GCR_SCON_MEMPROT_EN_POS) /**< SCON_MEMPROT_EN_EN Setting */ + +#define MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS 21 /**< SCON_MEMPROT_KEYSZ Position */ +#define MXC_F_GCR_SCON_MEMPROT_KEYSZ \ + ((uint32_t)(0x1UL << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS)) /**< SCON_MEMPROT_KEYSZ Mask */ +#define MXC_V_GCR_SCON_MEMPROT_KEYSZ_128 ((uint32_t)0x0UL) /**< SCON_MEMPROT_KEYSZ_128 Value */ +#define MXC_S_GCR_SCON_MEMPROT_KEYSZ_128 \ + (MXC_V_GCR_SCON_MEMPROT_KEYSZ_128 << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS) /**< SCON_MEMPROT_KEYSZ_128 Setting */ +#define MXC_V_GCR_SCON_MEMPROT_KEYSZ_256 ((uint32_t)0x1UL) /**< SCON_MEMPROT_KEYSZ_256 Value */ +#define MXC_S_GCR_SCON_MEMPROT_KEYSZ_256 \ + (MXC_V_GCR_SCON_MEMPROT_KEYSZ_256 << MXC_F_GCR_SCON_MEMPROT_KEYSZ_POS) /**< SCON_MEMPROT_KEYSZ_256 Setting */ + +/**@} end of group GCR_SCON_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_RSTR0 GCR_RSTR0 + * @brief Reset. + * @{ + */ +#define MXC_F_GCR_RSTR0_DMA_POS 0 /**< RSTR0_DMA Position */ +#define MXC_F_GCR_RSTR0_DMA ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_DMA_POS)) /**< RSTR0_DMA Mask */ +#define MXC_V_GCR_RSTR0_DMA_RESET_DONE ((uint32_t)0x0UL) /**< RSTR0_DMA_RESET_DONE Value */ +#define MXC_S_GCR_RSTR0_DMA_RESET_DONE \ + (MXC_V_GCR_RSTR0_DMA_RESET_DONE << MXC_F_GCR_RSTR0_DMA_POS) /**< RSTR0_DMA_RESET_DONE Setting */ +#define MXC_V_GCR_RSTR0_DMA_BUSY ((uint32_t)0x1UL) /**< RSTR0_DMA_BUSY Value */ +#define MXC_S_GCR_RSTR0_DMA_BUSY (MXC_V_GCR_RSTR0_DMA_BUSY << MXC_F_GCR_RSTR0_DMA_POS) /**< RSTR0_DMA_BUSY Setting */ + +#define MXC_F_GCR_RSTR0_WDT_POS 1 /**< RSTR0_WDT Position */ +#define MXC_F_GCR_RSTR0_WDT ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_WDT_POS)) /**< RSTR0_WDT Mask */ + +#define MXC_F_GCR_RSTR0_GPIO0_POS 2 /**< RSTR0_GPIO0 Position */ +#define MXC_F_GCR_RSTR0_GPIO0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_GPIO0_POS)) /**< RSTR0_GPIO0 Mask */ + +#define MXC_F_GCR_RSTR0_GPIO1_POS 3 /**< RSTR0_GPIO1 Position */ +#define MXC_F_GCR_RSTR0_GPIO1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_GPIO1_POS)) /**< RSTR0_GPIO1 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER0_POS 5 /**< RSTR0_TIMER0 Position */ +#define MXC_F_GCR_RSTR0_TIMER0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER0_POS)) /**< RSTR0_TIMER0 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER1_POS 6 /**< RSTR0_TIMER1 Position */ +#define MXC_F_GCR_RSTR0_TIMER1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER1_POS)) /**< RSTR0_TIMER1 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER2_POS 7 /**< RSTR0_TIMER2 Position */ +#define MXC_F_GCR_RSTR0_TIMER2 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER2_POS)) /**< RSTR0_TIMER2 Mask */ + +#define MXC_F_GCR_RSTR0_TIMER3_POS 8 /**< RSTR0_TIMER3 Position */ +#define MXC_F_GCR_RSTR0_TIMER3 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TIMER3_POS)) /**< RSTR0_TIMER3 Mask */ + +#define MXC_F_GCR_RSTR0_UART0_POS 11 /**< RSTR0_UART0 Position */ +#define MXC_F_GCR_RSTR0_UART0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_UART0_POS)) /**< RSTR0_UART0 Mask */ + +#define MXC_F_GCR_RSTR0_SPI0_POS 13 /**< RSTR0_SPI0 Position */ +#define MXC_F_GCR_RSTR0_SPI0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SPI0_POS)) /**< RSTR0_SPI0 Mask */ + +#define MXC_F_GCR_RSTR0_SPI1_POS 14 /**< RSTR0_SPI1 Position */ +#define MXC_F_GCR_RSTR0_SPI1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SPI1_POS)) /**< RSTR0_SPI1 Mask */ + +#define MXC_F_GCR_RSTR0_I2C0_POS 16 /**< RSTR0_I2C0 Position */ +#define MXC_F_GCR_RSTR0_I2C0 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_I2C0_POS)) /**< RSTR0_I2C0 Mask */ + +#define MXC_F_GCR_RSTR0_CRYPTO_POS 18 /**< RSTR0_CRYPTO Position */ +#define MXC_F_GCR_RSTR0_CRYPTO ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_CRYPTO_POS)) /**< RSTR0_CRYPTO Mask */ + +#define MXC_F_GCR_RSTR0_SMPHR_POS 22 /**< RSTR0_SMPHR Position */ +#define MXC_F_GCR_RSTR0_SMPHR ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SMPHR_POS)) /**< RSTR0_SMPHR Mask */ + +#define MXC_F_GCR_RSTR0_TRNG_POS 24 /**< RSTR0_TRNG Position */ +#define MXC_F_GCR_RSTR0_TRNG ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_TRNG_POS)) /**< RSTR0_TRNG Mask */ + +#define MXC_F_GCR_RSTR0_SRST_POS 29 /**< RSTR0_SRST Position */ +#define MXC_F_GCR_RSTR0_SRST ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SRST_POS)) /**< RSTR0_SRST Mask */ + +#define MXC_F_GCR_RSTR0_PRST_POS 30 /**< RSTR0_PRST Position */ +#define MXC_F_GCR_RSTR0_PRST ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_PRST_POS)) /**< RSTR0_PRST Mask */ + +#define MXC_F_GCR_RSTR0_SYSTEM_POS 31 /**< RSTR0_SYSTEM Position */ +#define MXC_F_GCR_RSTR0_SYSTEM ((uint32_t)(0x1UL << MXC_F_GCR_RSTR0_SYSTEM_POS)) /**< RSTR0_SYSTEM Mask */ + +/**@} end of group GCR_RSTR0_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_CLKCN GCR_CLKCN + * @brief Clock Control. + * @{ + */ +#define MXC_F_GCR_CLKCN_PSC_POS 6 /**< CLKCN_PSC Position */ +#define MXC_F_GCR_CLKCN_PSC ((uint32_t)(0x7UL << MXC_F_GCR_CLKCN_PSC_POS)) /**< CLKCN_PSC Mask */ +#define MXC_V_GCR_CLKCN_PSC_DIV1 ((uint32_t)0x0UL) /**< CLKCN_PSC_DIV1 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV1 (MXC_V_GCR_CLKCN_PSC_DIV1 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV1 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV2 ((uint32_t)0x1UL) /**< CLKCN_PSC_DIV2 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV2 (MXC_V_GCR_CLKCN_PSC_DIV2 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV2 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV4 ((uint32_t)0x2UL) /**< CLKCN_PSC_DIV4 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV4 (MXC_V_GCR_CLKCN_PSC_DIV4 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV4 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV8 ((uint32_t)0x3UL) /**< CLKCN_PSC_DIV8 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV8 (MXC_V_GCR_CLKCN_PSC_DIV8 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV8 Setting */ +#define MXC_V_GCR_CLKCN_PSC_DIV16 ((uint32_t)0x4UL) /**< CLKCN_PSC_DIV16 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV16 (MXC_V_GCR_CLKCN_PSC_DIV16 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV16 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV32 ((uint32_t)0x5UL) /**< CLKCN_PSC_DIV32 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV32 (MXC_V_GCR_CLKCN_PSC_DIV32 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV32 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV64 ((uint32_t)0x6UL) /**< CLKCN_PSC_DIV64 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV64 (MXC_V_GCR_CLKCN_PSC_DIV64 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV64 Setting \ + */ +#define MXC_V_GCR_CLKCN_PSC_DIV128 ((uint32_t)0x7UL) /**< CLKCN_PSC_DIV128 Value */ +#define MXC_S_GCR_CLKCN_PSC_DIV128 \ + (MXC_V_GCR_CLKCN_PSC_DIV128 << MXC_F_GCR_CLKCN_PSC_POS) /**< CLKCN_PSC_DIV128 Setting */ + +#define MXC_F_GCR_CLKCN_CLKSEL_POS 9 /**< CLKCN_CLKSEL Position */ +#define MXC_F_GCR_CLKCN_CLKSEL ((uint32_t)(0x7UL << MXC_F_GCR_CLKCN_CLKSEL_POS)) /**< CLKCN_CLKSEL Mask */ +#define MXC_V_GCR_CLKCN_CLKSEL_HIRC ((uint32_t)0x0UL) /**< CLKCN_CLKSEL_HIRC Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_HIRC \ + (MXC_V_GCR_CLKCN_CLKSEL_HIRC << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_HIRC Setting */ +#define MXC_V_GCR_CLKCN_CLKSEL_LIRC8 ((uint32_t)0x3UL) /**< CLKCN_CLKSEL_LIRC8 Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_LIRC8 \ + (MXC_V_GCR_CLKCN_CLKSEL_LIRC8 << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_LIRC8 Setting */ +#define MXC_V_GCR_CLKCN_CLKSEL_HIRC8 ((uint32_t)0x5UL) /**< CLKCN_CLKSEL_HIRC8 Value */ +#define MXC_S_GCR_CLKCN_CLKSEL_HIRC8 \ + (MXC_V_GCR_CLKCN_CLKSEL_HIRC8 << MXC_F_GCR_CLKCN_CLKSEL_POS) /**< CLKCN_CLKSEL_HIRC8 Setting */ + +#define MXC_F_GCR_CLKCN_CKRDY_POS 13 /**< CLKCN_CKRDY Position */ +#define MXC_F_GCR_CLKCN_CKRDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_CKRDY_POS)) /**< CLKCN_CKRDY Mask */ +#define MXC_V_GCR_CLKCN_CKRDY_BUSY ((uint32_t)0x0UL) /**< CLKCN_CKRDY_BUSY Value */ +#define MXC_S_GCR_CLKCN_CKRDY_BUSY \ + (MXC_V_GCR_CLKCN_CKRDY_BUSY << MXC_F_GCR_CLKCN_CKRDY_POS) /**< CLKCN_CKRDY_BUSY Setting */ +#define MXC_V_GCR_CLKCN_CKRDY_READY ((uint32_t)0x1UL) /**< CLKCN_CKRDY_READY Value */ +#define MXC_S_GCR_CLKCN_CKRDY_READY \ + (MXC_V_GCR_CLKCN_CKRDY_READY << MXC_F_GCR_CLKCN_CKRDY_POS) /**< CLKCN_CKRDY_READY Setting */ + +#define MXC_F_GCR_CLKCN_HIRC_EN_POS 18 /**< CLKCN_HIRC_EN Position */ +#define MXC_F_GCR_CLKCN_HIRC_EN ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC_EN_POS)) /**< CLKCN_HIRC_EN Mask */ +#define MXC_V_GCR_CLKCN_HIRC_EN_DIS ((uint32_t)0x0UL) /**< CLKCN_HIRC_EN_DIS Value */ +#define MXC_S_GCR_CLKCN_HIRC_EN_DIS \ + (MXC_V_GCR_CLKCN_HIRC_EN_DIS << MXC_F_GCR_CLKCN_HIRC_EN_POS) /**< CLKCN_HIRC_EN_DIS Setting */ +#define MXC_V_GCR_CLKCN_HIRC_EN_EN ((uint32_t)0x1UL) /**< CLKCN_HIRC_EN_EN Value */ +#define MXC_S_GCR_CLKCN_HIRC_EN_EN \ + (MXC_V_GCR_CLKCN_HIRC_EN_EN << MXC_F_GCR_CLKCN_HIRC_EN_POS) /**< CLKCN_HIRC_EN_EN Setting */ + +#define MXC_F_GCR_CLKCN_HIRC8M_EN_POS 20 /**< CLKCN_HIRC8M_EN Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_EN ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_EN_POS)) /**< CLKCN_HIRC8M_EN Mask */ + +#define MXC_F_GCR_CLKCN_HIRC8M_VS_POS 21 /**< CLKCN_HIRC8M_VS Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_VS ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_VS_POS)) /**< CLKCN_HIRC8M_VS Mask */ +#define MXC_V_GCR_CLKCN_HIRC8M_VS_VCOR ((uint32_t)0x0UL) /**< CLKCN_HIRC8M_VS_VCOR Value */ +#define MXC_S_GCR_CLKCN_HIRC8M_VS_VCOR \ + (MXC_V_GCR_CLKCN_HIRC8M_VS_VCOR << MXC_F_GCR_CLKCN_HIRC8M_VS_POS) /**< CLKCN_HIRC8M_VS_VCOR Setting */ +#define MXC_V_GCR_CLKCN_HIRC8M_VS_1V ((uint32_t)0x1UL) /**< CLKCN_HIRC8M_VS_1V Value */ +#define MXC_S_GCR_CLKCN_HIRC8M_VS_1V \ + (MXC_V_GCR_CLKCN_HIRC8M_VS_1V << MXC_F_GCR_CLKCN_HIRC8M_VS_POS) /**< CLKCN_HIRC8M_VS_1V Setting */ + +#define MXC_F_GCR_CLKCN_HIRC_RDY_POS 26 /**< CLKCN_HIRC_RDY Position */ +#define MXC_F_GCR_CLKCN_HIRC_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC_RDY_POS)) /**< CLKCN_HIRC_RDY Mask */ +#define MXC_V_GCR_CLKCN_HIRC_RDY_NOT ((uint32_t)0x0UL) /**< CLKCN_HIRC_RDY_NOT Value */ +#define MXC_S_GCR_CLKCN_HIRC_RDY_NOT \ + (MXC_V_GCR_CLKCN_HIRC_RDY_NOT << MXC_F_GCR_CLKCN_HIRC_RDY_POS) /**< CLKCN_HIRC_RDY_NOT Setting */ +#define MXC_V_GCR_CLKCN_HIRC_RDY_READY ((uint32_t)0x1UL) /**< CLKCN_HIRC_RDY_READY Value */ +#define MXC_S_GCR_CLKCN_HIRC_RDY_READY \ + (MXC_V_GCR_CLKCN_HIRC_RDY_READY << MXC_F_GCR_CLKCN_HIRC_RDY_POS) /**< CLKCN_HIRC_RDY_READY Setting */ + +#define MXC_F_GCR_CLKCN_HIRC8M_RDY_POS 28 /**< CLKCN_HIRC8M_RDY Position */ +#define MXC_F_GCR_CLKCN_HIRC8M_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_HIRC8M_RDY_POS)) /**< CLKCN_HIRC8M_RDY Mask */ + +#define MXC_F_GCR_CLKCN_LIRC8K_RDY_POS 29 /**< CLKCN_LIRC8K_RDY Position */ +#define MXC_F_GCR_CLKCN_LIRC8K_RDY ((uint32_t)(0x1UL << MXC_F_GCR_CLKCN_LIRC8K_RDY_POS)) /**< CLKCN_LIRC8K_RDY Mask */ + +/**@} end of group GCR_CLKCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PM GCR_PM + * @brief Power Management. + * @{ + */ +#define MXC_F_GCR_PM_MODE_POS 0 /**< PM_MODE Position */ +#define MXC_F_GCR_PM_MODE ((uint32_t)(0x7UL << MXC_F_GCR_PM_MODE_POS)) /**< PM_MODE Mask */ +#define MXC_V_GCR_PM_MODE_ACTIVE ((uint32_t)0x0UL) /**< PM_MODE_ACTIVE Value */ +#define MXC_S_GCR_PM_MODE_ACTIVE (MXC_V_GCR_PM_MODE_ACTIVE << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_ACTIVE Setting */ +#define MXC_V_GCR_PM_MODE_DEEPSLEEP ((uint32_t)0x2UL) /**< PM_MODE_DEEPSLEEP Value */ +#define MXC_S_GCR_PM_MODE_DEEPSLEEP \ + (MXC_V_GCR_PM_MODE_DEEPSLEEP << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_DEEPSLEEP Setting */ +#define MXC_V_GCR_PM_MODE_SHUTDOWN ((uint32_t)0x3UL) /**< PM_MODE_SHUTDOWN Value */ +#define MXC_S_GCR_PM_MODE_SHUTDOWN \ + (MXC_V_GCR_PM_MODE_SHUTDOWN << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_SHUTDOWN Setting */ +#define MXC_V_GCR_PM_MODE_BACKUP ((uint32_t)0x4UL) /**< PM_MODE_BACKUP Value */ +#define MXC_S_GCR_PM_MODE_BACKUP (MXC_V_GCR_PM_MODE_BACKUP << MXC_F_GCR_PM_MODE_POS) /**< PM_MODE_BACKUP Setting */ + +#define MXC_F_GCR_PM_GPIOWKEN_POS 4 /**< PM_GPIOWKEN Position */ +#define MXC_F_GCR_PM_GPIOWKEN ((uint32_t)(0x1UL << MXC_F_GCR_PM_GPIOWKEN_POS)) /**< PM_GPIOWKEN Mask */ +#define MXC_V_GCR_PM_GPIOWKEN_DIS ((uint32_t)0x0UL) /**< PM_GPIOWKEN_DIS Value */ +#define MXC_S_GCR_PM_GPIOWKEN_DIS \ + (MXC_V_GCR_PM_GPIOWKEN_DIS << MXC_F_GCR_PM_GPIOWKEN_POS) /**< PM_GPIOWKEN_DIS Setting */ +#define MXC_V_GCR_PM_GPIOWKEN_EN ((uint32_t)0x1UL) /**< PM_GPIOWKEN_EN Value */ +#define MXC_S_GCR_PM_GPIOWKEN_EN (MXC_V_GCR_PM_GPIOWKEN_EN << MXC_F_GCR_PM_GPIOWKEN_POS) /**< PM_GPIOWKEN_EN Setting \ + */ + +#define MXC_F_GCR_PM_HIRCPD_POS 15 /**< PM_HIRCPD Position */ +#define MXC_F_GCR_PM_HIRCPD ((uint32_t)(0x1UL << MXC_F_GCR_PM_HIRCPD_POS)) /**< PM_HIRCPD Mask */ +#define MXC_V_GCR_PM_HIRCPD_ACTIVE ((uint32_t)0x0UL) /**< PM_HIRCPD_ACTIVE Value */ +#define MXC_S_GCR_PM_HIRCPD_ACTIVE \ + (MXC_V_GCR_PM_HIRCPD_ACTIVE << MXC_F_GCR_PM_HIRCPD_POS) /**< PM_HIRCPD_ACTIVE Setting */ +#define MXC_V_GCR_PM_HIRCPD_DEEPSLEEP ((uint32_t)0x1UL) /**< PM_HIRCPD_DEEPSLEEP Value */ +#define MXC_S_GCR_PM_HIRCPD_DEEPSLEEP \ + (MXC_V_GCR_PM_HIRCPD_DEEPSLEEP << MXC_F_GCR_PM_HIRCPD_POS) /**< PM_HIRCPD_DEEPSLEEP Setting */ + +#define MXC_F_GCR_PM_HIRC8MPD_POS 17 /**< PM_HIRC8MPD Position */ +#define MXC_F_GCR_PM_HIRC8MPD ((uint32_t)(0x1UL << MXC_F_GCR_PM_HIRC8MPD_POS)) /**< PM_HIRC8MPD Mask */ + +/**@} end of group GCR_PM_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PCKDIV GCR_PCKDIV + * @brief Peripheral Clock Divider. + * @{ + */ +#define MXC_F_GCR_PCKDIV_PCF_POS 0 /**< PCKDIV_PCF Position */ +#define MXC_F_GCR_PCKDIV_PCF ((uint32_t)(0x7UL << MXC_F_GCR_PCKDIV_PCF_POS)) /**< PCKDIV_PCF Mask */ +#define MXC_V_GCR_PCKDIV_PCF_96MHZ ((uint32_t)0x2UL) /**< PCKDIV_PCF_96MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_96MHZ \ + (MXC_V_GCR_PCKDIV_PCF_96MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_96MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_48MHZ ((uint32_t)0x3UL) /**< PCKDIV_PCF_48MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_48MHZ \ + (MXC_V_GCR_PCKDIV_PCF_48MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_48MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_24MHZ ((uint32_t)0x4UL) /**< PCKDIV_PCF_24MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_24MHZ \ + (MXC_V_GCR_PCKDIV_PCF_24MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_24MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_12MHZ ((uint32_t)0x5UL) /**< PCKDIV_PCF_12MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_12MHZ \ + (MXC_V_GCR_PCKDIV_PCF_12MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_12MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_6MHZ ((uint32_t)0x6UL) /**< PCKDIV_PCF_6MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_6MHZ \ + (MXC_V_GCR_PCKDIV_PCF_6MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_6MHZ Setting */ +#define MXC_V_GCR_PCKDIV_PCF_3MHZ ((uint32_t)0x7UL) /**< PCKDIV_PCF_3MHZ Value */ +#define MXC_S_GCR_PCKDIV_PCF_3MHZ \ + (MXC_V_GCR_PCKDIV_PCF_3MHZ << MXC_F_GCR_PCKDIV_PCF_POS) /**< PCKDIV_PCF_3MHZ Setting */ + +#define MXC_F_GCR_PCKDIV_PCFWEN_POS 3 /**< PCKDIV_PCFWEN Position */ +#define MXC_F_GCR_PCKDIV_PCFWEN ((uint32_t)(0x1UL << MXC_F_GCR_PCKDIV_PCFWEN_POS)) /**< PCKDIV_PCFWEN Mask */ +#define MXC_V_GCR_PCKDIV_PCFWEN_DISABLED ((uint32_t)0x0UL) /**< PCKDIV_PCFWEN_DISABLED Value */ +#define MXC_S_GCR_PCKDIV_PCFWEN_DISABLED \ + (MXC_V_GCR_PCKDIV_PCFWEN_DISABLED << MXC_F_GCR_PCKDIV_PCFWEN_POS) /**< PCKDIV_PCFWEN_DISABLED Setting */ +#define MXC_V_GCR_PCKDIV_PCFWEN_ENABLED ((uint32_t)0x1UL) /**< PCKDIV_PCFWEN_ENABLED Value */ +#define MXC_S_GCR_PCKDIV_PCFWEN_ENABLED \ + (MXC_V_GCR_PCKDIV_PCFWEN_ENABLED << MXC_F_GCR_PCKDIV_PCFWEN_POS) /**< PCKDIV_PCFWEN_ENABLED Setting */ + +#define MXC_F_GCR_PCKDIV_AONCD_POS 14 /**< PCKDIV_AONCD Position */ +#define MXC_F_GCR_PCKDIV_AONCD ((uint32_t)(0x3UL << MXC_F_GCR_PCKDIV_AONCD_POS)) /**< PCKDIV_AONCD Mask */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_4 ((uint32_t)0x0UL) /**< PCKDIV_AONCD_DIV_4 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_4 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_4 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_4 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_8 ((uint32_t)0x1UL) /**< PCKDIV_AONCD_DIV_8 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_8 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_8 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_8 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_16 ((uint32_t)0x2UL) /**< PCKDIV_AONCD_DIV_16 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_16 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_16 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_16 Setting */ +#define MXC_V_GCR_PCKDIV_AONCD_DIV_32 ((uint32_t)0x3UL) /**< PCKDIV_AONCD_DIV_32 Value */ +#define MXC_S_GCR_PCKDIV_AONCD_DIV_32 \ + (MXC_V_GCR_PCKDIV_AONCD_DIV_32 << MXC_F_GCR_PCKDIV_AONCD_POS) /**< PCKDIV_AONCD_DIV_32 Setting */ + +/**@} end of group GCR_PCKDIV_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PERCKCN0 GCR_PERCKCN0 + * @brief Peripheral Clock Disable. + * @{ + */ +#define MXC_F_GCR_PERCKCN0_GPIO0D_POS 0 /**< PERCKCN0_GPIO0D Position */ +#define MXC_F_GCR_PERCKCN0_GPIO0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_GPIO0D_POS)) /**< PERCKCN0_GPIO0D Mask */ +#define MXC_V_GCR_PERCKCN0_GPIO0D_EN ((uint32_t)0x0UL) /**< PERCKCN0_GPIO0D_EN Value */ +#define MXC_S_GCR_PERCKCN0_GPIO0D_EN \ + (MXC_V_GCR_PERCKCN0_GPIO0D_EN << MXC_F_GCR_PERCKCN0_GPIO0D_POS) /**< PERCKCN0_GPIO0D_EN Setting */ +#define MXC_V_GCR_PERCKCN0_GPIO0D_DIS ((uint32_t)0x1UL) /**< PERCKCN0_GPIO0D_DIS Value */ +#define MXC_S_GCR_PERCKCN0_GPIO0D_DIS \ + (MXC_V_GCR_PERCKCN0_GPIO0D_DIS << MXC_F_GCR_PERCKCN0_GPIO0D_POS) /**< PERCKCN0_GPIO0D_DIS Setting */ + +#define MXC_F_GCR_PERCKCN0_GPIO1D_POS 1 /**< PERCKCN0_GPIO1D Position */ +#define MXC_F_GCR_PERCKCN0_GPIO1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_GPIO1D_POS)) /**< PERCKCN0_GPIO1D Mask */ + +#define MXC_F_GCR_PERCKCN0_DMAD_POS 5 /**< PERCKCN0_DMAD Position */ +#define MXC_F_GCR_PERCKCN0_DMAD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_DMAD_POS)) /**< PERCKCN0_DMAD Mask */ + +#define MXC_F_GCR_PERCKCN0_SPI0D_POS 6 /**< PERCKCN0_SPI0D Position */ +#define MXC_F_GCR_PERCKCN0_SPI0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_SPI0D_POS)) /**< PERCKCN0_SPI0D Mask */ + +#define MXC_F_GCR_PERCKCN0_SPI1D_POS 7 /**< PERCKCN0_SPI1D Position */ +#define MXC_F_GCR_PERCKCN0_SPI1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_SPI1D_POS)) /**< PERCKCN0_SPI1D Mask */ + +#define MXC_F_GCR_PERCKCN0_UART0D_POS 9 /**< PERCKCN0_UART0D Position */ +#define MXC_F_GCR_PERCKCN0_UART0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_UART0D_POS)) /**< PERCKCN0_UART0D Mask */ + +#define MXC_F_GCR_PERCKCN0_I2C0D_POS 13 /**< PERCKCN0_I2C0D Position */ +#define MXC_F_GCR_PERCKCN0_I2C0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_I2C0D_POS)) /**< PERCKCN0_I2C0D Mask */ + +#define MXC_F_GCR_PERCKCN0_CRYPTOD_POS 14 /**< PERCKCN0_CRYPTOD Position */ +#define MXC_F_GCR_PERCKCN0_CRYPTOD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_CRYPTOD_POS)) /**< PERCKCN0_CRYPTOD Mask */ + +#define MXC_F_GCR_PERCKCN0_T0D_POS 15 /**< PERCKCN0_T0D Position */ +#define MXC_F_GCR_PERCKCN0_T0D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T0D_POS)) /**< PERCKCN0_T0D Mask */ + +#define MXC_F_GCR_PERCKCN0_T1D_POS 16 /**< PERCKCN0_T1D Position */ +#define MXC_F_GCR_PERCKCN0_T1D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T1D_POS)) /**< PERCKCN0_T1D Mask */ + +#define MXC_F_GCR_PERCKCN0_T2D_POS 17 /**< PERCKCN0_T2D Position */ +#define MXC_F_GCR_PERCKCN0_T2D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T2D_POS)) /**< PERCKCN0_T2D Mask */ + +#define MXC_F_GCR_PERCKCN0_T3D_POS 18 /**< PERCKCN0_T3D Position */ +#define MXC_F_GCR_PERCKCN0_T3D ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN0_T3D_POS)) /**< PERCKCN0_T3D Mask */ + +/**@} end of group GCR_PERCKCN0_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_MEMCKCN GCR_MEMCKCN + * @brief Memory Clock Control Register. + * @{ + */ +#define MXC_F_GCR_MEMCKCN_FWS_POS 0 /**< MEMCKCN_FWS Position */ +#define MXC_F_GCR_MEMCKCN_FWS ((uint32_t)(0x7UL << MXC_F_GCR_MEMCKCN_FWS_POS)) /**< MEMCKCN_FWS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS 16 /**< MEMCKCN_SYSRAM0LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM0LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS)) /**< MEMCKCN_SYSRAM0LS Mask */ +#define MXC_V_GCR_MEMCKCN_SYSRAM0LS_ACTIVE ((uint32_t)0x0UL) /**< MEMCKCN_SYSRAM0LS_ACTIVE Value */ +#define MXC_S_GCR_MEMCKCN_SYSRAM0LS_ACTIVE \ + (MXC_V_GCR_MEMCKCN_SYSRAM0LS_ACTIVE << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS) /**< MEMCKCN_SYSRAM0LS_ACTIVE Setting */ +#define MXC_V_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP ((uint32_t)0x1UL) /**< MEMCKCN_SYSRAM0LS_LIGHT_SLEEP Value */ +#define MXC_S_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP \ + (MXC_V_GCR_MEMCKCN_SYSRAM0LS_LIGHT_SLEEP \ + << MXC_F_GCR_MEMCKCN_SYSRAM0LS_POS) /**< MEMCKCN_SYSRAM0LS_LIGHT_SLEEP Setting */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM1LS_POS 17 /**< MEMCKCN_SYSRAM1LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM1LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM1LS_POS)) /**< MEMCKCN_SYSRAM1LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM2LS_POS 18 /**< MEMCKCN_SYSRAM2LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM2LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM2LS_POS)) /**< MEMCKCN_SYSRAM2LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM3LS_POS 19 /**< MEMCKCN_SYSRAM3LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM3LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM3LS_POS)) /**< MEMCKCN_SYSRAM3LS Mask */ + +#define MXC_F_GCR_MEMCKCN_SYSRAM4LS_POS 20 /**< MEMCKCN_SYSRAM4LS Position */ +#define MXC_F_GCR_MEMCKCN_SYSRAM4LS \ + ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_SYSRAM4LS_POS)) /**< MEMCKCN_SYSRAM4LS Mask */ + +#define MXC_F_GCR_MEMCKCN_ICACHELS_POS 24 /**< MEMCKCN_ICACHELS Position */ +#define MXC_F_GCR_MEMCKCN_ICACHELS ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_ICACHELS_POS)) /**< MEMCKCN_ICACHELS Mask */ + +#define MXC_F_GCR_MEMCKCN_ROMLS_POS 29 /**< MEMCKCN_ROMLS Position */ +#define MXC_F_GCR_MEMCKCN_ROMLS ((uint32_t)(0x1UL << MXC_F_GCR_MEMCKCN_ROMLS_POS)) /**< MEMCKCN_ROMLS Mask */ + +/**@} end of group GCR_MEMCKCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_MEMZCN GCR_MEMZCN + * @brief Memory Zeroize Control. + * @{ + */ +#define MXC_F_GCR_MEMZCN_SRAM0Z_POS 0 /**< MEMZCN_SRAM0Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM0Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM0Z_POS)) /**< MEMZCN_SRAM0Z Mask */ +#define MXC_V_GCR_MEMZCN_SRAM0Z_NOP ((uint32_t)0x0UL) /**< MEMZCN_SRAM0Z_NOP Value */ +#define MXC_S_GCR_MEMZCN_SRAM0Z_NOP \ + (MXC_V_GCR_MEMZCN_SRAM0Z_NOP << MXC_F_GCR_MEMZCN_SRAM0Z_POS) /**< MEMZCN_SRAM0Z_NOP Setting */ +#define MXC_V_GCR_MEMZCN_SRAM0Z_START ((uint32_t)0x1UL) /**< MEMZCN_SRAM0Z_START Value */ +#define MXC_S_GCR_MEMZCN_SRAM0Z_START \ + (MXC_V_GCR_MEMZCN_SRAM0Z_START << MXC_F_GCR_MEMZCN_SRAM0Z_POS) /**< MEMZCN_SRAM0Z_START Setting */ + +#define MXC_F_GCR_MEMZCN_SRAM1Z_POS 1 /**< MEMZCN_SRAM1Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM1Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM1Z_POS)) /**< MEMZCN_SRAM1Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM2Z_POS 2 /**< MEMZCN_SRAM2Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM2Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM2Z_POS)) /**< MEMZCN_SRAM2Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM3Z_POS 3 /**< MEMZCN_SRAM3Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM3Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM3Z_POS)) /**< MEMZCN_SRAM3Z Mask */ + +#define MXC_F_GCR_MEMZCN_SRAM4Z_POS 4 /**< MEMZCN_SRAM4Z Position */ +#define MXC_F_GCR_MEMZCN_SRAM4Z ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_SRAM4Z_POS)) /**< MEMZCN_SRAM4Z Mask */ + +#define MXC_F_GCR_MEMZCN_ICACHEZ_POS 8 /**< MEMZCN_ICACHEZ Position */ +#define MXC_F_GCR_MEMZCN_ICACHEZ ((uint32_t)(0x1UL << MXC_F_GCR_MEMZCN_ICACHEZ_POS)) /**< MEMZCN_ICACHEZ Mask */ + +/**@} end of group GCR_MEMZCN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SYSST GCR_SYSST + * @brief System Status Register. + * @{ + */ +#define MXC_F_GCR_SYSST_ICECLOCK_POS 0 /**< SYSST_ICECLOCK Position */ +#define MXC_F_GCR_SYSST_ICECLOCK ((uint32_t)(0x1UL << MXC_F_GCR_SYSST_ICECLOCK_POS)) /**< SYSST_ICECLOCK Mask */ +#define MXC_V_GCR_SYSST_ICECLOCK_UNLOCKED ((uint32_t)0x0UL) /**< SYSST_ICECLOCK_UNLOCKED Value */ +#define MXC_S_GCR_SYSST_ICECLOCK_UNLOCKED \ + (MXC_V_GCR_SYSST_ICECLOCK_UNLOCKED << MXC_F_GCR_SYSST_ICECLOCK_POS) /**< SYSST_ICECLOCK_UNLOCKED Setting */ +#define MXC_V_GCR_SYSST_ICECLOCK_LOCKED ((uint32_t)0x1UL) /**< SYSST_ICECLOCK_LOCKED Value */ +#define MXC_S_GCR_SYSST_ICECLOCK_LOCKED \ + (MXC_V_GCR_SYSST_ICECLOCK_LOCKED << MXC_F_GCR_SYSST_ICECLOCK_POS) /**< SYSST_ICECLOCK_LOCKED Setting */ + +/**@} end of group GCR_SYSST_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_RSTR1 GCR_RSTR1 + * @brief Reset 1. + * @{ + */ +#define MXC_F_GCR_RSTR1_WDT1_POS 8 /**< RSTR1_WDT1 Position */ +#define MXC_F_GCR_RSTR1_WDT1 ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_WDT1_POS)) /**< RSTR1_WDT1 Mask */ +#define MXC_V_GCR_RSTR1_WDT1_RESET_DONE ((uint32_t)0x0UL) /**< RSTR1_WDT1_RESET_DONE Value */ +#define MXC_S_GCR_RSTR1_WDT1_RESET_DONE \ + (MXC_V_GCR_RSTR1_WDT1_RESET_DONE << MXC_F_GCR_RSTR1_WDT1_POS) /**< RSTR1_WDT1_RESET_DONE Setting */ +#define MXC_V_GCR_RSTR1_WDT1_BUSY ((uint32_t)0x1UL) /**< RSTR1_WDT1_BUSY Value */ +#define MXC_S_GCR_RSTR1_WDT1_BUSY \ + (MXC_V_GCR_RSTR1_WDT1_BUSY << MXC_F_GCR_RSTR1_WDT1_POS) /**< RSTR1_WDT1_BUSY Setting */ + +#define MXC_F_GCR_RSTR1_PUFC_POS 27 /**< RSTR1_PUFC Position */ +#define MXC_F_GCR_RSTR1_PUFC ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_PUFC_POS)) /**< RSTR1_PUFC Mask */ + +#define MXC_F_GCR_RSTR1_CSPIS_POS 28 /**< RSTR1_CSPIS Position */ +#define MXC_F_GCR_RSTR1_CSPIS ((uint32_t)(0x1UL << MXC_F_GCR_RSTR1_CSPIS_POS)) /**< RSTR1_CSPIS Mask */ + +/**@} end of group GCR_RSTR1_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_PERCKCN1 GCR_PERCKCN1 + * @brief Peripheral Clock Disable. + * @{ + */ +#define MXC_F_GCR_PERCKCN1_TRNGD_POS 2 /**< PERCKCN1_TRNGD Position */ +#define MXC_F_GCR_PERCKCN1_TRNGD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_TRNGD_POS)) /**< PERCKCN1_TRNGD Mask */ +#define MXC_V_GCR_PERCKCN1_TRNGD_EN ((uint32_t)0x0UL) /**< PERCKCN1_TRNGD_EN Value */ +#define MXC_S_GCR_PERCKCN1_TRNGD_EN \ + (MXC_V_GCR_PERCKCN1_TRNGD_EN << MXC_F_GCR_PERCKCN1_TRNGD_POS) /**< PERCKCN1_TRNGD_EN Setting */ +#define MXC_V_GCR_PERCKCN1_TRNGD_DIS ((uint32_t)0x1UL) /**< PERCKCN1_TRNGD_DIS Value */ +#define MXC_S_GCR_PERCKCN1_TRNGD_DIS \ + (MXC_V_GCR_PERCKCN1_TRNGD_DIS << MXC_F_GCR_PERCKCN1_TRNGD_POS) /**< PERCKCN1_TRNGD_DIS Setting */ + +#define MXC_F_GCR_PERCKCN1_PUFCD_POS 3 /**< PERCKCN1_PUFCD Position */ +#define MXC_F_GCR_PERCKCN1_PUFCD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_PUFCD_POS)) /**< PERCKCN1_PUFCD Mask */ + +#define MXC_F_GCR_PERCKCN1_ICACHED_POS 11 /**< PERCKCN1_ICACHED Position */ +#define MXC_F_GCR_PERCKCN1_ICACHED ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_ICACHED_POS)) /**< PERCKCN1_ICACHED Mask */ + +#define MXC_F_GCR_PERCKCN1_CSPISD_POS 30 /**< PERCKCN1_CSPISD Position */ +#define MXC_F_GCR_PERCKCN1_CSPISD ((uint32_t)(0x1UL << MXC_F_GCR_PERCKCN1_CSPISD_POS)) /**< PERCKCN1_CSPISD Mask */ + +/**@} end of group GCR_PERCKCN1_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_EVTEN GCR_EVTEN + * @brief Event Enable Register. + * @{ + */ +#define MXC_F_GCR_EVTEN_CPU0DMAEVENT_POS 0 /**< EVTEN_CPU0DMAEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0DMAEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0DMAEVENT_POS)) /**< EVTEN_CPU0DMAEVENT Mask */ + +#define MXC_F_GCR_EVTEN_CPU0RXEVENT_POS 1 /**< EVTEN_CPU0RXEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0RXEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0RXEVENT_POS)) /**< EVTEN_CPU0RXEVENT Mask */ + +#define MXC_F_GCR_EVTEN_CPU0TXEVENT_POS 2 /**< EVTEN_CPU0TXEVENT Position */ +#define MXC_F_GCR_EVTEN_CPU0TXEVENT \ + ((uint32_t)(0x1UL << MXC_F_GCR_EVTEN_CPU0TXEVENT_POS)) /**< EVTEN_CPU0TXEVENT Mask */ + +/**@} end of group GCR_EVTEN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_REVISION GCR_REVISION + * @brief Revision Register. + * @{ + */ +#define MXC_F_GCR_REVISION_REVISION_POS 0 /**< REVISION_REVISION Position */ +#define MXC_F_GCR_REVISION_REVISION \ + ((uint32_t)(0xFFFFUL << MXC_F_GCR_REVISION_REVISION_POS)) /**< REVISION_REVISION Mask */ + +/**@} end of group GCR_REVISION_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_SYSSIE GCR_SYSSIE + * @brief System Status Interrupt Enable Register. + * @{ + */ +#define MXC_F_GCR_SYSSIE_ICEULIE_POS 0 /**< SYSSIE_ICEULIE Position */ +#define MXC_F_GCR_SYSSIE_ICEULIE ((uint32_t)(0x1UL << MXC_F_GCR_SYSSIE_ICEULIE_POS)) /**< SYSSIE_ICEULIE Mask */ +#define MXC_V_GCR_SYSSIE_ICEULIE_DIS ((uint32_t)0x0UL) /**< SYSSIE_ICEULIE_DIS Value */ +#define MXC_S_GCR_SYSSIE_ICEULIE_DIS \ + (MXC_V_GCR_SYSSIE_ICEULIE_DIS << MXC_F_GCR_SYSSIE_ICEULIE_POS) /**< SYSSIE_ICEULIE_DIS Setting */ +#define MXC_V_GCR_SYSSIE_ICEULIE_EN ((uint32_t)0x1UL) /**< SYSSIE_ICEULIE_EN Value */ +#define MXC_S_GCR_SYSSIE_ICEULIE_EN \ + (MXC_V_GCR_SYSSIE_ICEULIE_EN << MXC_F_GCR_SYSSIE_ICEULIE_POS) /**< SYSSIE_ICEULIE_EN Setting */ + +/**@} end of group GCR_SYSSIE_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCERR GCR_ECCERR + * @brief ECC Error Register + * @{ + */ +#define MXC_F_GCR_ECCERR_SYSRAM0ECCERR_POS 0 /**< ECCERR_SYSRAM0ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM0ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM0ECCERR_POS)) /**< ECCERR_SYSRAM0ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM1ECCERR_POS 1 /**< ECCERR_SYSRAM1ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM1ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM1ECCERR_POS)) /**< ECCERR_SYSRAM1ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM2ECCERR_POS 2 /**< ECCERR_SYSRAM2ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM2ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM2ECCERR_POS)) /**< ECCERR_SYSRAM2ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM3ECCERR_POS 3 /**< ECCERR_SYSRAM3ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM3ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM3ECCERR_POS)) /**< ECCERR_SYSRAM3ECCERR Mask */ + +#define MXC_F_GCR_ECCERR_SYSRAM4ECCERR_POS 4 /**< ECCERR_SYSRAM4ECCERR Position */ +#define MXC_F_GCR_ECCERR_SYSRAM4ECCERR \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCERR_SYSRAM4ECCERR_POS)) /**< ECCERR_SYSRAM4ECCERR Mask */ + +/**@} end of group GCR_ECCERR_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCNDED GCR_ECCNDED + * @brief ECC Not Double Error Detect Register + * @{ + */ +#define MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED_POS 0 /**< ECCNDED_SYSRAM0ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM0ECCNDED_POS)) /**< ECCNDED_SYSRAM0ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED_POS 1 /**< ECCNDED_SYSRAM1ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM1ECCNDED_POS)) /**< ECCNDED_SYSRAM1ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED_POS 2 /**< ECCNDED_SYSRAM2ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM2ECCNDED_POS)) /**< ECCNDED_SYSRAM2ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED_POS 3 /**< ECCNDED_SYSRAM3ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM3ECCNDED_POS)) /**< ECCNDED_SYSRAM3ECCNDED Mask */ + +#define MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED_POS 4 /**< ECCNDED_SYSRAM4ECCNDED Position */ +#define MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED \ + ((uint32_t)(0x1UL << MXC_F_GCR_ECCNDED_SYSRAM4ECCNDED_POS)) /**< ECCNDED_SYSRAM4ECCNDED Mask */ + +/**@} end of group GCR_ECCNDED_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCIRQEN GCR_ECCIRQEN + * @brief ECC IRQ Enable Register + * @{ + */ +#define MXC_F_GCR_ECCIRQEN_ECCERAD_POS 0 /**< ECCIRQEN_ECCERAD Position */ +#define MXC_F_GCR_ECCIRQEN_ECCERAD \ + ((uint32_t)(0x7FFFFFFFUL << MXC_F_GCR_ECCIRQEN_ECCERAD_POS)) /**< ECCIRQEN_ECCERAD Mask */ + +/**@} end of group GCR_ECCIRQEN_Register */ + +/** + * @ingroup gcr_registers + * @defgroup GCR_ECCERRAD GCR_ECCERRAD + * @brief ECC Error Address Register + * @{ + */ +#define MXC_F_GCR_ECCERRAD_ECCERAD_POS 0 /**< ECCERRAD_ECCERAD Position */ +#define MXC_F_GCR_ECCERRAD_ECCERAD \ + ((uint32_t)(0x7FFFFFFFUL << MXC_F_GCR_ECCERRAD_ECCERAD_POS)) /**< ECCERRAD_ECCERAD Mask */ + +/**@} end of group GCR_ECCERRAD_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GCR_REGS_H_ */ diff --git a/contrib/loaders/flash/max32xxx/max32xxx.inc b/contrib/loaders/flash/max32xxx/max32xxx.inc deleted file mode 100644 index 442165d0d1..0000000000 --- a/contrib/loaders/flash/max32xxx/max32xxx.inc +++ /dev/null @@ -1,6 +0,0 @@ -/* Autogenerated with ../../../../src/helper/bin2char.sh */ -0xdf,0xf8,0x44,0x40,0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1a,0xd0,0x47,0x68, -0x47,0x45,0xf7,0xd0,0x22,0x60,0x02,0xf1,0x04,0x02,0x57,0xf8,0x04,0x8b,0xc4,0xf8, -0x30,0x80,0xa5,0x68,0x45,0xf0,0x01,0x05,0xa5,0x60,0xd4,0xf8,0x08,0x80,0x18,0xf0, -0x01,0x0f,0xfa,0xd1,0x8f,0x42,0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b, -0x03,0xb1,0xdf,0xe7,0x00,0xbe,0x00,0xbf,0x00,0x00,0x00,0x40, diff --git a/contrib/loaders/flash/max32xxx/max32xxx.s b/contrib/loaders/flash/max32xxx/max32xxx.s deleted file mode 100644 index 38a4f12c32..0000000000 --- a/contrib/loaders/flash/max32xxx/max32xxx.s +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/*************************************************************************** - * Copyright (C) 2016 by Maxim Integrated * - * Kevin Gillespie +#else +#define printf(...) +#endif + +/***** Definitions *****/ +#define MXC_BASE_TPU ((uint32_t)0x40001000UL) +#define MXC_TPU ((struct mxc_tpu_regs *)MXC_BASE_TPU) +#define MXC_BASE_GCR ((uint32_t)0x40000000UL) +#define MXC_GCR ((struct mxc_gcr_regs *)MXC_BASE_GCR) + +/******************************************************************************/ +#define getbyte(temp8) \ +/* Wait for the Read FIFO to not equal the Write FIFO */ \ + do { while (*read_ptr == *write_ptr); \ + temp8 = **read_ptr; \ +/* Increment and wrap around the read pointer */ \ + if ((*read_ptr + 1) >= (uint8_t *)(work_end - 8 - 256)) { \ + *read_ptr = (uint8_t *)(work_start + 8); \ + } else { \ + (*read_ptr)++; \ + } \ + len--; \ + addr++; } while (0) + +/******************************************************************************/ +#ifndef ALGO_TEST +__attribute__ ((naked, section(".algo"))) +#endif +void algo_write(uint8_t *work_start, uint8_t *work_end, uint32_t len, uint32_t addr) +{ + printf(" > %s starting\n", __func__); + + volatile uint8_t * (*write_ptr) = (volatile uint8_t **)work_start; + volatile uint8_t * (*read_ptr) = (volatile uint8_t **)(work_start + 4); + uint32_t *flc_base = (uint32_t *)(work_end - 4 - 128); + uint32_t *options = (uint32_t *)(work_end - 8 - 128); + uint32_t *enc_buffer = (uint32_t *)(work_end - 8 - 256); + uint8_t temp8; + uint32_t addr_save; + int i; + struct mxc_flc_regs *MXC_FLC = (struct mxc_flc_regs *)*flc_base; + + printf(" > w%08x r%08x o%08x f%08x b%08x b%08x\n", + (uint32_t)write_ptr, (uint32_t)read_ptr, (uint32_t)*options, (uint32_t)*flc_base, + (uint32_t)enc_buffer, (uint32_t)(enc_buffer + 256)); + + if (*options & OPTIONS_ENC) { + /* Enable Memory Protection */ + MXC_GCR->scon |= MXC_F_GCR_SCON_MEMPROT_EN; + + /* Set the keysize */ + if (*options & OPTIONS_KEYSIZE) + MXC_GCR->scon |= MXC_F_GCR_SCON_MEMPROT_KEYSZ; + else + MXC_GCR->scon &= ~(MXC_F_GCR_SCON_MEMPROT_KEYSZ); + } else { + /* Disable memory protection */ + MXC_GCR->scon &= ~MXC_F_GCR_SCON_MEMPROT_EN; + } + + if (*options & OPTIONS_ENC) { + /* Setup the AES */ + + /* Enable CRYPTO clock */ + if ((MXC_GCR->clkcn & MXC_F_GCR_CLKCN_HIRC_EN) == 0) + MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC_EN; + + /* Disable CRYPTO clock gate */ + if (MXC_GCR->perckcn0 & MXC_F_GCR_PERCKCN0_CRYPTOD) + MXC_GCR->perckcn0 &= ~(MXC_F_GCR_PERCKCN0_CRYPTOD); + + /* Reset Crypto block and clear state */ + MXC_TPU->ctrl = MXC_F_TPU_CTRL_RST; + + /* Set the legacy bit */ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_FLAG_MODE; + + /* Byte swap the input and output */ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_BSO; + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_BSI; + } + + while (len) { + if ((*options & OPTIONS_128) == 0) { + /* Save the current address before we read from the working area */ + addr_save = addr; + + /* 32-bit write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WDTH; + + enc_buffer[0] = 0; + for (i = 0; i < 4; i++) { + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[0] |= (temp8 << (i * 8)); + } + + /* 32-bit write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WDTH; + + MXC_FLC->addr = addr_save; + MXC_FLC->data[0] = enc_buffer[0]; + + /* Enable the write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WR; + + /* Wait for the operation to complete */ + do {} while (MXC_FLC->cn & MXC_F_FLC_CN_WR); + + /* Check access violations */ + if (MXC_FLC->intr & MXC_F_FLC_INTR_AF) { + MXC_FLC->intr &= ~MXC_F_FLC_INTR_AF; + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + #else + printf(" > Error writing to flash\n"); + return; + #endif + } + } else { + /* Save the current address before we read from the working area */ + addr_save = addr; + + /* Fill the buffer with the plain text data from the working area */ + for (i = 0; i < 4; i++) { + /* Get data from the working area, pad with 0xFF */ + enc_buffer[i] = 0; + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (0)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (8)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (16)); + /* Get data from the working area, pad with 0xFF */ + if (len) { + getbyte(temp8); + __asm("nop\n"); + } else { + temp8 = 0xFF; + __asm("nop\n"); + } + enc_buffer[i] |= (temp8 << (24)); + } + + if (*options & OPTIONS_ENC) { + /* XOR data with the address */ + for (i = 0; i < 4; i++) { + if (*options & OPTIONS_RELATIVE_XOR) + enc_buffer[i] ^= ((addr_save & 0x00FFFFFF) + i * 4); + else + enc_buffer[i] ^= (addr_save + i * 4); + } + + /* Encrypt the plain text + * Clear interrupt flags*/ + MXC_TPU->ctrl |= MXC_F_TPU_CTRL_CPH_DONE; + + MXC_TPU->cipher_ctrl = ((0x0 << MXC_F_TPU_CIPHER_CTRL_MODE_POS) | + (0x0 << MXC_F_TPU_CIPHER_CTRL_ENC_POS)); + + if (*options & OPTIONS_KEYSIZE) { + /* ECB, AES-256, encrypt */ + MXC_TPU->cipher_ctrl |= + (0x3 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS); + } else { + /* ECB, AES-128, encrypt */ + MXC_TPU->cipher_ctrl |= + (0x1 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS); + } + + /* Set the key source */ + MXC_TPU->cipher_ctrl = + ((MXC_TPU->cipher_ctrl & ~MXC_F_TPU_CIPHER_CTRL_SRC) | + (0x3 << MXC_F_TPU_CIPHER_CTRL_SRC_POS)); + + /* Copy data to start the operation */ + MXC_TPU->din[0] = enc_buffer[0]; + MXC_TPU->din[1] = enc_buffer[1]; + MXC_TPU->din[2] = enc_buffer[2]; + MXC_TPU->din[3] = enc_buffer[3]; + + /* Wait until operation is complete */ + do {} while (!(MXC_TPU->ctrl & MXC_F_TPU_CTRL_CPH_DONE)); + + /* Copy the data out */ + enc_buffer[0] = MXC_TPU->dout[0]; + enc_buffer[1] = MXC_TPU->dout[1]; + enc_buffer[2] = MXC_TPU->dout[2]; + enc_buffer[3] = MXC_TPU->dout[3]; + } + + /* 128-bit write */ + MXC_FLC->cn &= ~MXC_F_FLC_CN_WDTH; + + MXC_FLC->addr = addr_save; + MXC_FLC->data[0] = enc_buffer[0]; + MXC_FLC->data[1] = enc_buffer[1]; + MXC_FLC->data[2] = enc_buffer[2]; + MXC_FLC->data[3] = enc_buffer[3]; + + /* Enable the write */ + MXC_FLC->cn |= MXC_F_FLC_CN_WR; + + /* Wait for the operation to complete */ + do {} while (MXC_FLC->cn & MXC_F_FLC_CN_WR); + + /* Check access violations */ + if (MXC_FLC->intr & MXC_F_FLC_INTR_AF) { + MXC_FLC->intr &= ~MXC_F_FLC_INTR_AF; + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + printf(" > Error writing to flash\n"); + return; + #endif + } + } + } + + #ifndef ALGO_TEST + #ifdef __riscv + __asm("ebreak\n"); + #else + __asm("bkpt\n"); + #endif + #else + printf(" > %s returning\n", __func__); + return; + #endif +} diff --git a/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc b/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc new file mode 100644 index 0000000000..cdc373071a --- /dev/null +++ b/contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc @@ -0,0 +1,57 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x51,0xe9,0x22,0x54,0x15,0xf0,0x02,0x0f,0x4f,0xf0,0x80,0x45,0x00,0x93,0xa1,0xf5, +0x84,0x76,0x2f,0x68,0x00,0xf0,0x90,0x80,0x47,0xf4,0x80,0x17,0x2f,0x60,0x51,0xf8, +0x88,0x7c,0x17,0xf0,0x40,0x0f,0x2f,0x68,0x14,0xbf,0x47,0xf4,0x00,0x17,0x27,0xf4, +0x00,0x17,0x2f,0x60,0x51,0xf8,0x88,0x5c,0xad,0x07,0x1e,0xd5,0x4f,0xf0,0x80,0x45, +0xaf,0x68,0x7b,0x03,0x5e,0xbf,0xaf,0x68,0x47,0xf4,0x80,0x27,0xaf,0x60,0x6f,0x6a, +0x7f,0x04,0x42,0xbf,0x6f,0x6a,0x27,0xf4,0x80,0x47,0x6f,0x62,0xc0,0x4d,0x01,0x27, +0x2f,0x60,0x2f,0x68,0x47,0xf4,0x80,0x47,0x2f,0x60,0x2f,0x68,0x47,0xf0,0x10,0x07, +0x2f,0x60,0x2f,0x68,0x47,0xf0,0x20,0x07,0x2f,0x60,0xa1,0xf1,0xfc,0x05,0x03,0x95, +0x00,0xf1,0x08,0x05,0x01,0x95,0xa1,0xf5,0x82,0x75,0x02,0x95,0xb4,0x4d,0xa1,0xf5, +0x80,0x7c,0x00,0x2a,0x00,0xf0,0x63,0x81,0x51,0xf8,0x88,0x7c,0x17,0xf0,0x01,0x0e, +0x50,0xd1,0xa7,0x68,0x47,0xf0,0x10,0x07,0xa7,0x60,0x00,0x9f,0xc6,0xf8,0x00,0xe0, +0x00,0x2a,0x44,0xd0,0xd0,0xf8,0x04,0x90,0xd0,0xf8,0x00,0x80,0xc1,0x45,0xf9,0xd0, +0xd0,0xf8,0x04,0x80,0xd0,0xf8,0x04,0x90,0x98,0xf8,0x00,0x80,0x09,0xf1,0x01,0x09, +0x4e,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0x90,0x01,0x9b,0x43,0x60,0x09,0xf1,0x01,0x09, +0x88,0xbf,0xc0,0xf8,0x04,0x90,0x01,0x3a,0x01,0x37,0x33,0x68,0x08,0xfa,0x0e,0xf8, +0x0e,0xf1,0x08,0x0e,0x43,0xea,0x08,0x08,0xbe,0xf1,0x20,0x0f,0xc6,0xf8,0x00,0x80, +0xd6,0xd1,0xd4,0xf8,0x08,0xe0,0x00,0x9b,0x4e,0xf0,0x10,0x0e,0xc4,0xf8,0x08,0xe0, +0x23,0x60,0x33,0x68,0x23,0x63,0xa3,0x68,0x43,0xf0,0x01,0x03,0xa3,0x60,0xa3,0x68, +0xdb,0x07,0xfc,0xd4,0x63,0x6a,0x9b,0x07,0x04,0xd5,0x63,0x6a,0x23,0xf0,0x02,0x03, +0x63,0x62,0x00,0xbe,0x00,0x97,0xac,0xe7,0x27,0xf4,0x80,0x17,0x79,0xe7,0x4f,0xf0, +0xff,0x08,0xd2,0xe7,0xa1,0xf5,0x86,0x78,0x00,0x9f,0xc1,0x46,0x00,0x23,0x49,0xf8, +0x04,0x3f,0x00,0x2a,0x00,0xf0,0x06,0x81,0xd0,0xf8,0x04,0xa0,0xd0,0xf8,0x00,0xe0, +0xf2,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xe0,0xd0,0xf8,0x04,0xa0,0x9e,0xf8,0x00,0xe0, +0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60, +0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a,0x01,0x37,0xc9,0xf8, +0x00,0xe0,0x00,0x2a,0x00,0xf0,0xe9,0x80,0xd0,0xf8,0x04,0xb0,0xd0,0xf8,0x00,0xa0, +0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0,0x9a,0xf8,0x00,0xb0,0xd0,0xf8,0x04,0xa0, +0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60, +0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a,0x01,0x37,0x4e,0xea, +0x0b,0x2e,0xc9,0xf8,0x00,0xe0,0x00,0x2a,0x00,0xf0,0xca,0x80,0xd0,0xf8,0x04,0xb0, +0xd0,0xf8,0x00,0xa0,0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0,0x9a,0xf8,0x00,0xb0, +0xd0,0xf8,0x04,0xa0,0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf,0xd0,0xf8,0x04,0xa0, +0x01,0x9b,0x43,0x60,0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8,0x04,0xa0,0x01,0x3a, +0x01,0x37,0x4e,0xea,0x0b,0x4e,0xc9,0xf8,0x00,0xe0,0x00,0x2a,0x00,0xf0,0xab,0x80, +0xd0,0xf8,0x04,0xb0,0xd0,0xf8,0x00,0xa0,0xd3,0x45,0xf9,0xd0,0xd0,0xf8,0x04,0xa0, +0x9a,0xf8,0x00,0xb0,0xd0,0xf8,0x04,0xa0,0x0a,0xf1,0x01,0x0a,0x56,0x45,0x8d,0xbf, +0xd0,0xf8,0x04,0xa0,0x01,0x9b,0x43,0x60,0x0a,0xf1,0x01,0x0a,0x88,0xbf,0xc0,0xf8, +0x04,0xa0,0x01,0x3a,0x01,0x37,0x03,0x9b,0x4e,0xea,0x0b,0x6e,0x99,0x45,0xc9,0xf8, +0x00,0xe0,0x7f,0xf4,0x73,0xaf,0x51,0xf8,0x88,0x3c,0x9b,0x07,0x55,0xd5,0x00,0x9b, +0x4f,0xf0,0x00,0x0e,0x23,0xf0,0x7f,0x4a,0x51,0xf8,0x88,0x3c,0x58,0xf8,0x04,0x9f, +0x9b,0x06,0x56,0xbf,0x00,0x9b,0x0a,0xeb,0x0e,0x0b,0x0e,0xeb,0x03,0x0b,0x0e,0xf1, +0x04,0x0e,0x8b,0xea,0x09,0x09,0xbe,0xf1,0x10,0x0f,0xc8,0xf8,0x00,0x90,0xeb,0xd1, +0xd5,0xf8,0x00,0xe0,0x4e,0xf0,0x00,0x6e,0xc5,0xf8,0x00,0xe0,0x4f,0xf0,0x00,0x0e, +0xc5,0xf8,0x04,0xe0,0x51,0xf8,0x88,0x3c,0xd5,0xf8,0x04,0xe0,0x5b,0x06,0x4c,0xbf, +0x4e,0xf0,0x30,0x0e,0x4e,0xf0,0x10,0x0e,0xc5,0xf8,0x04,0xe0,0xd5,0xf8,0x04,0xe0, +0x4e,0xf0,0x0c,0x0e,0xc5,0xf8,0x04,0xe0,0x33,0x68,0x2b,0x62,0x02,0x9b,0x1b,0x68, +0x6b,0x62,0xdc,0xf8,0x00,0x30,0xab,0x62,0x51,0xf8,0xfc,0x3c,0xeb,0x62,0xd5,0xf8, +0x00,0xe0,0x1e,0xf0,0x00,0x6f,0xfa,0xd0,0xd5,0xf8,0x30,0xe0,0xc6,0xf8,0x00,0xe0, +0x02,0x9b,0xd5,0xf8,0x34,0xe0,0xc3,0xf8,0x00,0xe0,0xd5,0xf8,0x38,0xe0,0xcc,0xf8, +0x00,0xe0,0xd5,0xf8,0x3c,0xe0,0x41,0xf8,0xfc,0xec,0xd4,0xf8,0x08,0xe0,0x00,0x9b, +0x2e,0xf0,0x10,0x0e,0xc4,0xf8,0x08,0xe0,0x23,0x60,0x33,0x68,0x23,0x63,0x02,0x9b, +0x1b,0x68,0x63,0x63,0xdc,0xf8,0x00,0x30,0xa3,0x63,0x51,0xf8,0xfc,0x3c,0xe3,0x63, +0xa3,0x68,0x43,0xf0,0x01,0x03,0xa3,0x60,0xa3,0x68,0xdb,0x07,0xfc,0xd4,0x63,0x6a, +0x9b,0x07,0x7f,0xf5,0xef,0xae,0x63,0x6a,0x23,0xf0,0x02,0x03,0x63,0x62,0x00,0xbe, +0x00,0x10,0x00,0x40,0x4f,0xf0,0xff,0x0e,0x11,0xe7,0x4f,0xf0,0xff,0x0b,0x2e,0xe7, +0x4f,0xf0,0xff,0x0b,0x4d,0xe7,0x4f,0xf0,0xff,0x0b,0x6c,0xe7, diff --git a/contrib/loaders/flash/max32xxx/tpu_regs.h b/contrib/loaders/flash/max32xxx/tpu_regs.h new file mode 100644 index 0000000000..f750148af2 --- /dev/null +++ b/contrib/loaders/flash/max32xxx/tpu_regs.h @@ -0,0 +1,572 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2016 by Maxim Integrated * + * Copyright (C) 2025 Analog Devices, Inc. * + ***************************************************************************/ + +#ifndef _TPU_REGS_H_ +#define _TPU_REGS_H_ + +/* **** Includes **** */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__ICCARM__) +#pragma system_include +#endif + +/*/ @cond */ +/* + If types are not defined elsewhere (CMSIS) define them here +*/ +#ifndef __IO +#define __IO volatile +#endif +#ifndef __I +#define __I volatile const +#endif +#ifndef __O +#define __O volatile +#endif +#ifndef __R +#define __R volatile const +#endif +/*/ @endcond */ + +/* **** Definitions **** */ + +/** + * @ingroup tpu + * @defgroup tpu_registers Registers + * @brief Registers, Bit Masks and Bit Positions for the TPU Peripheral Module. + * @description The Trust Protection Unit used to assist the computationally intensive operations of several common + * cryptographic algorithms. + */ + +/** + * @ingroup tpu_registers + * Structure type to access the TPU Registers. + */ +struct mxc_tpu_regs { + __IO uint32_t ctrl; /**< \b 0x00:<\tt> TPU CTRL Register */ + __IO uint32_t cipher_ctrl; /**< \b 0x04:<\tt> TPU CIPHER_CTRL Register */ + __IO uint32_t hash_ctrl; /**< \b 0x08:<\tt> TPU HASH_CTRL Register */ + __IO uint32_t crc_ctrl; /**< \b 0x0C:<\tt> TPU CRC_CTRL Register */ + __IO uint32_t dma_src; /**< \b 0x10:<\tt> TPU DMA_SRC Register */ + __IO uint32_t dma_dest; /**< \b 0x14:<\tt> TPU DMA_DEST Register */ + __IO uint32_t dma_cnt; /**< \b 0x18:<\tt> TPU DMA_CNT Register */ + __IO uint32_t maa_ctrl; /**< \b 0x1C:<\tt> TPU MAA_CTRL Register */ + __O uint32_t din[4]; /**< \b 0x20:<\tt> TPU DIN Register */ + __I uint32_t dout[4]; /**< \b 0x30:<\tt> TPU DOUT Register */ + __IO uint32_t crc_poly; /**< \b 0x40:<\tt> TPU CRC_POLY Register */ + __IO uint32_t crc_val; /**< \b 0x44:<\tt> TPU CRC_VAL Register */ + __I uint32_t crc_prng; /**< \b 0x48:<\tt> TPU CRC_PRNG Register */ + __IO uint32_t ham_ecc; /**< \b 0x4C:<\tt> TPU HAM_ECC Register */ + __IO uint32_t cipher_init[4]; /**< \b 0x50:<\tt> TPU CIPHER_INIT Register */ + __O uint32_t cipher_key[8]; /**< \b 0x60:<\tt> TPU CIPHER_KEY Register */ + __IO uint32_t hash_digest[16]; /**< \b 0x80:<\tt> TPU HASH_DIGEST Register */ + __IO uint32_t hash_msg_sz[4]; /**< \b 0xC0:<\tt> TPU HASH_MSG_SZ Register */ + __IO uint32_t maa_maws; /**< \b 0xD0:<\tt> TPU MAA_MAWS Register */ +}; + +/* Register offsets for module TPU */ +/** + * @ingroup tpu_registers + * @defgroup TPU_Register_Offsets Register Offsets + * @brief TPU Peripheral Register Offsets from the TPU Base Peripheral Address. + * @{ + */ +#define MXC_R_TPU_CTRL ((uint32_t)0x00000000UL) /**< Offset from TPU Base Address: 0x0x000 */ +#define MXC_R_TPU_CIPHER_CTRL ((uint32_t)0x00000004UL) /**< Offset from TPU Base Address: 0x0x004 */ +#define MXC_R_TPU_HASH_CTRL ((uint32_t)0x00000008UL) /**< Offset from TPU Base Address: 0x0x008 */ +#define MXC_R_TPU_CRC_CTRL ((uint32_t)0x0000000CUL) /**< Offset from TPU Base Address: 0x0x00C */ +#define MXC_R_TPU_DMA_SRC ((uint32_t)0x00000010UL) /**< Offset from TPU Base Address: 0x0x010 */ +#define MXC_R_TPU_DMA_DEST ((uint32_t)0x00000014UL) /**< Offset from TPU Base Address: 0x0x014 */ +#define MXC_R_TPU_DMA_CNT ((uint32_t)0x00000018UL) /**< Offset from TPU Base Address: 0x0x018 */ +#define MXC_R_TPU_MAA_CTRL ((uint32_t)0x0000001CUL) /**< Offset from TPU Base Address: 0x0x01C */ +#define MXC_R_TPU_DIN ((uint32_t)0x00000020UL) /**< Offset from TPU Base Address: 0x0x020 */ +#define MXC_R_TPU_DOUT ((uint32_t)0x00000030UL) /**< Offset from TPU Base Address: 0x0x030 */ +#define MXC_R_TPU_CRC_POLY ((uint32_t)0x00000040UL) /**< Offset from TPU Base Address: 0x0x040 */ +#define MXC_R_TPU_CRC_VAL ((uint32_t)0x00000044UL) /**< Offset from TPU Base Address: 0x0x044 */ +#define MXC_R_TPU_CRC_PRNG ((uint32_t)0x00000048UL) /**< Offset from TPU Base Address: 0x0x048 */ +#define MXC_R_TPU_HAM_ECC ((uint32_t)0x0000004CUL) /**< Offset from TPU Base Address: 0x0x04C */ +#define MXC_R_TPU_CIPHER_INIT ((uint32_t)0x00000050UL) /**< Offset from TPU Base Address: 0x0x050 */ +#define MXC_R_TPU_CIPHER_KEY ((uint32_t)0x00000060UL) /**< Offset from TPU Base Address: 0x0x060 */ +#define MXC_R_TPU_HASH_DIGEST ((uint32_t)0x00000080UL) /**< Offset from TPU Base Address: 0x0x080 */ +#define MXC_R_TPU_HASH_MSG_SZ ((uint32_t)0x000000C0UL) /**< Offset from TPU Base Address: 0x0x0C0 */ +#define MXC_R_TPU_MAA_MAWS ((uint32_t)0x000000D0UL) /**< Offset from TPU Base Address: 0x0x0D0 */ + /**@} end of group tpu_registers */ + +/** + * @ingroup tpu_registers + * @defgroup CTRL_Register + * @brief Crypto Control Register. + * @{ + */ +#define MXC_F_TPU_CTRL_RST_POS 0 /**< CTRL_RST Position */ +#define MXC_F_TPU_CTRL_RST ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_RST_POS)) /**< CTRL_RST Mask */ + +#define MXC_F_TPU_CTRL_INTR_POS 1 /**< CTRL_INTR Position */ +#define MXC_F_TPU_CTRL_INTR ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_INTR_POS)) /**< CTRL_INTR Mask */ + +#define MXC_F_TPU_CTRL_SRC_POS 2 /**< CTRL_SRC Position */ +#define MXC_F_TPU_CTRL_SRC ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_SRC_POS)) /**< CTRL_SRC Mask */ + +#define MXC_F_TPU_CTRL_BSO_POS 4 /**< CTRL_BSO Position */ +#define MXC_F_TPU_CTRL_BSO ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_BSO_POS)) /**< CTRL_BSO Mask */ + +#define MXC_F_TPU_CTRL_BSI_POS 5 /**< CTRL_BSI Position */ +#define MXC_F_TPU_CTRL_BSI ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_BSI_POS)) /**< CTRL_BSI Mask */ + +#define MXC_F_TPU_CTRL_WAIT_EN_POS 6 /**< CTRL_WAIT_EN Position */ +#define MXC_F_TPU_CTRL_WAIT_EN ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_WAIT_EN_POS)) /**< CTRL_WAIT_EN Mask */ + +#define MXC_F_TPU_CTRL_WAIT_POL_POS 7 /**< CTRL_WAIT_POL Position */ +#define MXC_F_TPU_CTRL_WAIT_POL ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_WAIT_POL_POS)) /**< CTRL_WAIT_POL Mask */ + +#define MXC_F_TPU_CTRL_WRSRC_POS 8 /**< CTRL_WRSRC Position */ +#define MXC_F_TPU_CTRL_WRSRC ((uint32_t)(0x3UL << MXC_F_TPU_CTRL_WRSRC_POS)) /**< CTRL_WRSRC Mask */ +#define MXC_V_TPU_CTRL_WRSRC_NONE ((uint32_t)0x0UL) /**< CTRL_WRSRC_NONE Value */ +#define MXC_S_TPU_CTRL_WRSRC_NONE \ + (MXC_V_TPU_CTRL_WRSRC_NONE << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_NONE Setting */ +#define MXC_V_TPU_CTRL_WRSRC_CIPHEROUTPUT ((uint32_t)0x1UL) /**< CTRL_WRSRC_CIPHEROUTPUT Value */ +#define MXC_S_TPU_CTRL_WRSRC_CIPHEROUTPUT \ + (MXC_V_TPU_CTRL_WRSRC_CIPHEROUTPUT << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_CIPHEROUTPUT Setting */ +#define MXC_V_TPU_CTRL_WRSRC_READFIFO ((uint32_t)0x2UL) /**< CTRL_WRSRC_READFIFO Value */ +#define MXC_S_TPU_CTRL_WRSRC_READFIFO \ + (MXC_V_TPU_CTRL_WRSRC_READFIFO << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_READFIFO Setting */ +#define MXC_V_TPU_CTRL_WRSRC_RFU ((uint32_t)0x3UL) /**< CTRL_WRSRC_RFU Value */ +#define MXC_S_TPU_CTRL_WRSRC_RFU (MXC_V_TPU_CTRL_WRSRC_RFU << MXC_F_TPU_CTRL_WRSRC_POS) /**< CTRL_WRSRC_RFU Setting */ + +#define MXC_F_TPU_CTRL_RDSRC_POS 10 /**< CTRL_RDSRC Position */ +#define MXC_F_TPU_CTRL_RDSRC ((uint32_t)(0x3UL << MXC_F_TPU_CTRL_RDSRC_POS)) /**< CTRL_RDSRC Mask */ +#define MXC_V_TPU_CTRL_RDSRC_DMADISABLED ((uint32_t)0x0UL) /**< CTRL_RDSRC_DMADISABLED Value */ +#define MXC_S_TPU_CTRL_RDSRC_DMADISABLED \ + (MXC_V_TPU_CTRL_RDSRC_DMADISABLED << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_DMADISABLED Setting */ +#define MXC_V_TPU_CTRL_RDSRC_DMAORAPB ((uint32_t)0x1UL) /**< CTRL_RDSRC_DMAORAPB Value */ +#define MXC_S_TPU_CTRL_RDSRC_DMAORAPB \ + (MXC_V_TPU_CTRL_RDSRC_DMAORAPB << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_DMAORAPB Setting */ +#define MXC_V_TPU_CTRL_RDSRC_RNG ((uint32_t)0x2UL) /**< CTRL_RDSRC_RNG Value */ +#define MXC_S_TPU_CTRL_RDSRC_RNG (MXC_V_TPU_CTRL_RDSRC_RNG << MXC_F_TPU_CTRL_RDSRC_POS) /**< CTRL_RDSRC_RNG Setting */ + +#define MXC_F_TPU_CTRL_FLAG_MODE_POS 14 /**< CTRL_FLAG_MODE Position */ +#define MXC_F_TPU_CTRL_FLAG_MODE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_FLAG_MODE_POS)) /**< CTRL_FLAG_MODE Mask */ + +#define MXC_F_TPU_CTRL_DMADNEMSK_POS 15 /**< CTRL_DMADNEMSK Position */ +#define MXC_F_TPU_CTRL_DMADNEMSK ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DMADNEMSK_POS)) /**< CTRL_DMADNEMSK Mask */ + +#define MXC_F_TPU_CTRL_DMA_DONE_POS 24 /**< CTRL_DMA_DONE Position */ +#define MXC_F_TPU_CTRL_DMA_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DMA_DONE_POS)) /**< CTRL_DMA_DONE Mask */ + +#define MXC_F_TPU_CTRL_GLS_DONE_POS 25 /**< CTRL_GLS_DONE Position */ +#define MXC_F_TPU_CTRL_GLS_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_GLS_DONE_POS)) /**< CTRL_GLS_DONE Mask */ + +#define MXC_F_TPU_CTRL_HSH_DONE_POS 26 /**< CTRL_HSH_DONE Position */ +#define MXC_F_TPU_CTRL_HSH_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_HSH_DONE_POS)) /**< CTRL_HSH_DONE Mask */ + +#define MXC_F_TPU_CTRL_CPH_DONE_POS 27 /**< CTRL_CPH_DONE Position */ +#define MXC_F_TPU_CTRL_CPH_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_CPH_DONE_POS)) /**< CTRL_CPH_DONE Mask */ + +#define MXC_F_TPU_CTRL_MAA_DONE_POS 28 /**< CTRL_MAA_DONE Position */ +#define MXC_F_TPU_CTRL_MAA_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_MAA_DONE_POS)) /**< CTRL_MAA_DONE Mask */ + +#define MXC_F_TPU_CTRL_ERR_POS 29 /**< CTRL_ERR Position */ +#define MXC_F_TPU_CTRL_ERR ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_ERR_POS)) /**< CTRL_ERR Mask */ + +#define MXC_F_TPU_CTRL_RDY_POS 30 /**< CTRL_RDY Position */ +#define MXC_F_TPU_CTRL_RDY ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_RDY_POS)) /**< CTRL_RDY Mask */ + +#define MXC_F_TPU_CTRL_DONE_POS 31 /**< CTRL_DONE Position */ +#define MXC_F_TPU_CTRL_DONE ((uint32_t)(0x1UL << MXC_F_TPU_CTRL_DONE_POS)) /**< CTRL_DONE Mask */ + +/**@} end of group CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_CTRL_Register + * @brief Cipher Control Register. + * @{ + */ +#define MXC_F_TPU_CIPHER_CTRL_ENC_POS 0 /**< CIPHER_CTRL_ENC Position */ +#define MXC_F_TPU_CIPHER_CTRL_ENC ((uint32_t)(0x1UL << MXC_F_TPU_CIPHER_CTRL_ENC_POS)) /**< CIPHER_CTRL_ENC Mask */ + +#define MXC_F_TPU_CIPHER_CTRL_KEY_POS 1 /**< CIPHER_CTRL_KEY Position */ +#define MXC_F_TPU_CIPHER_CTRL_KEY ((uint32_t)(0x1UL << MXC_F_TPU_CIPHER_CTRL_KEY_POS)) /**< CIPHER_CTRL_KEY Mask */ + +#define MXC_F_TPU_CIPHER_CTRL_SRC_POS 2 /**< CIPHER_CTRL_SRC Position */ +#define MXC_F_TPU_CIPHER_CTRL_SRC ((uint32_t)(0x3UL << MXC_F_TPU_CIPHER_CTRL_SRC_POS)) /**< CIPHER_CTRL_SRC Mask */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_CIPHERKEY ((uint32_t)0x0UL) /**< CIPHER_CTRL_SRC_CIPHERKEY Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_CIPHERKEY \ + (MXC_V_TPU_CIPHER_CTRL_SRC_CIPHERKEY << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_CIPHERKEY Setting */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_REGFILE ((uint32_t)0x2UL) /**< CIPHER_CTRL_SRC_REGFILE Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_REGFILE \ + (MXC_V_TPU_CIPHER_CTRL_SRC_REGFILE << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_REGFILE Setting */ +#define MXC_V_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE ((uint32_t)0x3UL) /**< CIPHER_CTRL_SRC_QSPIKEY_REGFILE Value */ +#define MXC_S_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE \ + (MXC_V_TPU_CIPHER_CTRL_SRC_QSPIKEY_REGFILE \ + << MXC_F_TPU_CIPHER_CTRL_SRC_POS) /**< CIPHER_CTRL_SRC_QSPIKEY_REGFILE Setting */ + +#define MXC_F_TPU_CIPHER_CTRL_CIPHER_POS 4 /**< CIPHER_CTRL_CIPHER Position */ +#define MXC_F_TPU_CIPHER_CTRL_CIPHER \ + ((uint32_t)(0x7UL << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS)) /**< CIPHER_CTRL_CIPHER Mask */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_DIS ((uint32_t)0x0UL) /**< CIPHER_CTRL_CIPHER_DIS Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_DIS \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_DIS << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_DIS Setting */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES128 ((uint32_t)0x1UL) /**< CIPHER_CTRL_CIPHER_AES128 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES128 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES128 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES128 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES192 ((uint32_t)0x2UL) /**< CIPHER_CTRL_CIPHER_AES192 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES192 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES192 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES192 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_AES256 ((uint32_t)0x3UL) /**< CIPHER_CTRL_CIPHER_AES256 Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_AES256 \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_AES256 << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_AES256 Setting \ + */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_DES ((uint32_t)0x4UL) /**< CIPHER_CTRL_CIPHER_DES Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_DES \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_DES << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_DES Setting */ +#define MXC_V_TPU_CIPHER_CTRL_CIPHER_TDES ((uint32_t)0x5UL) /**< CIPHER_CTRL_CIPHER_TDES Value */ +#define MXC_S_TPU_CIPHER_CTRL_CIPHER_TDES \ + (MXC_V_TPU_CIPHER_CTRL_CIPHER_TDES << MXC_F_TPU_CIPHER_CTRL_CIPHER_POS) /**< CIPHER_CTRL_CIPHER_TDES Setting */ + +#define MXC_F_TPU_CIPHER_CTRL_MODE_POS 8 /**< CIPHER_CTRL_MODE Position */ +#define MXC_F_TPU_CIPHER_CTRL_MODE ((uint32_t)(0x7UL << MXC_F_TPU_CIPHER_CTRL_MODE_POS)) /**< CIPHER_CTRL_MODE Mask */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_ECB ((uint32_t)0x0UL) /**< CIPHER_CTRL_MODE_ECB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_ECB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_ECB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_ECB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CBC ((uint32_t)0x1UL) /**< CIPHER_CTRL_MODE_CBC Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CBC \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CBC << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CBC Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CFB ((uint32_t)0x2UL) /**< CIPHER_CTRL_MODE_CFB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CFB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CFB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CFB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_OFB ((uint32_t)0x3UL) /**< CIPHER_CTRL_MODE_OFB Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_OFB \ + (MXC_V_TPU_CIPHER_CTRL_MODE_OFB << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_OFB Setting */ +#define MXC_V_TPU_CIPHER_CTRL_MODE_CTR ((uint32_t)0x4UL) /**< CIPHER_CTRL_MODE_CTR Value */ +#define MXC_S_TPU_CIPHER_CTRL_MODE_CTR \ + (MXC_V_TPU_CIPHER_CTRL_MODE_CTR << MXC_F_TPU_CIPHER_CTRL_MODE_POS) /**< CIPHER_CTRL_MODE_CTR Setting */ + +/**@} end of group CIPHER_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_CTRL_Register + * @brief HASH Control Register. + * @{ + */ +#define MXC_F_TPU_HASH_CTRL_INIT_POS 0 /**< HASH_CTRL_INIT Position */ +#define MXC_F_TPU_HASH_CTRL_INIT ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_INIT_POS)) /**< HASH_CTRL_INIT Mask */ + +#define MXC_F_TPU_HASH_CTRL_XOR_POS 1 /**< HASH_CTRL_XOR Position */ +#define MXC_F_TPU_HASH_CTRL_XOR ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_XOR_POS)) /**< HASH_CTRL_XOR Mask */ + +#define MXC_F_TPU_HASH_CTRL_HASH_POS 2 /**< HASH_CTRL_HASH Position */ +#define MXC_F_TPU_HASH_CTRL_HASH ((uint32_t)(0x7UL << MXC_F_TPU_HASH_CTRL_HASH_POS)) /**< HASH_CTRL_HASH Mask */ +#define MXC_V_TPU_HASH_CTRL_HASH_DIS ((uint32_t)0x0UL) /**< HASH_CTRL_HASH_DIS Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_DIS \ + (MXC_V_TPU_HASH_CTRL_HASH_DIS << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_DIS Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA1 ((uint32_t)0x1UL) /**< HASH_CTRL_HASH_SHA1 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA1 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA1 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA1 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA224 ((uint32_t)0x2UL) /**< HASH_CTRL_HASH_SHA224 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA224 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA224 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA224 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA256 ((uint32_t)0x3UL) /**< HASH_CTRL_HASH_SHA256 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA256 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA256 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA256 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA384 ((uint32_t)0x4UL) /**< HASH_CTRL_HASH_SHA384 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA384 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA384 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA384 Setting */ +#define MXC_V_TPU_HASH_CTRL_HASH_SHA512 ((uint32_t)0x5UL) /**< HASH_CTRL_HASH_SHA512 Value */ +#define MXC_S_TPU_HASH_CTRL_HASH_SHA512 \ + (MXC_V_TPU_HASH_CTRL_HASH_SHA512 << MXC_F_TPU_HASH_CTRL_HASH_POS) /**< HASH_CTRL_HASH_SHA512 Setting */ + +#define MXC_F_TPU_HASH_CTRL_LAST_POS 5 /**< HASH_CTRL_LAST Position */ +#define MXC_F_TPU_HASH_CTRL_LAST ((uint32_t)(0x1UL << MXC_F_TPU_HASH_CTRL_LAST_POS)) /**< HASH_CTRL_LAST Mask */ + +/**@} end of group HASH_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_CTRL_Register + * @brief CRC Control Register. + * @{ + */ +#define MXC_F_TPU_CRC_CTRL_CRC_POS 0 /**< CRC_CTRL_CRC Position */ +#define MXC_F_TPU_CRC_CTRL_CRC ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_CRC_POS)) /**< CRC_CTRL_CRC Mask */ + +#define MXC_F_TPU_CRC_CTRL_MSB_POS 1 /**< CRC_CTRL_MSB Position */ +#define MXC_F_TPU_CRC_CTRL_MSB ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_MSB_POS)) /**< CRC_CTRL_MSB Mask */ + +#define MXC_F_TPU_CRC_CTRL_PRNG_POS 2 /**< CRC_CTRL_PRNG Position */ +#define MXC_F_TPU_CRC_CTRL_PRNG ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_PRNG_POS)) /**< CRC_CTRL_PRNG Mask */ + +#define MXC_F_TPU_CRC_CTRL_ENT_POS 3 /**< CRC_CTRL_ENT Position */ +#define MXC_F_TPU_CRC_CTRL_ENT ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_ENT_POS)) /**< CRC_CTRL_ENT Mask */ + +#define MXC_F_TPU_CRC_CTRL_HAM_POS 4 /**< CRC_CTRL_HAM Position */ +#define MXC_F_TPU_CRC_CTRL_HAM ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_HAM_POS)) /**< CRC_CTRL_HAM Mask */ + +#define MXC_F_TPU_CRC_CTRL_HRST_POS 5 /**< CRC_CTRL_HRST Position */ +#define MXC_F_TPU_CRC_CTRL_HRST ((uint32_t)(0x1UL << MXC_F_TPU_CRC_CTRL_HRST_POS)) /**< CRC_CTRL_HRST Mask */ + +/**@} end of group CRC_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_SRC_Register + * @brief Crypto DMA Source Address. + * @{ + */ +#define MXC_F_TPU_DMA_SRC_ADDR_POS 0 /**< DMA_SRC_ADDR Position */ +#define MXC_F_TPU_DMA_SRC_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_SRC_ADDR_POS)) /**< DMA_SRC_ADDR Mask */ + +/**@} end of group DMA_SRC_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_DEST_Register + * @brief Crypto DMA Destination Address. + * @{ + */ +#define MXC_F_TPU_DMA_DEST_ADDR_POS 0 /**< DMA_DEST_ADDR Position */ +#define MXC_F_TPU_DMA_DEST_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_DEST_ADDR_POS)) /**< DMA_DEST_ADDR Mask */ + +/**@} end of group DMA_DEST_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DMA_CNT_Register + * @brief Crypto DMA Byte Count. + * @{ + */ +#define MXC_F_TPU_DMA_CNT_ADDR_POS 0 /**< DMA_CNT_ADDR Position */ +#define MXC_F_TPU_DMA_CNT_ADDR ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DMA_CNT_ADDR_POS)) /**< DMA_CNT_ADDR Mask */ + +/**@} end of group DMA_CNT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup MAA_CTRL_Register + * @brief MAA Control Register. + * @{ + */ +#define MXC_F_TPU_MAA_CTRL_STC_POS 0 /**< MAA_CTRL_STC Position */ +#define MXC_F_TPU_MAA_CTRL_STC ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_STC_POS)) /**< MAA_CTRL_STC Mask */ + +#define MXC_F_TPU_MAA_CTRL_CLC_POS 1 /**< MAA_CTRL_CLC Position */ +#define MXC_F_TPU_MAA_CTRL_CLC ((uint32_t)(0x7UL << MXC_F_TPU_MAA_CTRL_CLC_POS)) /**< MAA_CTRL_CLC Mask */ +#define MXC_V_TPU_MAA_CTRL_CLC_EXP ((uint32_t)0x0UL) /**< MAA_CTRL_CLC_EXP Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_EXP \ + (MXC_V_TPU_MAA_CTRL_CLC_EXP << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_EXP Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SQ ((uint32_t)0x1UL) /**< MAA_CTRL_CLC_SQ Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SQ \ + (MXC_V_TPU_MAA_CTRL_CLC_SQ << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SQ Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_MUL ((uint32_t)0x2UL) /**< MAA_CTRL_CLC_MUL Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_MUL \ + (MXC_V_TPU_MAA_CTRL_CLC_MUL << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_MUL Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SQMUL ((uint32_t)0x3UL) /**< MAA_CTRL_CLC_SQMUL Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SQMUL \ + (MXC_V_TPU_MAA_CTRL_CLC_SQMUL << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SQMUL Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_ADD ((uint32_t)0x4UL) /**< MAA_CTRL_CLC_ADD Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_ADD \ + (MXC_V_TPU_MAA_CTRL_CLC_ADD << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_ADD Setting */ +#define MXC_V_TPU_MAA_CTRL_CLC_SUB ((uint32_t)0x5UL) /**< MAA_CTRL_CLC_SUB Value */ +#define MXC_S_TPU_MAA_CTRL_CLC_SUB \ + (MXC_V_TPU_MAA_CTRL_CLC_SUB << MXC_F_TPU_MAA_CTRL_CLC_POS) /**< MAA_CTRL_CLC_SUB Setting */ + +#define MXC_F_TPU_MAA_CTRL_OCALC_POS 4 /**< MAA_CTRL_OCALC Position */ +#define MXC_F_TPU_MAA_CTRL_OCALC ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_OCALC_POS)) /**< MAA_CTRL_OCALC Mask */ + +#define MXC_F_TPU_MAA_CTRL_MAAER_POS 7 /**< MAA_CTRL_MAAER Position */ +#define MXC_F_TPU_MAA_CTRL_MAAER ((uint32_t)(0x1UL << MXC_F_TPU_MAA_CTRL_MAAER_POS)) /**< MAA_CTRL_MAAER Mask */ + +#define MXC_F_TPU_MAA_CTRL_AMS_POS 8 /**< MAA_CTRL_AMS Position */ +#define MXC_F_TPU_MAA_CTRL_AMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_AMS_POS)) /**< MAA_CTRL_AMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_BMS_POS 10 /**< MAA_CTRL_BMS Position */ +#define MXC_F_TPU_MAA_CTRL_BMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_BMS_POS)) /**< MAA_CTRL_BMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_EMS_POS 12 /**< MAA_CTRL_EMS Position */ +#define MXC_F_TPU_MAA_CTRL_EMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_EMS_POS)) /**< MAA_CTRL_EMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_MMS_POS 14 /**< MAA_CTRL_MMS Position */ +#define MXC_F_TPU_MAA_CTRL_MMS ((uint32_t)(0x3UL << MXC_F_TPU_MAA_CTRL_MMS_POS)) /**< MAA_CTRL_MMS Mask */ + +#define MXC_F_TPU_MAA_CTRL_AMA_POS 16 /**< MAA_CTRL_AMA Position */ +#define MXC_F_TPU_MAA_CTRL_AMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_AMA_POS)) /**< MAA_CTRL_AMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_BMA_POS 20 /**< MAA_CTRL_BMA Position */ +#define MXC_F_TPU_MAA_CTRL_BMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_BMA_POS)) /**< MAA_CTRL_BMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_RMA_POS 24 /**< MAA_CTRL_RMA Position */ +#define MXC_F_TPU_MAA_CTRL_RMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_RMA_POS)) /**< MAA_CTRL_RMA Mask */ + +#define MXC_F_TPU_MAA_CTRL_TMA_POS 28 /**< MAA_CTRL_TMA Position */ +#define MXC_F_TPU_MAA_CTRL_TMA ((uint32_t)(0xFUL << MXC_F_TPU_MAA_CTRL_TMA_POS)) /**< MAA_CTRL_TMA Mask */ + +/**@} end of group MAA_CTRL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DIN_Register + * @brief Crypto Data Input. Data input can be written to this register instead of using + * the DMA. This register writes to the FIFO. This register occupies four + * successive words to allow the use of multi-store instructions. Words can be + * written to any location, they will be placed in the FIFO in the order they are + * written. The endian swap input control bit affects this register. + * @{ + */ +#define MXC_F_TPU_DIN_DATA_POS 0 /**< DIN_DATA Position */ +#define MXC_F_TPU_DIN_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DIN_DATA_POS)) /**< DIN_DATA Mask */ + +/**@} end of group DIN_Register */ + +/** + * @ingroup tpu_registers + * @defgroup DOUT_Register + * @brief Crypto Data Output. Resulting data from cipher calculation. Data is placed in + * the lower words of these four registers depending on the algorithm. For block + * cipher modes, this register holds the result of most recent encryption or + * decryption operation. These registers are affected by the endian swap bits. + * @{ + */ +#define MXC_F_TPU_DOUT_DATA_POS 0 /**< DOUT_DATA Position */ +#define MXC_F_TPU_DOUT_DATA ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_DOUT_DATA_POS)) /**< DOUT_DATA Mask */ + +/**@} end of group DOUT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_POLY_Register + * @brief CRC Polynomial. The polynomial to be used for Galois Field calculations (CRC or + * LFSR) should be written to this register. This register is affected by the MSB + * control bit. + * @{ + */ +#define MXC_F_TPU_CRC_POLY_POLY_POS 0 /**< CRC_POLY_POLY Position */ +#define MXC_F_TPU_CRC_POLY_POLY ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_POLY_POLY_POS)) /**< CRC_POLY_POLY Mask */ + +/**@} end of group CRC_POLY_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_VAL_Register + * @brief CRC Value. This is the state for the Galois Field. This register holds the + * result of a CRC calculation or the current state of the LFSR. This register is + * affected by the MSB control bit. + * @{ + */ +#define MXC_F_TPU_CRC_VAL_VAL_POS 0 /**< CRC_VAL_VAL Position */ +#define MXC_F_TPU_CRC_VAL_VAL ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_VAL_VAL_POS)) /**< CRC_VAL_VAL Mask */ + +/**@} end of group CRC_VAL_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CRC_PRNG_Register + * @brief Pseudo Random Value. Output of the Galois Field shift register. This holds the + * resulting pseudo-random number if entropy is disabled or true random number if + * entropy is enabled. + * @{ + */ +#define MXC_F_TPU_CRC_PRNG_PRNG_POS 0 /**< CRC_PRNG_PRNG Position */ +#define MXC_F_TPU_CRC_PRNG_PRNG ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CRC_PRNG_PRNG_POS)) /**< CRC_PRNG_PRNG Mask */ + +/**@} end of group CRC_PRNG_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HAM_ECC_Register + * @brief Hamming ECC Register. + * @{ + */ +#define MXC_F_TPU_HAM_ECC_ECC_POS 0 /**< HAM_ECC_ECC Position */ +#define MXC_F_TPU_HAM_ECC_ECC ((uint32_t)(0xFFFFUL << MXC_F_TPU_HAM_ECC_ECC_POS)) /**< HAM_ECC_ECC Mask */ + +#define MXC_F_TPU_HAM_ECC_PAR_POS 16 /**< HAM_ECC_PAR Position */ +#define MXC_F_TPU_HAM_ECC_PAR ((uint32_t)(0x1UL << MXC_F_TPU_HAM_ECC_PAR_POS)) /**< HAM_ECC_PAR Mask */ + +/**@} end of group HAM_ECC_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_INIT_Register + * @brief Initial Vector. For block cipher operations that use CBC, CFB, OFB, or CNTR + * modes, this register holds the initial value. This register is updated with each + * encryption or decryption operation. This register is affected by the endian swap + * bits. + * @{ + */ +#define MXC_F_TPU_CIPHER_INIT_IVEC_POS 0 /**< CIPHER_INIT_IVEC Position */ +#define MXC_F_TPU_CIPHER_INIT_IVEC \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CIPHER_INIT_IVEC_POS)) /**< CIPHER_INIT_IVEC Mask */ + +/**@} end of group CIPHER_INIT_Register */ + +/** + * @ingroup tpu_registers + * @defgroup CIPHER_KEY_Register + * @brief Cipher Key. This register holds the key used for block cipher operations. The + * lower words are used for block ciphers that use shorter key lengths. This + * register is affected by the endian swap input control bits. + * @{ + */ +#define MXC_F_TPU_CIPHER_KEY_KEY_POS 0 /**< CIPHER_KEY_KEY Position */ +#define MXC_F_TPU_CIPHER_KEY_KEY \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_CIPHER_KEY_KEY_POS)) /**< CIPHER_KEY_KEY Mask \ + */ + +/**@} end of group CIPHER_KEY_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_DIGEST_Register + * @brief This register holds the calculated hash value. This register is affected by the + * endian swap bits. + * @{ + */ +#define MXC_F_TPU_HASH_DIGEST_HASH_POS 0 /**< HASH_DIGEST_HASH Position */ +#define MXC_F_TPU_HASH_DIGEST_HASH \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_HASH_DIGEST_HASH_POS)) /**< HASH_DIGEST_HASH Mask */ + +/**@} end of group HASH_DIGEST_Register */ + +/** + * @ingroup tpu_registers + * @defgroup HASH_MSG_SZ_Register + * @brief Message Size. This register holds the lowest 32-bit of message size in bytes. + * @{ + */ +#define MXC_F_TPU_HASH_MSG_SZ_MSGSZ_POS 0 /**< HASH_MSG_SZ_MSGSZ Position */ +#define MXC_F_TPU_HASH_MSG_SZ_MSGSZ \ + ((uint32_t)(0xFFFFFFFFUL << MXC_F_TPU_HASH_MSG_SZ_MSGSZ_POS)) /**< HASH_MSG_SZ_MSGSZ Mask */ + +/**@} end of group HASH_MSG_SZ_Register */ + +/** + * @ingroup tpu_registers + * @defgroup MAA_MAWS_Register + * @brief MAA Word Size. This register defines the number of bits for a modular operation. + * This register must be set to a valid value prior to the MAA operation start. + * Valid values are from 1 to 2048. Invalid values are ignored and will not + * initiate a MAA operation. + * @{ + */ +#define MXC_F_TPU_MAA_MAWS_MAWS_POS 0 /**< MAA_MAWS_MAWS Position */ +#define MXC_F_TPU_MAA_MAWS_MAWS ((uint32_t)(0xFFFUL << MXC_F_TPU_MAA_MAWS_MAWS_POS)) /**< MAA_MAWS_MAWS Mask */ + +/**@} end of group MAA_MAWS_Register */ + +#ifdef __cplusplus +} +#endif + +#endif /* _TPU_REGS_H_ */ diff --git a/contrib/loaders/flash/msp432/driverlib.c b/contrib/loaders/flash/msp432/driverlib.c index 6f483b83da..b897755d16 100644 --- a/contrib/loaders/flash/msp432/driverlib.c +++ b/contrib/loaders/flash/msp432/driverlib.c @@ -67,20 +67,20 @@ static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level, reg_value = PCM->CTL0; switch (pcm_get_power_state()) { - case PCM_AM_LF_VCORE1: - case PCM_AM_DCDC_VCORE1: - case PCM_AM_LDO_VCORE0: - PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LF_VCORE0: - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LDO_VCORE1: - PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - default: - break; + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LDO_VCORE0: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LDO_VCORE1: + PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0) + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + default: + break; } if (blocking) { @@ -117,22 +117,22 @@ uint8_t pcm_get_power_mode(void) current_power_state = pcm_get_power_state(); switch (current_power_state) { - case PCM_AM_LDO_VCORE0: - case PCM_AM_LDO_VCORE1: - case PCM_LPM0_LDO_VCORE0: - case PCM_LPM0_LDO_VCORE1: - default: - return PCM_LDO_MODE; - case PCM_AM_DCDC_VCORE0: - case PCM_AM_DCDC_VCORE1: - case PCM_LPM0_DCDC_VCORE0: - case PCM_LPM0_DCDC_VCORE1: - return PCM_DCDC_MODE; - case PCM_LPM0_LF_VCORE0: - case PCM_LPM0_LF_VCORE1: - case PCM_AM_LF_VCORE1: - case PCM_AM_LF_VCORE0: - return PCM_LF_MODE; + case PCM_AM_DCDC_VCORE0: + case PCM_AM_DCDC_VCORE1: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_DCDC_VCORE1: + return PCM_DCDC_MODE; + case PCM_LPM0_LF_VCORE0: + case PCM_LPM0_LF_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_AM_LF_VCORE0: + return PCM_LF_MODE; + case PCM_AM_LDO_VCORE0: + case PCM_AM_LDO_VCORE1: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_LDO_VCORE1: + default: + return PCM_LDO_MODE; } } @@ -141,23 +141,23 @@ uint8_t pcm_get_core_voltage_level(void) uint8_t current_power_state = pcm_get_power_state(); switch (current_power_state) { - case PCM_AM_LDO_VCORE0: - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LF_VCORE0: - case PCM_LPM0_LDO_VCORE0: - case PCM_LPM0_DCDC_VCORE0: - case PCM_LPM0_LF_VCORE0: - default: - return PCM_VCORE0; - case PCM_AM_LDO_VCORE1: - case PCM_AM_DCDC_VCORE1: - case PCM_AM_LF_VCORE1: - case PCM_LPM0_LDO_VCORE1: - case PCM_LPM0_DCDC_VCORE1: - case PCM_LPM0_LF_VCORE1: - return PCM_VCORE1; - case PCM_LPM3: - return PCM_VCORELPM3; + case PCM_AM_LDO_VCORE1: + case PCM_AM_DCDC_VCORE1: + case PCM_AM_LF_VCORE1: + case PCM_LPM0_LDO_VCORE1: + case PCM_LPM0_DCDC_VCORE1: + case PCM_LPM0_LF_VCORE1: + return PCM_VCORE1; + case PCM_LPM3: + return PCM_VCORELPM3; + case PCM_AM_LDO_VCORE0: + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + case PCM_LPM0_LDO_VCORE0: + case PCM_LPM0_DCDC_VCORE0: + case PCM_LPM0_LF_VCORE0: + default: + return PCM_VCORE0; } } @@ -186,44 +186,44 @@ static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, reg_value = PCM->CTL0; switch (current_power_state) { - case PCM_AM_DCDC_VCORE0: - case PCM_AM_LF_VCORE0: - PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LF_VCORE1: - case PCM_AM_DCDC_VCORE1: - PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); - break; - case PCM_AM_LDO_VCORE1: { - if (power_mode == PCM_DCDC_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else if (power_mode == PCM_LF_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else - return false; - break; + case PCM_AM_DCDC_VCORE0: + case PCM_AM_LF_VCORE0: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LF_VCORE1: + case PCM_AM_DCDC_VCORE1: + PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK))); + break; + case PCM_AM_LDO_VCORE1: + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else { + return false; } - case PCM_AM_LDO_VCORE0: { - if (power_mode == PCM_DCDC_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else if (power_mode == PCM_LF_MODE) { - PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 - | (reg_value & ~(PCM_CTL0_KEY_MASK - | PCM_CTL0_AMR_MASK))); - } else - return false; - break; + break; + case PCM_AM_LDO_VCORE0: + if (power_mode == PCM_DCDC_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else if (power_mode == PCM_LF_MODE) { + PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0 + | (reg_value & ~(PCM_CTL0_KEY_MASK + | PCM_CTL0_AMR_MASK))); + } else { + return false; } - default: - break; + break; + default: + break; } if (blocking) { @@ -231,8 +231,9 @@ static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode, if (bool_timeout && !(--time_out)) return false; } - } else + } else { return true; + } current_power_mode = pcm_get_power_mode(); current_power_state = pcm_get_power_state(); @@ -256,76 +257,76 @@ static bool __pcm_set_power_state_advanced(uint_fast8_t power_state, return true; switch (power_state) { - case PCM_AM_LDO_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking); - case PCM_AM_LDO_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking); - case PCM_AM_DCDC_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking); - case PCM_AM_DCDC_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking); - case PCM_AM_LF_VCORE0: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking); - case PCM_AM_LF_VCORE1: - return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking); - case PCM_LPM0_LDO_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LDO_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_DCDC_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_DCDC_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LF_VCORE0: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM0_LF_VCORE1: - if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, - blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, - timeout, blocking)) - break; - return pcm_goto_lpm0(); - case PCM_LPM3: - return pcm_goto_lpm3(); - case PCM_LPM4: - return pcm_goto_lpm4(); - case PCM_LPM45: - return pcm_shutdown_device(PCM_LPM45); - case PCM_LPM35_VCORE0: - return pcm_shutdown_device(PCM_LPM35_VCORE0); - default: - return false; + case PCM_AM_LDO_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_LDO_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_DCDC_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE0: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_AM_LF_VCORE1: + return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking); + case PCM_LPM0_LDO_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LDO_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_DCDC_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE0: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM0_LF_VCORE1: + if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout, + blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE, + timeout, blocking)) + break; + return pcm_goto_lpm0(); + case PCM_LPM3: + return pcm_goto_lpm3(); + case PCM_LPM4: + return pcm_goto_lpm4(); + case PCM_LPM45: + return pcm_shutdown_device(PCM_LPM45); + case PCM_LPM35_VCORE0: + return pcm_shutdown_device(PCM_LPM35_VCORE0); + default: + return false; } return false; diff --git a/contrib/loaders/flash/msp432/main_msp432e4x.c b/contrib/loaders/flash/msp432/main_msp432e4x.c index 7974f48c77..7c9cf468df 100644 --- a/contrib/loaders/flash/msp432/main_msp432e4x.c +++ b/contrib/loaders/flash/msp432/main_msp432e4x.c @@ -30,37 +30,37 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/contrib/loaders/flash/msp432/main_msp432p401x.c b/contrib/loaders/flash/msp432/main_msp432p401x.c index 47fb7fa476..024d047224 100644 --- a/contrib/loaders/flash/msp432/main_msp432p401x.c +++ b/contrib/loaders/flash/msp432/main_msp432p401x.c @@ -49,41 +49,41 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/contrib/loaders/flash/msp432/main_msp432p411x.c b/contrib/loaders/flash/msp432/main_msp432p411x.c index efc05a3b78..391057f2e5 100644 --- a/contrib/loaders/flash/msp432/main_msp432p411x.c +++ b/contrib/loaders/flash/msp432/main_msp432p411x.c @@ -52,41 +52,41 @@ int main(void) while (1) { switch (FLASH_LOADER->FLASH_FUNCTION) { - case FLASH_INIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_init(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_MASS_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_mass_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_SECTOR_ERASE: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_sector_erase(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_CONTINUOUS_PROGRAM: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_continous_write(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_EXIT: - FLASH_LOADER->RETURN_CODE = FLASH_BUSY; - msp432_flash_exit(); - FLASH_LOADER->FLASH_FUNCTION = 0; - break; - case FLASH_NO_COMMAND: - break; - default: - FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; - break; + case FLASH_INIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_init(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_MASS_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_mass_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_SECTOR_ERASE: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_sector_erase(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_CONTINUOUS_PROGRAM: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_continous_write(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_EXIT: + FLASH_LOADER->RETURN_CODE = FLASH_BUSY; + msp432_flash_exit(); + FLASH_LOADER->FLASH_FUNCTION = 0; + break; + case FLASH_NO_COMMAND: + break; + default: + FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND; + break; } } } diff --git a/doc/fdl.texi b/doc/fdl.texi index 2189f80a66..72916a9fb7 100644 --- a/doc/fdl.texi +++ b/doc/fdl.texi @@ -7,7 +7,7 @@ @display Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. -51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/doc/manual/helper.txt b/doc/manual/helper.txt index 6cf3c977bf..29e84e6f0b 100644 --- a/doc/manual/helper.txt +++ b/doc/manual/helper.txt @@ -97,18 +97,6 @@ registration, while the @c unregister_command() and These may be called at any time, allowing the command set to change in response to system actions. -@subsection helpercmdjim Jim Command Registration - -The command_registration structure provides support for registering -native Jim command handlers (@c jim_handler) too. For these handlers, -the module can provide help and usage support; however, this mechanism -allows Jim handlers to be called as sub-commands of other commands. -These commands may be registered with a private data value (@c -jim_handler_data) that will be available when called, as with low-level -Jim command registration. - -A command may have a normal @c handler or a @c jim_handler, but not both. - @subsection helpercmdregisterchains Command Chaining When using register_commands(), the array of commands may reference diff --git a/doc/manual/primer/docs.txt b/doc/manual/primer/docs.txt index 1aefa17e6d..ccf4550d51 100644 --- a/doc/manual/primer/docs.txt +++ b/doc/manual/primer/docs.txt @@ -16,7 +16,6 @@ OpenOCD presently produces several kinds of documentation: - Provides overview, usage, reference, and FAQ for each device. - Written using LaTeX language with custom macros. - Created with 'make references'. - - See @subpage primerlatex and @ref stylelatex. - The Manual: - Focuses on developing the OpenOCD software. - Details the architecture, driver interfaces, and processes. @@ -44,19 +43,6 @@ the Texinfo web site for the Texinfo manual and more information. OpenOCD style guidelines for Texinfo documentation can be found on the @ref styletexinfo page. - */ -/** @page primerlatex LaTeX Primer - -The OpenOCD project provides a number of reference guides using the -LaTeX typesetting language. - -- OpenOCD Quick Reference Sheets -- OpenOCD Hardware Reference Guides - -These documents have not yet been produced, so this Primer serves as -a placeholder to describe how they are created and can be extended. -The same holds true for the @ref stylelatex page. - */ /** @page primerdoxygen Doxygen Primer @@ -118,7 +104,6 @@ This file contains the Doxygen source code for the @ref primerdocs. The @ref primerdocs page also contains the following sections: - @ref primertexinfo -- @ref primerlatex - @ref primerdoxygen */ diff --git a/doc/manual/server.txt b/doc/manual/server.txt index 20e48c1f43..3c31e6fc62 100644 --- a/doc/manual/server.txt +++ b/doc/manual/server.txt @@ -190,7 +190,6 @@ Remember: OpenOCD runs on: -# FreeBSD -# Cygwin -# MinGW32 --# Ecos How can we get that to work? diff --git a/doc/manual/style.txt b/doc/manual/style.txt index f7a12988fc..fa08f4de96 100644 --- a/doc/manual/style.txt +++ b/doc/manual/style.txt @@ -22,7 +22,6 @@ providing documentation, either as part of the C code or stand-alone. - @subpage styledoxygen - @subpage styletexinfo -- @subpage stylelatex Feedback would be welcome to improve the OpenOCD guidelines. @@ -449,13 +448,6 @@ be as productive as possible. Needing to look at OpenOCD source code, to figure out how to use it is a bad sign, though it's OK to need to look at the User's guide to figure out what a config script is doing. - */ -/** @page stylelatex LaTeX Style Guide - -This page needs to provide style guidelines for using LaTeX, the -typesetting language used by The References for OpenOCD Hardware. -Likewise, the @ref primerlatex for using this guide needs to be completed. - */ /** @page styleperl Perl Style Guide @@ -510,7 +502,6 @@ documentation languages: - @ref stylec - @ref styledoxygen - @ref styletexinfo -- @ref stylelatex - @ref styleperl - @ref styleautotools diff --git a/doc/openocd.texi b/doc/openocd.texi index 6d9c198abc..e15188cf79 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -529,9 +529,8 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @section IBM PC Parallel Printer Port Based -The two well-known ``JTAG Parallel Ports'' cables are the Xilinx DLC5 -and the Macraigor Wiggler. There are many clones and variations of -these on the market. +The two well-known JTAG parallel port cables are the Xilinx DLC5 and the Macraigor Wiggler. +There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor @@ -553,7 +552,7 @@ produced, PDF schematics are easily found and it is easy to make. @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} -@* Yet another variation - See the source code, src/jtag/parport.c +@* Yet another variation, see configuration in @file{interface/parport/wiggler-ntrst-inverted.cfg} @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @@ -613,6 +612,12 @@ emulation model of target hardware. @item @b{xlnx_pcie_xvc} @* A JTAG driver exposing Xilinx Virtual Cable over PCI Express to OpenOCD as JTAG/SWD interface. +@* Link: @url{https://www.xilinx.com/products/intellectual-property/debug-bridge.html} + +@item @b{xlnx_axi_xvc} +@* A JTAG driver exposing JTAG to OpenOCD over AXI-mapped registers. +@* Link: @url{https://docs.amd.com/r/en-US/pg437-axi-jtag/Introduction} +@* Link: @url{https://china.xilinx.com/support/documentation/application_notes/xapp1251-xvc-zynq-petalinux.pdf} @item @b{linuxspidev} @* A SPI based SWD driver using Linux SPI devices. @@ -627,6 +632,10 @@ This is deprecated from Linux v5.3; prefer using @b{linuxgpiod}. @item @b{esp_usb_jtag} @* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3 and ESP32-S3 chips using OpenOCD. +@item @b{ch347} +@* A JTAG driver that works with the WCH CH347F and CH347T chips. +When using the CH347T, it must be configured to operate in mode 3 (UART + JTAG). + @end itemize @node About Jim Tcl @@ -804,8 +813,7 @@ itself), use the @option{-d} command line switch. This sets the @option{debug_level} to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this -setting from within a telnet or gdb session using @command{debug_level} -(@pxref{debuglevel,,debug_level}). +setting from within a telnet or gdb session using @ref{debuglevel,,@command{debug_level}}. You can redirect all output from the server to a file using the @option{-l } switch. @@ -1382,11 +1390,11 @@ Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. -@deffn {Command} {find} 'filename' +@deffn {Command} {find} filename Prints full path to @var{filename} according to OpenOCD search rules. @end deffn -@deffn {Command} {ocd_find} 'filename' +@deffn {Command} {ocd_find} filename Prints full path to @var{filename} according to OpenOCD search rules. This is a low level function used by the @command{find}. Usually you want to use @command{find}, instead. @@ -1432,7 +1440,6 @@ In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. -The full Tcl/Tk language supports ``namespaces'', but Jim Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. @@ -2431,13 +2438,14 @@ dict get [adapter list] ftdi @deffn {Config Command} {adapter gpio [ @ @option{tdo} | @option{tdi} | @option{tms} | @option{tck} | @option{trst} | @ @option{swdio} | @option{swdio_dir} | @option{swclk} | @option{srst} | @ - @option{led} @ + @option{led} | @option{user0} @ [ @ gpio_number | @option{-chip} chip_number | @ @option{-active-high} | @option{-active-low} | @ @option{-push-pull} | @option{-open-drain} | @option{-open-source} | @ @option{-pull-none} | @option{-pull-up} | @option{-pull-down} | @ @option{-init-inactive} | @option{-init-active} | @option{-init-input} @ + @option{-exit-inactive} | @option{-exit-active} | @option{-exit-input} | @option{-exit-no-change} @ ] ]} Define the GPIO mapping that the adapter will use. The following signals can be @@ -2450,6 +2458,7 @@ JTAG transport signals @item @option{swdio_dir}: optional swdio buffer control signal @item @option{srst}: system reset signal @item @option{led}: optional activity led +@item @option{user0}: optional, user-specific signal @end itemize @@ -2472,11 +2481,14 @@ equivalent to issuing the single command @command{gpio led 7 -chip 1 signals which are inputs. The drive mode for the srst and trst signals must be set with the @command{adapter reset_config} command. It is not permissible to set the initial state of swdio_dir as it is derived from the initial state of -swdio. The command @command{adapter gpio} prints the current configuration for -all GPIOs while the command @command{adapter gpio gpio_name} prints the current -configuration for gpio_name. Not all adapters support this generic GPIO mapping, -some require their own commands to define the GPIOs used. Adapters that support -the generic mapping may not support all of the listed options. +swdio. Accordingly, the final state before the adapter terminates its operation, +so-called “exit state”, can be set. By default the state and configuration of an +output pin is not changed when the driver terminates its operation. The +command @command{adapter gpio} prints the current configuration for all GPIOs +while the command @command{adapter gpio gpio_name} prints the current configuration +for gpio_name. Not all adapters support this generic GPIO mapping, some require +their own commands to define the GPIOs used. Adapters that support the generic +mapping may not support all of the listed options. @end deffn @deffn {Command} {adapter name} @@ -2499,6 +2511,9 @@ If this command is not specified, serial strings are not checked. Only the following adapter drivers use the serial string from this command: arm-jtag-ew, cmsis_dap, esp_usb_jtag, ft232r, ftdi, hla (stlink, ti-icdi), jlink, kitprog, opendus, openjtag, osbdm, presto, rlink, st-link, usb_blaster (ublast2), usbprog, vsllink, xds110. + +For jlink adapters, the @var{serial_string} is also compared +against the adapter's nickname. @end deffn @section Interface Drivers @@ -2508,6 +2523,8 @@ enabled when OpenOCD is configured, in order to be made available at run time. @deffn {Interface Driver} {amt_jtagaccel} +@b{Note: This adapter is deprecated and support will be removed in the next release!} + Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: @@ -2544,9 +2561,62 @@ and a specific set of GPIOs is used. @c chooses among list of bit configs ... only one option @end deffn +@deffn {Interface Driver} {ch347} +Driver for WCH CH347F and CH347T chips. +When using the CH347T, it must be configured to operate in mode 3 (UART + JTAG). + +@b{WARNING:} WCH CH347T chips have rather poor performance +with respect to the USB HS connection. Upgrade firmware to the latest version! +@itemize @bullet +@item Chip version 2.41: +@itemize @minus +@item JTAG timing is very weird, some clock pulses are +much shorter then the requested clock frequency. +@item SWD is not implemented. +@end itemize +@item Chip version 4.41: +@itemize @minus +@item SWD clock is limited to 1 MHz maximum. +@item SWD reading AP reg CH347 erroneously drives +SWDIO to H for 392 ns after the last ACK bit. Some devices get so upset +that send wrong data with parity error. A resistor in the SWDIO circuit +mitigates the problem. +@item A long SWD operation causes that USB host disconnects the adapter. +@end itemize +@item Chip version 5.44: +@itemize @minus +@item Maximal SWD clock speed is 5 MHz +@item A long SWD operation causes that USB host disconnects the adapter. +@end itemize +@end itemize + +The driver supports activity LED through the generic +command @ref{adapter gpio, @command{adapter gpio led}}. + +This driver has these driver-specific command: + +@deffn {Config Command} {ch347 vid_pid} [vid pid]+ +The vendor ID and product ID of the CH347F or CH347T device in mode 3. If not specified +the driver will use vendor ID 0x1a86 and product ID 0x55dd. +Currently, up to four [@var{vid}, @var{pid}] pairs may be given, e.g. +@example +ch347 vid_pid 0x1a86 0x55dd 0x1a86 0x55de +@end example +@end deffn + +@deffn {Config Command} {ch347 device_desc} description +If specified connect to a device which exactly has this product description +string. If not specified the first found device with the correct vendor +and product ID will be connected. +@example +ch347 device_desc "EasyDevKit" +@end example +@end deffn +@end deffn + @deffn {Interface Driver} {cmsis-dap} ARM CMSIS-DAP compliant based adapter v1 (USB HID based) -or v2 (USB bulk). +or v2 (USB bulk or TCP/IP). @deffn {Config Command} {cmsis-dap vid_pid} [vid pid]+ The vendor ID and product ID of the CMSIS-DAP device. If not specified @@ -2557,23 +2627,56 @@ cmsis-dap vid_pid 0xc251 0xf001 0x0d28 0x0204 @end example @end deffn -@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}] +@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}|@option{tcp}] Specifies how to communicate with the adapter: @itemize @minus -@item @option{hid} Use HID generic reports - CMSIS-DAP v1 +@item @option{hid} Use USB HID generic reports - CMSIS-DAP v1 @item @option{usb_bulk} Use USB bulk - CMSIS-DAP v2 -@item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try HID CMSIS-DAP v1. -This is the default if @command{cmsis-dap backend} is not specified. +@item @option{tcp} Use TCP/IP instead of USB +@item @option{auto} First try USB bulk CMSIS-DAP v2, if not found try USB HID +CMSIS-DAP v1, if not found try TCP (if @command{cmsis-dap tcp host} is +configured). This is the default if @command{cmsis-dap backend} is not +specified. @end itemize @end deffn -@deffn {Config Command} {cmsis-dap usb interface} [number] +@deffn {Config Command} {cmsis-dap usb interface} number Specifies the @var{number} of the USB interface to use in v2 mode (USB bulk). In most cases need not to be specified and interfaces are searched by interface string or for user class interface. @end deffn +@deffn {Config Command} {cmsis-dap tcp host} hostname +Specifies the @var{hostname} or IP address of the remote programmer. For use +with 'tcp' backend only. +@example +cmsis-dap backend tcp +cmsis-dap tcp host 192.168.1.4 +@end example +@end deffn + +@deffn {Config Command} {cmsis-dap tcp port} port +Specifies the TCP @var{port} number used by the remote programmer for DAP +commands. The default port is 4441. For use with 'tcp' backend only. +@example +cmsis-dap backend tcp +cmsis-dap tcp host 192.168.1.4 +cmsis-dap tcp port 4441 +@end example +@end deffn + +@deffn {Config Command} {cmsis-dap tcp min_timeout} milliseconds +Sets a lower bound on the requested timeout in @var{milliseconds} to wait for +response packets from the remote programmer when using the 'tcp' backend. The +user may want to use a larger value on slower networks, to avoid getting +command mismatch errors. Default value is 150 milliseconds. For use with 'tcp' +backend only. +@example +cmsis-dap tcp min_timeout 200 +@end example +@end deffn + @deffn {Command} {cmsis-dap quirk} [@option{enable}|@option{disable}] Enables or disables the following workarounds of known CMSIS-DAP adapter quirks: @@ -2956,6 +3059,8 @@ image. To be used with USB-Blaster II only. @end deffn @deffn {Interface Driver} {gw16012} +@b{Note: This adapter is deprecated and support will be removed in the next release!} + Gateworks GW16012 JTAG programmer. This has one driver-specific command: @@ -3107,61 +3212,66 @@ version, and target voltage. @end deffn @deffn {Interface Driver} {parport} -Supports PC parallel port bit-banging cables: -Wigglers, PLD download cable, and more. -These interfaces have several commands, used to configure the driver -before initializing the JTAG scan chain: - -@deffn {Config Command} {parport cable} name -Set the layout of the parallel port cable used to connect to the target. -This is a write-once setting. -Currently valid cable @var{name} values include: -@itemize @minus -@item @b{altium} Altium Universal JTAG cable. -@item @b{arm-jtag} Same as original wiggler except SRST and -TRST connections reversed and TRST is also inverted. -@item @b{chameleon} The Amontec Chameleon's CPLD when operated -in configuration mode. This is only used to -program the Chameleon itself, not a connected target. -@item @b{dlc5} The Xilinx Parallel cable III. -@item @b{flashlink} The ST Parallel cable. -@item @b{lattice} Lattice ispDOWNLOAD Cable -@item @b{old_amt_wiggler} The Wiggler configuration that comes with -some versions of -Amontec's Chameleon Programmer. The new version available from -the website uses the original Wiggler layout ('@var{wiggler}') -@item @b{triton} The parallel port adapter found on the -``Karo Triton 1 Development Board''. -This is also the layout used by the HollyGates design -(see @uref{http://www.lartmaker.nl/projects/jtag/}). -@item @b{wiggler} The original Wiggler layout, also supported by -several clones, such as the Olimex ARM-JTAG -@item @b{wiggler2} Same as original wiggler except an led is fitted on D5. -@item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. -@end itemize +This driver supports PC parallel port bit-banging adapters. +Only JTAG is supported as transport protocol. +The driver supports Linux, FreeBSD, and Windows. +However, the Windows support is untested and unmaintained. + +The pin configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}. +In addition to the JTAG signals, the driver also supports the activity LED signal. + +The data and status pins of the parallel port are used as output and input pins, respectively. +The pin direction is given in the following table. + +@multitable @columnfractions .2 .1 .1 .1 .1 .1 .1 .1 .1 +@headitem Pin direction +@item Input +@tab ~11 +@tab 10 +@tab 12 +@tab 13 +@tab 15 +@tab - +@tab - +@tab - +@item Output +@tab 9 +@tab 8 +@tab 7 +@tab 6 +@tab 5 +@tab 4 +@tab 3 +@tab 2 +@end multitable + +@deffn {Config Command} {parport port} file +Specify the device file of the parallel port device. +The parallel port device file is usually @file{/dev/parportX} on Linux and @file{/dev/ppiX} on FreeBSD. + +For legacy reason, the port number @var{X} can be specified instead of the device file. +@b{Note:} Using the port number is a deprecated feature and will be removed in the future. + +When using direct I/O, the number is the I/O port number. +The default port number is 0x378 (LTP1). +@b{Note:} Direct I/O support is deprecated and will be removed in the future. @end deffn -@deffn {Config Command} {parport port} [port_number] -Display either the address of the I/O port -(default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. -If a parameter is provided, first switch to use that port. -This is a write-once setting. +@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) +@b{Note:} This command is deprecated and will be removed in the future. +Use the command @command{adapter gpio} to configure the pin states before the adapter terminates its operation. -When using PPDEV to access the parallel port, use the number of the parallel port: -@option{parport port 0} (the default). If @option{parport port 0x378} is specified -you may encounter a problem. +Configure whether the driver sets the value specified by @command{adapter gpio} to the output pins on shutdown. @end deffn -@deffn {Config Command} {parport toggling_time} [nanoseconds] -Displays how many nanoseconds the hardware needs to toggle TCK; -the parport driver uses this value to obey the -@command{adapter speed} configuration. -When the optional @var{nanoseconds} parameter is given, -that setting is changed before displaying the current value. +@deffn {Config Command} {parport toggling_time} time +Configure how many nanoseconds the hardware needs to toggle TCK. +The driver uses this value to obey the @command{adapter speed} configuration. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. + @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @@ -3169,15 +3279,18 @@ oscilloscope, follow the procedure below: > parport toggling_time 1000 > adapter speed 500 @end example + This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: + @example > parport toggling_time @end example + Now the clock speed will be a better match for @command{adapter speed} command given in OpenOCD scripts and event handlers. @@ -3189,20 +3302,6 @@ match with the rate you specified in the @command{adapter speed} command; be conservative. @end quotation @end deffn - -@deffn {Config Command} {parport write_on_exit} (@option{on}|@option{off}) -This will configure the parallel driver to write a known -cable-specific value to the parallel interface on exiting OpenOCD. -@end deffn - -For example, the interface configuration file for a -classic ``Wiggler'' cable on LPT2 might look something like this: - -@example -adapter driver parport -parport port 0x278 -parport cable wiggler -@end example @end deffn @deffn {Interface Driver} {presto} @@ -3374,9 +3473,26 @@ The string will be of the format "DDDD:BB:SS.F" such as "0000:65:00.1". @end deffn @end deffn +@deffn {Interface Driver} {xlnx_axi_xvc} +This driver supports the Xilinx JTAG mapping over AXI using the AXI to JTAG +Converter or the AXI-to-JTAG mode of the debug bridge. +It is commonly found in Xilinx MPSoC based designs. It allows debugging +fabric based JTAG/SWD devices such as Cortex-M1/M3 or RISC-V softcores. Access to this +is exposed via extended capability registers in the AXI-mapped configuration space. + +@deffn {Config Command} {xlnx_axi_xvc dev_addr} addr +Specifies the address of the AXI-mapped registers via parameter @var{addr}. + +The correct value for @var{addr} is specified in the "Address Editor" tab +in Vivado. +@end deffn +@end deffn + @deffn {Interface Driver} {bcm2835gpio} -This SoC is present in Raspberry Pi which is a cheap single-board computer -exposing some GPIOs on its expansion header. +This GPIO interface is present in Raspberry Pi 0-4 which is a cheap +single-board computer exposing some GPIOs on its expansion header. + +@emph{Note:} for Raspberry Pi 5, use @b{linuxgpiod} not this driver. The driver accesses memory-mapped GPIO peripheral registers directly for maximum performance, but the only possible race condition is for @@ -3415,9 +3531,7 @@ and drive strength is reduced to 4 mA (2 mA on RPi 4). @deffn {Config Command} {bcm2835gpio peripheral_base} @var{base} Set the peripheral base register address to access GPIOs. Ignored if @file{/dev/gpiomem} is used. For the RPi1, use -0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full -list can be found in the -@uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}. +0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. @end deffn @end deffn @@ -5468,7 +5582,8 @@ Displays the current target state: @code{debug-running}, @code{halted}, @code{reset}, -@code{running}, or @code{unknown}. +@code{running}, +@code{unavailable} or @code{unknown}. (Also, @pxref{eventpolling,,Event Polling}.) @end deffn @@ -5898,6 +6013,24 @@ The flash bank to use is inferred from the @var{address} of each block, and the specified length must stay within that bank. @end deffn +@deffn {Command} {flash read_memory} address width count +This function provides an efficient way to read flash memory from a Tcl script. +A Tcl list containing the requested memory elements is returned by this function. + +@itemize +@item @var{address} ... flash memory address +@item @var{width} ... memory access bit size, can be 8, 16, 32 or 64 +@item @var{count} ... number of elements to read +@end itemize + +For example, the following command reads two 32 bit words from the flash +memory at address 0x08000000: + +@example +flash read_memory 0x08000000 32 2 +@end example +@end deffn + @deffn {Command} {flash write_bank} num filename [offset] Write the binary @file{filename} to flash bank @var{num}, starting at @var{offset} bytes from the beginning of the bank. If @var{offset} @@ -6591,6 +6724,50 @@ the flash. @end deffn @end deffn +@deffn {Flash Driver} {artery} +@cindex artery +This driver supports Artery Technology devices from the following series: + +@itemize +@item AT32F403A / AT32F407 +@item AT32F413 +@item AT32F415 +@item AT32F421 +@item AT32F423 +@item AT32F425 +@item AT32F435 / AT32F437 +@item AT32WB415 +@end itemize + +Devices with dual-bank flash memory are currently not supported. +Also, access to user data in the user system data (USD) area is not supported. + +The driver supports flash write protection and flash access protection (FAP). +For the FAP, only the low-level protection is implemented. + +@b{Note:} a change of the flash write protection or FAP requires a device reset for the changes to take effect. + +The @var{artery} driver provides the following additional commands: + +@deffn {Command} {artery fap enable} +Enable low-level flash access protection (FAP). +@end deffn + +@deffn {Command} {artery fap disable} +Disable flash access protection (FAP). +@end deffn + +@deffn {Command} {artery fap state} +Get the flash access protection (FAP) state. +The state is a boolean value that indicates whether the FAP is configured in level 'low' or higher. +@end deffn + +@deffn {Command} {artery mass_erase} +Erase entire bank. +@end deffn + +@end deffn + @deffn {Flash Driver} {at91samd} @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller @@ -6839,6 +7016,18 @@ This driver uses the same command names/syntax as @xref{at91sam3}. flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME @end example +These families also have a user signature area located at the beginning +of an embedded flash. This is a 512 bytes large page whose data are not +erased by assering ERASE pin or by software ERASE command. It can be +used to store configuration, keys, trimming values and so on. The area +overlaps with the beginning of standard flash and uses special commands +to perform write/read operations. OpenOCD locates the signature area +at fake address above 32 bit address space, specifically at 0x100000000. + +@example +flash bank $_SIGNATURENAME atsamv 0x100000000 0 0 0 $_TARGETNAME +@end example + @deffn {Command} {atsamv gpnvm} [@option{show} [@option{all}|number]] @deffnx {Command} {atsamv gpnvm} (@option{clr}|@option{set}) number With no parameters, @option{show} or @option{show all}, @@ -8319,10 +8508,8 @@ is the register offset of the Option byte to read. For example to read the FLASH_OPTR register: @example -stm32l4x option_read 0 0x20 -# Option Register (for STM32L4x): <0x40022020> = 0xffeff8aa -# Option Register (for STM32WBx): <0x58004020> = ... -# The correct flash base address will be used automatically +> stm32l4x option_read 0 0x20 +0xffeff8aa @end example The above example will read out the FLASH_OPTR register which contains the RDP @@ -9311,10 +9498,10 @@ will proceed to quit. @end deffn @anchor{debuglevel} -@deffn {Command} {debug_level} [n] +@deffn {Command} {debug_level} [number] @cindex message level -Display debug level. -If @var{n} (from 0..4) is provided, then set it to that level. +Without arguments it displays the current debug level. +If @var{number} (from 0..4) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; @@ -9341,7 +9528,7 @@ Redirect logging to @var{filename}. If used without an argument or stderr. @end deffn -@deffn {Command} {add_script_search_dir} [directory] +@deffn {Command} {add_script_search_dir} directory Add @var{directory} to the file/script search path. @end deffn @@ -9734,12 +9921,14 @@ hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. -@deffn {Command} {bp} [address len [@option{hw}]] +@deffn {Command} {bp} [address [asid] len [@option{hw} | @option{hw_ctx}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. -This is a software breakpoint, unless @option{hw} is specified -in which case it will be a hardware breakpoint. +This is a software breakpoint, unless @option{hw} or @option{hw_ctx} +is specified in which case it will be a hardware, context or hybrid breakpoint. +The context and hybrid breakpoints require an additional parameter @var{asid}: +address space identifier. (@xref{arm9vectorcatch,,arm9 vector_catch}, or @pxref{xscalevectorcatch,,xscale vector_catch}, for similar mechanisms that do not consume hardware breakpoints.) @@ -9876,11 +10065,11 @@ Requests the current target to map the specified @var{virtual_address} to its corresponding physical address, and displays the result. @end deffn -@deffn {Command} {add_help_text} 'command_name' 'help-string' +@deffn {Command} {add_help_text} command_name help_string Add or replace help text on the given @var{command_name}. @end deffn -@deffn {Command} {add_usage_text} 'command_name' 'help-string' +@deffn {Command} {add_usage_text} command_name help_string Add or replace usage text on the given @var{command_name}. @end deffn @@ -10739,10 +10928,6 @@ Display/set the current core displayed in GDB Selects whether interrupts will be processed when single stepping @end deffn -@deffn {Command} {cache_config l2x} [base way] -configure l2x cache -@end deffn - @deffn {Command} {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]] Dump the MMU translation table from TTB0 or TTB1 register, or from physical memory location @var{address}. When dumping the table from @var{address}, print at most @@ -10958,6 +11143,10 @@ Enable or disable trace output for all ITM stimulus ports. @subsection Cortex-M specific commands @cindex Cortex-M +@deffn {Command} {cortex_m cache_info} +Report information about the type and size of the cache, if present. +@end deffn + @deffn {Command} {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}|@option{steponly}) Control masking (disabling) interrupts during target step/resume. diff --git a/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt b/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt new file mode 100644 index 0000000000..9a0ae71edf --- /dev/null +++ b/doc/usb_adapters/ch347/1a86_55dd_easydevkit.txt @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: GPL-2.0-or-later OR GFDL-1.2-no-invariants-or-later + +# Link: https://www.easydevkits.com +# PCB: ESP32-WROVER-E WCH JTAG DevKit v0.1 +# Chip: CH347T in mode 3 (UART+JTAG mode) +# Product id of 0x55dd is only valid if the chip is started in mode 3 +# These are the other product ids: mode 0 = 0x55da, mode 1 = 0x55db, mode 2 = 0x55dc +# The similar chip CH347F has no modes and always product id 0x55de + +Bus 001 Device 013: ID 1a86:55dd QinHeng Electronics EasyDevKit +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1a86 QinHeng Electronics + idProduct 0x55dd + bcdDevice 4.41 + iManufacturer 1 EasyDevKits + iProduct 2 EasyDevKit + iSerial 3 ACBACJGAAB + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 0x0062 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Association: + bLength 8 + bDescriptorType 11 + bFirstInterface 0 + bInterfaceCount 2 + bFunctionClass 2 Communications + bFunctionSubClass 2 Abstract (modem) + bFunctionProtocol 1 AT-commands (v.25ter) + iFunction 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 0 + CDC Header: + bcdCDC 1.10 + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x02 + line coding and serial state + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x04 EP 4 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x84 EP 4 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x06 EP 6 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x86 EP 6 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 0 + bDeviceProtocol 255 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index c5430aeb05..a79844eb5f 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -310,16 +310,15 @@ int nand_probe(struct nand_device *nand) retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { - case ERROR_NAND_OPERATION_FAILED: - LOG_DEBUG("controller initialization failed"); - return ERROR_NAND_OPERATION_FAILED; - case ERROR_NAND_OPERATION_NOT_SUPPORTED: - LOG_ERROR( - "BUG: controller reported that it doesn't support default parameters"); - return ERROR_NAND_OPERATION_FAILED; - default: - LOG_ERROR("BUG: unknown controller initialization failure"); - return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_FAILED: + LOG_DEBUG("controller initialization failed"); + return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_NOT_SUPPORTED: + LOG_ERROR("BUG: controller reported that it doesn't support default parameters"); + return ERROR_NAND_OPERATION_FAILED; + default: + LOG_ERROR("BUG: unknown controller initialization failure"); + return ERROR_NAND_OPERATION_FAILED; } } @@ -450,18 +449,18 @@ int nand_probe(struct nand_device *nand) /* erase size */ if (nand->device->erase_size == 0) { switch ((id_buff[4] >> 4) & 3) { - case 0: - nand->erase_size = 64 << 10; - break; - case 1: - nand->erase_size = 128 << 10; - break; - case 2: - nand->erase_size = 256 << 10; - break; - case 3: - nand->erase_size = 512 << 10; - break; + case 0: + nand->erase_size = 64 << 10; + break; + case 1: + nand->erase_size = 128 << 10; + break; + case 2: + nand->erase_size = 256 << 10; + break; + case 3: + nand->erase_size = 512 << 10; + break; } } else nand->erase_size = nand->device->erase_size; @@ -470,19 +469,18 @@ int nand_probe(struct nand_device *nand) retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { - case ERROR_NAND_OPERATION_FAILED: - LOG_DEBUG("controller initialization failed"); - return ERROR_NAND_OPERATION_FAILED; - case ERROR_NAND_OPERATION_NOT_SUPPORTED: - LOG_ERROR( - "controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", + case ERROR_NAND_OPERATION_FAILED: + LOG_DEBUG("controller initialization failed"); + return ERROR_NAND_OPERATION_FAILED; + case ERROR_NAND_OPERATION_NOT_SUPPORTED: + LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", nand->bus_width, nand->address_cycles, nand->page_size); - return ERROR_NAND_OPERATION_FAILED; - default: - LOG_ERROR("BUG: unknown controller initialization failure"); - return ERROR_NAND_OPERATION_FAILED; + return ERROR_NAND_OPERATION_FAILED; + default: + LOG_ERROR("BUG: unknown controller initialization failure"); + return ERROR_NAND_OPERATION_FAILED; } } diff --git a/src/flash/nand/davinci.c b/src/flash/nand/davinci.c index 17040fe172..d27b4c748c 100644 --- a/src/flash/nand/davinci.c +++ b/src/flash/nand/davinci.c @@ -256,17 +256,17 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page, /* If we're not given OOB, write 0xff where we don't write ECC codes. */ switch (nand->page_size) { - case 512: - oob_size = 16; - break; - case 2048: - oob_size = 64; - break; - case 4096: - oob_size = 128; - break; - default: - return ERROR_NAND_OPERATION_FAILED; + case 512: + oob_size = 16; + break; + case 2048: + oob_size = 64; + break; + case 4096: + oob_size = 128; + break; + default: + return ERROR_NAND_OPERATION_FAILED; } if (!oob) { ooballoc = malloc(oob_size); @@ -391,15 +391,15 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, * for 16-bit OOB, those extra bytes are discontiguous. */ switch (nand->page_size) { - case 512: - oob_offset = 0; - break; - case 2048: - oob_offset = 40; - break; - default: - oob_offset = 80; - break; + case 512: + oob_offset = 0; + break; + case 2048: + oob_offset = 40; + break; + default: + oob_offset = 80; + break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); @@ -482,15 +482,15 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, * the standard ECC logic can't handle. */ switch (nand->page_size) { - case 512: - l = ecc512; - break; - case 2048: - l = ecc2048; - break; - default: - l = ecc4096; - break; + case 512: + l = ecc512; + break; + case 2048: + l = ecc2048; + break; + default: + l = ecc4096; + break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); @@ -741,19 +741,19 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) info->read_page = nand_read_page_raw; switch (eccmode) { - case HWECC1: - /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ - info->write_page = davinci_write_page_ecc1; - break; - case HWECC4: - /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ - info->write_page = davinci_write_page_ecc4; - break; - case HWECC4_INFIX: - /* Same 4-bit ECC HW, with problematic page/ecc layout */ - info->read_page = davinci_read_page_ecc4infix; - info->write_page = davinci_write_page_ecc4infix; - break; + case HWECC1: + /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ + info->write_page = davinci_write_page_ecc1; + break; + case HWECC4: + /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ + info->write_page = davinci_write_page_ecc4; + break; + case HWECC4_INFIX: + /* Same 4-bit ECC HW, with problematic page/ecc layout */ + info->read_page = davinci_read_page_ecc4infix; + info->write_page = davinci_write_page_ecc4infix; + break; } return ERROR_OK; diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index 5d99102c85..eda033b5b7 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -10,30 +10,32 @@ #ifdef HAVE_CONFIG_H #include #endif + +#include #include "core.h" #include "driver.h" static struct nand_flash_controller *nand_flash_controllers[] = { - &nonce_nand_controller, + // Keep in alphabetic order the list of drivers + &at91sam9_nand_controller, &davinci_nand_controller, + &imx31_nand_flash_controller, &lpc3180_nand_controller, &lpc32xx_nand_controller, + &mxc_nand_flash_controller, + &nonce_nand_controller, + &nuc910_nand_controller, &orion_nand_controller, &s3c2410_nand_controller, &s3c2412_nand_controller, &s3c2440_nand_controller, &s3c2443_nand_controller, &s3c6400_nand_controller, - &mxc_nand_flash_controller, - &imx31_nand_flash_controller, - &at91sam9_nand_controller, - &nuc910_nand_controller, - NULL }; struct nand_flash_controller *nand_driver_find_by_name(const char *name) { - for (unsigned int i = 0; nand_flash_controllers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(nand_flash_controllers); i++) { struct nand_flash_controller *controller = nand_flash_controllers[i]; if (strcmp(name, controller->name) == 0) return controller; @@ -42,7 +44,7 @@ struct nand_flash_controller *nand_driver_find_by_name(const char *name) } int nand_driver_walk(nand_driver_walker_t f, void *x) { - for (unsigned int i = 0; nand_flash_controllers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(nand_flash_controllers); i++) { int retval = (*f)(nand_flash_controllers[i], x); if (retval != ERROR_OK) return retval; diff --git a/src/flash/nand/driver.h b/src/flash/nand/driver.h index 4e84f10fbd..d26e77c75b 100644 --- a/src/flash/nand/driver.h +++ b/src/flash/nand/driver.h @@ -89,6 +89,7 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); */ int nand_driver_walk(nand_driver_walker_t f, void *x); +// Keep in alphabetic order the list of drivers extern struct nand_flash_controller at91sam9_nand_controller; extern struct nand_flash_controller davinci_nand_controller; extern struct nand_flash_controller imx31_nand_flash_controller; diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index 86e94685b7..23c18947ba 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -256,23 +256,23 @@ static int imx31_command(struct nand_device *nand, uint8_t command) } switch (command) { - case NAND_CMD_READOOB: - command = NAND_CMD_READ0; - in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for - * data_read() and - * read_block_data() to - * spare area in SRAM - * buffer */ - break; - case NAND_CMD_READ1: - command = NAND_CMD_READ0; - /* - * offset == one half of page size - */ - in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); - break; - default: - in_sram_address = MX3_NF_MAIN_BUFFER0; + case NAND_CMD_READOOB: + command = NAND_CMD_READ0; + in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for + * data_read() and + * read_block_data() to + * spare area in SRAM + * buffer */ + break; + case NAND_CMD_READ1: + command = NAND_CMD_READ0; + /* + * offset == one half of page size + */ + in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; + default: + in_sram_address = MX3_NF_MAIN_BUFFER0; } target_write_u16(target, MX3_NF_FCMD, command); @@ -291,20 +291,20 @@ static int imx31_command(struct nand_device *nand, uint8_t command) */ sign_of_sequental_byte_read = 0; switch (command) { - case NAND_CMD_READID: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_STATUS: - mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - break; - case NAND_CMD_READ0: - mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; - break; - default: - mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + case NAND_CMD_READID: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_STATUS: + mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + break; + case NAND_CMD_READ0: + mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; + break; + default: + mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; } return ERROR_OK; } @@ -647,46 +647,46 @@ static int do_data_output(struct nand_device *nand) struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; switch (mx3_nf_info->fin) { - case MX3_NF_FIN_DATAOUT: - /* - * start data output operation (set MX3_NF_BIT_OP_DONE==0) - */ - target_write_u16 (target, MX3_NF_CFG2, - MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); - { - int poll_result; - poll_result = poll_for_complete_op(target, "data output"); - if (poll_result != ERROR_OK) - return poll_result; + case MX3_NF_FIN_DATAOUT: + /* + * start data output operation (set MX3_NF_BIT_OP_DONE==0) + */ + target_write_u16 (target, MX3_NF_CFG2, + MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); + { + int poll_result; + poll_result = poll_for_complete_op(target, "data output"); + if (poll_result != ERROR_OK) + return poll_result; + } + mx3_nf_info->fin = MX3_NF_FIN_NONE; + /* + * ECC stuff + */ + if (mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE + && mx3_nf_info->flags.hw_ecc_enabled) { + uint16_t ecc_status; + target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); + switch (ecc_status & 0x000c) { + case 1 << 2: + LOG_DEBUG("main area read with 1 (correctable) error"); + break; + case 2 << 2: + LOG_DEBUG("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } - mx3_nf_info->fin = MX3_NF_FIN_NONE; - /* - * ECC stuff - */ - if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) - && mx3_nf_info->flags.hw_ecc_enabled) { - uint16_t ecc_status; - target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); - switch (ecc_status & 0x000c) { - case 1 << 2: - LOG_DEBUG("main area read with 1 (correctable) error"); - break; - case 2 << 2: - LOG_DEBUG("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - } - switch (ecc_status & 0x0003) { - case 1: - LOG_DEBUG("spare area read with 1 (correctable) error"); - break; - case 2: - LOG_DEBUG("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; - } + switch (ecc_status & 0x0003) { + case 1: + LOG_DEBUG("spare area read with 1 (correctable) error"); + break; + case 2: + LOG_DEBUG("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } - break; - case MX3_NF_FIN_NONE: - break; + } + break; + case MX3_NF_FIN_NONE: + break; } return ERROR_OK; } diff --git a/src/flash/nand/mxc.c b/src/flash/nand/mxc.c index 845a3bb9a6..f37468f8dc 100644 --- a/src/flash/nand/mxc.c +++ b/src/flash/nand/mxc.c @@ -338,26 +338,26 @@ static int mxc_command(struct nand_device *nand, uint8_t command) return validate_target_result; switch (command) { - case NAND_CMD_READOOB: - command = NAND_CMD_READ0; - /* set read point for data_read() and read_block_data() to - * spare area in SRAM buffer - */ - if (nfc_is_v1()) - in_sram_address = MXC_NF_V1_SPARE_BUFFER0; - else - in_sram_address = MXC_NF_V2_SPARE_BUFFER0; - break; - case NAND_CMD_READ1: - command = NAND_CMD_READ0; - /* - * offset == one half of page size - */ - in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); - break; - default: - in_sram_address = MXC_NF_MAIN_BUFFER0; - break; + case NAND_CMD_READOOB: + command = NAND_CMD_READ0; + /* set read point for data_read() and read_block_data() to + * spare area in SRAM buffer + */ + if (nfc_is_v1()) + in_sram_address = MXC_NF_V1_SPARE_BUFFER0; + else + in_sram_address = MXC_NF_V2_SPARE_BUFFER0; + break; + case NAND_CMD_READ1: + command = NAND_CMD_READ0; + /* + * offset == one half of page size + */ + in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; + default: + in_sram_address = MXC_NF_MAIN_BUFFER0; + break; } target_write_u16(target, MXC_NF_FCMD, command); @@ -374,24 +374,24 @@ static int mxc_command(struct nand_device *nand, uint8_t command) sign_of_sequental_byte_read = 0; /* Handle special read command and adjust NF_CFG2(FDO) */ switch (command) { - case NAND_CMD_READID: - mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - break; - case NAND_CMD_STATUS: - mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - target_write_u16 (target, MXC_NF_BUFADDR, 0); - in_sram_address = 0; - break; - case NAND_CMD_READ0: - mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; - mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; - break; - default: - /* Other command use the default 'One page data out' FDO */ - mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; - break; + case NAND_CMD_READID: + mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + break; + case NAND_CMD_STATUS: + mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + target_write_u16 (target, MXC_NF_BUFADDR, 0); + in_sram_address = 0; + break; + case NAND_CMD_READ0: + mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; + mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; + break; + default: + /* Other command use the default 'One page data out' FDO */ + mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; + break; } return ERROR_OK; } @@ -857,20 +857,20 @@ static int ecc_status_v1(struct nand_device *nand) target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { - case 1 << 2: - LOG_INFO("main area read with 1 (correctable) error"); - break; - case 2 << 2: - LOG_INFO("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; + case 1 << 2: + LOG_INFO("main area read with 1 (correctable) error"); + break; + case 2 << 2: + LOG_INFO("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } switch (ecc_status & 0x0003) { - case 1: - LOG_INFO("spare area read with 1 (correctable) error"); - break; - case 2: - LOG_INFO("main area read with more than 1 (incorrectable) error"); - return ERROR_NAND_OPERATION_FAILED; + case 1: + LOG_INFO("spare area read with 1 (correctable) error"); + break; + case 2: + LOG_INFO("main area read with more than 1 (incorrectable) error"); + return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } @@ -904,31 +904,31 @@ static int do_data_output(struct nand_device *nand) struct target *target = nand->target; int poll_result; switch (mxc_nf_info->fin) { - case MXC_NF_FIN_DATAOUT: - /* - * start data output operation (set MXC_NF_BIT_OP_DONE==0) - */ - target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); - poll_result = poll_for_complete_op(nand, "data output"); - if (poll_result != ERROR_OK) - return poll_result; + case MXC_NF_FIN_DATAOUT: + /* + * start data output operation (set MXC_NF_BIT_OP_DONE==0) + */ + target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); + poll_result = poll_for_complete_op(nand, "data output"); + if (poll_result != ERROR_OK) + return poll_result; - mxc_nf_info->fin = MXC_NF_FIN_NONE; - /* - * ECC stuff - */ - if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { - int ecc_status; - if (nfc_is_v1()) - ecc_status = ecc_status_v1(nand); - else - ecc_status = ecc_status_v2(nand); - if (ecc_status != ERROR_OK) - return ecc_status; - } - break; - case MXC_NF_FIN_NONE: - break; + mxc_nf_info->fin = MXC_NF_FIN_NONE; + /* + * ECC stuff + */ + if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { + int ecc_status; + if (nfc_is_v1()) + ecc_status = ecc_status_v1(nand); + else + ecc_status = ecc_status_v2(nand); + if (ecc_status != ERROR_OK) + return ecc_status; + } + break; + case MXC_NF_FIN_NONE: + break; } return ERROR_OK; } diff --git a/src/flash/nand/tcl.c b/src/flash/nand/tcl.c index 67a62770fb..0d6686d007 100644 --- a/src/flash/nand/tcl.c +++ b/src/flash/nand/tcl.c @@ -50,21 +50,22 @@ COMMAND_HANDLER(handle_nand_info_command) int last = -1; switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 1: - first = 0; - last = INT32_MAX; - break; - case 2: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); - first = last = i; - i = 0; - break; - case 3: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); - break; + case 1: + first = 0; + last = INT32_MAX; + break; + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); + first = i; + last = i; + i = 0; + break; + case 3: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); + COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } struct nand_device *p; diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 7a81b282b6..f408559004 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -12,6 +12,7 @@ NOR_DRIVERS = \ %D%/aduc702x.c \ %D%/aducm360.c \ %D%/ambiqmicro.c \ + %D%/artery.c \ %D%/at91sam4.c \ %D%/at91sam4l.c \ %D%/at91samd.c \ @@ -85,6 +86,7 @@ NOR_DRIVERS = \ %D%/xmc4xxx.c NORHEADERS = \ + %D%/artery.h \ %D%/core.h \ %D%/cc3220sf.h \ %D%/bluenrg-x.h \ diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c index bb893778ce..cb9fa5ed77 100644 --- a/src/flash/nor/ambiqmicro.c +++ b/src/flash/nor/ambiqmicro.c @@ -190,37 +190,36 @@ static int ambiqmicro_read_part_info(struct flash_bank *bank) ambiqmicro_info->target_class = (part_num & 0xFF000000) >> 24; switch (ambiqmicro_info->target_class) { - case 1: /* 1 - Apollo */ - case 5: /* 5 - Apollo Bootloader */ - bank->base = bank->bank_number * 0x40000; - ambiqmicro_info->pagesize = 2048; - ambiqmicro_info->flshsiz = + case 1: /* 1 - Apollo */ + case 5: /* 5 - Apollo Bootloader */ + bank->base = bank->bank_number * 0x40000; + ambiqmicro_info->pagesize = 2048; + ambiqmicro_info->flshsiz = apollo_flash_size[(part_num & 0x00F00000) >> 20]; - ambiqmicro_info->sramsiz = + ambiqmicro_info->sramsiz = apollo_sram_size[(part_num & 0x000F0000) >> 16]; - ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / - ambiqmicro_info->pagesize; - if (ambiqmicro_info->num_pages > 128) { - ambiqmicro_info->num_pages = 128; - ambiqmicro_info->flshsiz = 1024 * 256; - } - break; + ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / + ambiqmicro_info->pagesize; + if (ambiqmicro_info->num_pages > 128) { + ambiqmicro_info->num_pages = 128; + ambiqmicro_info->flshsiz = 1024 * 256; + } + break; - default: - LOG_INFO("Unknown Class. Using Apollo-64 as default."); + default: + LOG_INFO("Unknown Class. Using Apollo-64 as default."); - bank->base = bank->bank_number * 0x40000; - ambiqmicro_info->pagesize = 2048; - ambiqmicro_info->flshsiz = apollo_flash_size[1]; - ambiqmicro_info->sramsiz = apollo_sram_size[0]; - ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / + bank->base = bank->bank_number * 0x40000; + ambiqmicro_info->pagesize = 2048; + ambiqmicro_info->flshsiz = apollo_flash_size[1]; + ambiqmicro_info->sramsiz = apollo_sram_size[0]; + ambiqmicro_info->num_pages = ambiqmicro_info->flshsiz / ambiqmicro_info->pagesize; - if (ambiqmicro_info->num_pages > 128) { - ambiqmicro_info->num_pages = 128; - ambiqmicro_info->flshsiz = 1024 * 256; - } - break; - + if (ambiqmicro_info->num_pages > 128) { + ambiqmicro_info->num_pages = 128; + ambiqmicro_info->flshsiz = 1024 * 256; + } + break; } if (ambiqmicro_info->target_class < ARRAY_SIZE(ambiqmicro_parts)) @@ -309,9 +308,9 @@ static int ambiqmicro_exec_command(struct target *target, */ target_poll(target); alive_sleep(100); - LOG_DEBUG("state = %d", target->state); } else { - LOG_ERROR("Target not halted or running %d", target->state); + LOG_ERROR("Target not halted or running (state is %s)", + target_state_name(target)); break; } } diff --git a/src/flash/nor/artery.c b/src/flash/nor/artery.c new file mode 100644 index 0000000000..797d60de51 --- /dev/null +++ b/src/flash/nor/artery.c @@ -0,0 +1,2608 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2023 by Marc Schink + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include +#include +#include + +#include "artery.h" + +// Flash timeout values in milliseconds. +#define FLASH_MASS_ERASE_TIMEOUT 2400 +#define FLASH_ERASE_TIMEOUT 500 +#define FLASH_WRITE_TIMEOUT 5 +#define HICK_STABLE_TIMEOUT 1000 + +/* + * Flash memory register assignment for the following device series: + * - AT32F403A / AT32F407 + * - AT32F413 + * - AT32F415 + * - AT32F421 + * - AT32F423 + * - AT32F425 + * - AT32WB415 + */ +static const uint32_t flash_regs_f4xx_wb415[ARTERY_FLASH_REG_INDEX_NUM] = { + [ARTERY_FLASH_REG_PSR] = 0x00, + [ARTERY_FLASH_REG_UNLOCK] = 0x04, + [ARTERY_FLASH_REG_USD_UNLOCK] = 0x08, + [ARTERY_FLASH_REG_STS] = 0x0c, + [ARTERY_FLASH_REG_CTRL] = 0x10, + [ARTERY_FLASH_REG_ADDR] = 0x14, + [ARTERY_FLASH_REG_USD] = 0x1c, + [ARTERY_FLASH_REG_EPPS0] = 0x20, + // [ARTERY_FLASH_REG_EPPS1] not available. +}; + +// Flash memory register assignment for the AT32F435 / AT32F437 series. +static const uint32_t flash_regs_f435_f437[ARTERY_FLASH_REG_INDEX_NUM] = { + [ARTERY_FLASH_REG_PSR] = 0x00, + [ARTERY_FLASH_REG_UNLOCK] = 0x04, + [ARTERY_FLASH_REG_USD_UNLOCK] = 0x08, + [ARTERY_FLASH_REG_STS] = 0x0c, + [ARTERY_FLASH_REG_CTRL] = 0x10, + [ARTERY_FLASH_REG_ADDR] = 0x14, + [ARTERY_FLASH_REG_USD] = 0x1c, + [ARTERY_FLASH_REG_EPPS0] = 0x20, + [ARTERY_FLASH_REG_EPPS1] = 0x2c, +}; + +/* + * User system data (USD) offsets for the following device series: + * - AT32F415 + * - AT32F421 + * - AT32F423 + * - AT32F425 + * - AT32WB415 + */ +static const uint32_t usd_offsets_f4xx_wb415[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + // [ARTERY_USD_EPP_EXT_INDEX] not available. + [ARTERY_USD_DATA_EXT_INDEX] = 0x10, +}; + +// User system data (USD) offsets for the AT32F403A / AT32F407 / AT32F413 series. +static const uint32_t usd_offsets_f403a_f407_f413[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + // [ARTERY_USD_EPP_EXT_INDEX] not available. + [ARTERY_USD_DATA_EXT_INDEX] = 0x14, +}; + +// User system data (USD) offsets for the AT32F435 / AT32F437 series. +static const uint32_t usd_offsets_f435_f437[ARTERY_USD_INDEX_NUM] = { + [ARTERY_USD_FAP_INDEX] = 0x00, + [ARTERY_USD_SSB_INDEX] = 0x02, + [ARTERY_USD_DATA_INDEX] = 0x04, + [ARTERY_USD_EPP_INDEX] = 0x08, + [ARTERY_USD_EPP_EXT_INDEX] = 0x14, + [ARTERY_USD_DATA_EXT_INDEX] = 0x4c, +}; + +static const struct artery_series_info artery_series[] = { + [ARTERY_SERIES_F403A_F407] = { + .has_fap_high_level = false, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f403a_f407_f413, + }, + [ARTERY_SERIES_F413] = { + .has_fap_high_level = false, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f403a_f407_f413, + }, + [ARTERY_SERIES_F415] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F421] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F423] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40023C00, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40023800, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F425] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, + [ARTERY_SERIES_F435_F437] = { + .has_fap_high_level = false, + .has_epp_ext = true, + .flash_regs_base = 0x40023C00, + .flash_regs = flash_regs_f435_f437, + .crm_base = 0x40023800, + .usd_base = 0x1FFFC000, + .usd_offsets = usd_offsets_f435_f437, + }, + [ARTERY_SERIES_WB415] = { + .has_fap_high_level = true, + .has_epp_ext = false, + .flash_regs_base = 0x40022000, + .flash_regs = flash_regs_f4xx_wb415, + .crm_base = 0x40021000, + .usd_base = 0x1FFFF800, + .usd_offsets = usd_offsets_f4xx_wb415, + }, +}; + +static const struct artery_part_info artery_parts[] = { + { + .pid = 0x70050240, + .name = "AT32F403AVCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050241, + .name = "AT32F403ARCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050242, + .name = "AT32F403ACCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050243, + .name = "AT32F403ACCU7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050249, + .name = "AT32F407VCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x7005024a, + .name = "AT32F407RCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502cd, + .name = "AT32F403AVET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502ce, + .name = "AT32F403ARET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502cf, + .name = "AT32F403ACET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d0, + .name = "AT32F403ACEU7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d1, + .name = "AT32F407VET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700502d2, + .name = "AT32F407RET7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 512, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70050254, + .name = "AT32F407AVCT7", + .series = ARTERY_SERIES_F403A_F407, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030240, + .name = "AT32F413RCT7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c1, + .name = "AT32F413RBT7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030242, + .name = "AT32F413CCT7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c3, + .name = "AT32F413CBT7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030244, + .name = "AT32F413KCU7-4", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301c5, + .name = "AT32F413KBU7-4", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030106, + .name = "AT32F413C8T7", + .series = ARTERY_SERIES_F413, + .flash_size = 64, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030247, + .name = "AT32F413CCU7", + .series = ARTERY_SERIES_F413, + .flash_size = 256, + .page_size = 2048, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x700301ca, + .name = "AT32F413CBU7", + .series = ARTERY_SERIES_F413, + .flash_size = 128, + .page_size = 1024, + .usd_size = 48, + .usd_data_size = 8, + }, + { + .pid = 0x70030240, + .name = "AT32F415RCT7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030241, + .name = "AT32F415CCT7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030242, + .name = "AT32F415KCU7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030243, + .name = "AT32F415RCT7-7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c4, + .name = "AT32F415RBT7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c5, + .name = "AT32F415CBT7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c6, + .name = "AT32F415KBU7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301c7, + .name = "AT32F415RBT7-7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030108, + .name = "AT32F415R8T7", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x70030109, + .name = "AT32F415C8T7", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x7003010a, + .name = "AT32F415K8U7-4", + .series = ARTERY_SERIES_F415, + .flash_size = 64, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x7003024c, + .name = "AT32F415CCU7", + .series = ARTERY_SERIES_F415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x700301cd, + .name = "AT32F415CBU7", + .series = ARTERY_SERIES_F415, + .flash_size = 128, + .page_size = 1024, + .usd_size = 1024, + .usd_data_size = 506, + }, + { + .pid = 0x50020100, + .name = "AT32F421C8T7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020101, + .name = "AT32F421K8T7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020102, + .name = "AT32F421K8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020103, + .name = "AT32F421K8U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020104, + .name = "AT32F421F8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020105, + .name = "AT32F421F8P7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020086, + .name = "AT32F421C6T7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020087, + .name = "AT32F421K6T7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020088, + .name = "AT32F421K6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020089, + .name = "AT32F421K6U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5002008a, + .name = "AT32F421F6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5002008b, + .name = "AT32F421F6P7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000c, + .name = "AT32F421C4T7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000d, + .name = "AT32F421K4T7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000e, + .name = "AT32F421K4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5001000f, + .name = "AT32F421K4U7-4", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010010, + .name = "AT32F421F4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010011, + .name = "AT32F421F4P7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020112, + .name = "AT32F421G8U7", + .series = ARTERY_SERIES_F421, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50020093, + .name = "AT32F421G6U7", + .series = ARTERY_SERIES_F421, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50010014, + .name = "AT32F421G4U7", + .series = ARTERY_SERIES_F421, + .flash_size = 16, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3240, + .name = "AT32F423VCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c1, + .name = "AT32F423VBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032102, + .name = "AT32F423V8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3243, + .name = "AT32F423RCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c4, + .name = "AT32F423RBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032105, + .name = "AT32F423R8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3246, + .name = "AT32F423RCT7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21c7, + .name = "AT32F423RBT7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032108, + .name = "AT32F423R8T7-7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3249, + .name = "AT32F423CCT7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21ca, + .name = "AT32F423CBT7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x7003210b, + .name = "AT32F423C8T7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a324c, + .name = "AT32F423CCU7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21cd, + .name = "AT32F423CBU7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x7003210e, + .name = "AT32F423C8U7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3250, + .name = "AT32F423TCU7", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21d1, + .name = "AT32F423TBU7", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032112, + .name = "AT32F423T8U7", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a3253, + .name = "AT32F423KCU7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x700a21d4, + .name = "AT32F423KBU7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 128, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70032115, + .name = "AT32F423K8U7-4", + .series = ARTERY_SERIES_F423, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092100, + .name = "AT32F425R8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092081, + .name = "AT32F425R6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092103, + .name = "AT32F425R8T7-7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092084, + .name = "AT32F425R6T7-7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092106, + .name = "AT32F425C8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092087, + .name = "AT32F425C6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092109, + .name = "AT32F425C8U7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009208a, + .name = "AT32F425C6U7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009210c, + .name = "AT32F425K8T7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009208d, + .name = "AT32F425K6T7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x5009210f, + .name = "AT32F425K8U7-4", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092090, + .name = "AT32F425K6U7-4", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092112, + .name = "AT32F425F8P7", + .series = ARTERY_SERIES_F425, + .flash_size = 64, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x50092093, + .name = "AT32F425F6P7", + .series = ARTERY_SERIES_F425, + .flash_size = 32, + .page_size = 1024, + .usd_size = 512, + .usd_data_size = 250, + }, + { + .pid = 0x70084598, + .name = "AT32F435ZDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083242, + .name = "AT32F435ZCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x70084599, + .name = "AT32F435VDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083245, + .name = "AT32F435VCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459a, + .name = "AT32F435RDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083248, + .name = "AT32F435RCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459b, + .name = "AT32F435CDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x7008324b, + .name = "AT32F435CCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459c, + .name = "AT32F435CDU7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x7008324e, + .name = "AT32F435CCU7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459d, + .name = "AT32F437ZDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083251, + .name = "AT32F437ZCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459e, + .name = "AT32F437VDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083254, + .name = "AT32F437VCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x7008459f, + .name = "AT32F437RDT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 448, + .page_size = 4096, + .usd_size = 4096, + .usd_data_size = 2012, + }, + { + .pid = 0x70083257, + .name = "AT32F437RCT7", + .series = ARTERY_SERIES_F435_F437, + .flash_size = 256, + .page_size = 2048, + .usd_size = 512, + .usd_data_size = 220, + }, + { + .pid = 0x70030250, + .name = "AT32WB415CCU7-7", + .series = ARTERY_SERIES_WB415, + .flash_size = 256, + .page_size = 2048, + .usd_size = 1024, + .usd_data_size = 506, + }, +}; + +/* flash bank artery 0 0 */ +FLASH_BANK_COMMAND_HANDLER(artery_flash_bank_command) +{ + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct artery_flash_bank *artery_info = calloc(1, + sizeof(struct artery_flash_bank)); + + if (!artery_info) + return ERROR_FAIL; + + bank->driver_priv = artery_info; + artery_info->probed = false; + + return ERROR_OK; +} + +static int artery_read_flash_register(struct flash_bank *bank, + enum artery_flash_reg_index reg, uint32_t *value) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t reg_addr = series_info->flash_regs_base + series_info->flash_regs[reg]; + + return target_read_u32(bank->target, reg_addr, value); +} + +static int artery_write_flash_register(struct flash_bank *bank, + enum artery_flash_reg_index reg, uint32_t value) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t reg_addr = series_info->flash_regs_base + series_info->flash_regs[reg]; + + return target_write_u32(bank->target, reg_addr, value); +} + +static int artery_wait_flash_busy(struct flash_bank *bank, unsigned int timeout) +{ + const int64_t start_time = timeval_ms(); + + while (true) { + uint32_t status; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, + &status); + + if (retval != ERROR_OK) + return retval; + + if (!(status & FLASH_STS_OBF)) + break; + + if ((timeval_ms() - start_time) > timeout) { + LOG_ERROR("Timed out waiting for flash"); + return ERROR_FAIL; + } + + keep_alive(); + } + + return ERROR_OK; +} + +static int artery_enable_hiclk(struct flash_bank *bank) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + uint32_t crm_base = series_info->crm_base; + struct target *target = bank->target; + + uint32_t crm_ctrl; + int ret = target_read_u32(target, crm_base + CRM_REG_CTRL, &crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + // High speed internal clock (HICK) is already enabled and ready. + if (crm_ctrl & CRM_CTRL_HICKSTBL) + return ERROR_OK; + + crm_ctrl |= CRM_CTRL_HICKEN; + ret = target_write_u32(target, crm_base + CRM_REG_CTRL, crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + const int64_t start_time = timeval_ms(); + + while (true) { + ret = target_read_u32(target, crm_base + CRM_REG_CTRL, &crm_ctrl); + + if (ret != ERROR_OK) + return ret; + + if (crm_ctrl & CRM_CTRL_HICKSTBL) + break; + + if ((timeval_ms() - start_time) > HICK_STABLE_TIMEOUT) { + LOG_ERROR("Timed out waiting for flash"); + return ERROR_FAIL; + } + + keep_alive(); + } + + return ERROR_OK; +} + +static int artery_usd_unlock(struct flash_bank *bank) +{ + uint32_t ctrl; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_USDULKS) + return ERROR_OK; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_USD_UNLOCK, KEY1); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_USD_UNLOCK, KEY2); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_USDULKS)) { + LOG_ERROR("Failed to unlock user system data"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int artery_usd_lock(struct flash_bank *bank) +{ + uint32_t ctrl; + + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_USDULKS)) + return ERROR_OK; + + ctrl &= ~FLASH_CTRL_USDULKS; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_USDULKS) { + LOG_ERROR("Failed to lock user system data"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +// Initialize the device for flash memory operations. +static int artery_init_flash(struct flash_bank *bank) +{ + /* + * The internal high speed clock (HICK) must be enabled before any flash + * operation is performed. + */ + int retval = artery_enable_hiclk(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to enable HICLK"); + return retval; + } + + uint32_t ctrl; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_OPLK)) + return ERROR_OK; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_UNLOCK, KEY1); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_UNLOCK, KEY2); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_OPLK) { + LOG_ERROR("Failed to initialize flash memory"); + return ERROR_FAIL; + } + + return artery_usd_unlock(bank); +} + +// Deinitialize the flash memory controller. +static int artery_deinit_flash(struct flash_bank *bank) +{ + int retval = artery_usd_lock(bank); + + if (retval != ERROR_OK) + return retval; + + uint32_t ctrl; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_CTRL_OPLK) + return ERROR_OK; + + ctrl |= FLASH_CTRL_OPLK; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) + return retval; + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) + return retval; + + if (!(ctrl & FLASH_CTRL_OPLK)) { + LOG_ERROR("Failed to lock flash"); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int artery_read_protection(struct flash_bank *bank, uint64_t *protection) +{ + uint32_t epps0; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_EPPS0, + &epps0); + + if (retval != ERROR_OK) + return retval; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + uint64_t prot = epps0; + + if (artery_series[part_info->series].has_epp_ext) { + uint32_t epps1; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_EPPS1, + &epps1); + + if (retval != ERROR_OK) + return retval; + + prot |= (((uint64_t)epps1) << 32); + } + + *protection = prot; + + return ERROR_OK; +} + +static int artery_protect_check(struct flash_bank *bank) +{ + uint64_t prot; + int retval = artery_read_protection(bank, &prot); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read flash protection settings"); + return retval; + } + + for (unsigned int i = 0; i < bank->num_prot_blocks; i++) { + const bool protected = !(prot & (UINT64_C(1) << i)); + bank->prot_blocks[i].is_protected = protected ? 1 : 0; + } + + return ERROR_OK; +} + +static int artery_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + // Clear the EPPERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_EPPERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + for (unsigned int i = first; i <= last; i++) { + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_ADDR, + bank->base + bank->sectors[i].offset); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_ADDR register"); + goto flash_deinit; + } + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, + FLASH_CTRL_SECERS | FLASH_CTRL_ERSTR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_ERASE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + goto flash_deinit; + } + + if (sts & FLASH_STS_EPPERR) { + LOG_ERROR("Sector %u is write protected", i); + retval = ERROR_FLASH_PROTECTED; + goto flash_deinit; + } + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +static int artery_usd_init(struct flash_bank *bank, uint8_t **buffer) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + uint32_t usd_size = part_info->usd_size; + + *buffer = malloc(usd_size); + + if (!*buffer) { + LOG_ERROR("Failed to allocate USD buffer"); + return ERROR_FAIL; + } + + memset(*buffer, 0xff, usd_size); + + return ERROR_OK; +} + +static int artery_usd_read(struct flash_bank *bank, uint8_t *buffer) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + + return target_read_buffer(bank->target, series_info->usd_base, + part_info->usd_size, buffer); +} + +static uint8_t artery_usd_read_buffer(const uint8_t *buffer, uint32_t base, + uint32_t offset) +{ + return buffer[base + (offset * 2)]; +} + +static int artery_usd_load(const struct artery_part_info *part_info, + const uint8_t *buffer, struct artery_usd *usd) +{ + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + uint8_t fap_level = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_FAP_INDEX], 0); + + switch (fap_level) { + case ARTERY_FAP_LEVEL_DISABLED: + case ARTERY_FAP_LEVEL_HIGH: + usd->fap_level = fap_level; + break; + default: + usd->fap_level = ARTERY_FAP_LEVEL_LOW; + } + + usd->ssb = artery_usd_read_buffer(buffer, usd_regs[ARTERY_USD_SSB_INDEX], 0); + usd->protection = 0; + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_EPP_INDEX], i); + usd->protection |= (prot << (i * 8)); + } + + if (artery_series[part_info->series].has_epp_ext) { + usd->protection_ext = 0; + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_EPP_INDEX], i); + usd->protection_ext |= (prot << (i * 8)); + } + } + + // All devices have at least two bytes of user data. + usd->data[0] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_INDEX], 0); + usd->data[1] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_INDEX], 1); + + for (unsigned int i = 0; i < part_info->usd_data_size - 2; i++) { + usd->data[i + 2] = artery_usd_read_buffer(buffer, + usd_regs[ARTERY_USD_DATA_EXT_INDEX], i); + } + + return ERROR_OK; +} + +static void artery_usd_write_buffer(uint8_t *buffer, uint32_t base, + uint32_t offset, uint8_t data) +{ + buffer[base + (offset * 2)] = data; + buffer[base + (offset * 2) + 1] = ~data; +} + +static void artery_usd_update(const struct artery_part_info *part_info, + uint8_t *buffer, const struct artery_usd *usd) +{ + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_FAP_INDEX], 0, + usd->fap_level); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_SSB_INDEX], 0, + usd->ssb); + + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = usd->protection >> (i * 8); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_EPP_INDEX], i, prot); + } + + if (artery_series[part_info->series].has_epp_ext) { + for (unsigned int i = 0; i < 4; i++) { + const uint8_t prot = usd->protection_ext >> (i * 8); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_EPP_EXT_INDEX], + i, prot); + } + } + + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_INDEX], 0, + usd->data[0]); + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_INDEX], 1, + usd->data[1]); + + for (unsigned int i = 0; i < part_info->usd_data_size - 2; i++) { + artery_usd_write_buffer(buffer, usd_regs[ARTERY_USD_DATA_EXT_INDEX], i, + usd->data[i + 2]); + } +} + +static int artery_usd_write(struct flash_bank *bank, const uint8_t *buffer) +{ + struct target *target = bank->target; + + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + // Clear the PRGMERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_PRGMERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + return retval; + } + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDPRGM; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + const target_addr_t usd_base = artery_series[part_info->series].usd_base; + const uint32_t usd_size = part_info->usd_size; + + unsigned int bytes_written = 0; + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + while (bytes_written < usd_size) { + uint32_t tmp; + memcpy(&tmp, buffer + bytes_written, sizeof(tmp)); + + if (tmp != 0xffffffff) { + retval = target_write_u32(target, usd_base + bytes_written, tmp); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write user system data"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + } + + bytes_written += 4; + } + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + return retval; + } + + if (sts & FLASH_STS_PRGMERR) { + LOG_ERROR("Failed to program user system data"); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + +static int artery_usd_erase(struct flash_bank *bank) +{ + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDERS | FLASH_CTRL_ERSTR; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + return retval; + } + + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_CTRL, &ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_CTRL register"); + return retval; + } + + return ERROR_OK; +} + +static int artery_get_fap(struct flash_bank *bank, + enum artery_fap_level *fap_level) +{ + uint32_t usd; + int retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_USD, + &usd); + + if (retval != ERROR_OK) + return retval; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const struct artery_series_info *series_info = &artery_series[part_info->series]; + + const bool fap_high = series_info->has_fap_high_level && (usd & FLASH_USD_FAP_HL); + const bool fap_low = usd & FLASH_USD_FAP; + + if (fap_high && fap_low) + *fap_level = ARTERY_FAP_LEVEL_HIGH; + else if (fap_low) + *fap_level = ARTERY_FAP_LEVEL_LOW; + else + *fap_level = ARTERY_FAP_LEVEL_DISABLED; + + return ERROR_OK; +} + +static int artery_protect(struct flash_bank *bank, int set, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + enum artery_fap_level fap_level; + int retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FAP level"); + return retval; + } + + if (fap_level != ARTERY_FAP_LEVEL_DISABLED) { + LOG_ERROR("Protection cannot be modified when FAP is active"); + return ERROR_FAIL; + } + + uint8_t *usd_buffer; + retval = artery_usd_init(bank, &usd_buffer); + + if (retval != ERROR_OK) + return retval; + + retval = artery_usd_read(bank, usd_buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read user system data"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + struct artery_usd usd; + retval = artery_usd_load(part_info, usd_buffer, &usd); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to load user system data"); + free(usd_buffer); + return retval; + } + + for (unsigned int i = first; i <= MIN(31, last); i++) { + if (bank->prot_blocks[i].is_protected == set) + continue; + + if (set) + usd.protection &= ~BIT(i); + else + usd.protection |= BIT(i); + } + + for (unsigned int i = 32; i <= last; i++) { + if (bank->prot_blocks[i].is_protected == set) + continue; + + if (set) + usd.protection_ext &= ~BIT(i - 32); + else + usd.protection_ext |= BIT(i - 32); + } + + artery_usd_update(part_info, usd_buffer, &usd); + retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + free(usd_buffer); + return retval; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to erase user system data"); + free(usd_buffer); + goto flash_deinit; + } + + retval = artery_usd_write(bank, usd_buffer); + + free(usd_buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write user system data"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +static int artery_write_without_loader(struct flash_bank *bank, + const uint8_t *buffer, uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + int retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, + FLASH_CTRL_FPRGM); + + if (retval != ERROR_OK) { + LOG_ERROR("failed to write ctrl register"); + return retval; + } + + const uint32_t block_size = 4; + + uint32_t bytes_written = 0; + target_addr_t address = bank->base + offset; + + for (uint32_t i = 0; i < count / block_size; i++) { + retval = target_write_memory(target, address, block_size, 1, + buffer + bytes_written); + + if (retval != ERROR_OK) + return retval; + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + return retval; + + address += block_size; + bytes_written += block_size; + } + + return ERROR_OK; +} + +static int artery_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = artery_init_flash(bank); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_write_without_loader(bank, buffer, offset, count); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write flash memory"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval != ERROR_OK) + return retval; + + return retval_deinit; +} + +static int artery_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } + + const struct cortex_m_common *cortex_m = target_to_cortex_m_safe(target); + + if (!cortex_m) { + LOG_ERROR("Target is not a Cortex-M device"); + return ERROR_TARGET_INVALID; + } + + struct artery_flash_bank *artery_info = bank->driver_priv; + + artery_info->probed = false; + + int retval = target_read_u32(target, DEBUG_IDCODE, &artery_info->idcode); + + if (retval != ERROR_OK) + return retval; + + const uint32_t pid = artery_info->idcode; + const bool has_fpu = cortex_m->armv7m.fp_feature != FP_NONE; + bool check_device_series = false; + enum artery_series device_series; + + /* + * The following PIDs are used for AT32F413 and AT32F415 devices. In order + * to distinguish between the series, we use the presence of the FPU. Note + * that we do not rely on the unqiue device ID (UID) which also encodes the + * device series. The reason is that the UID registers are not accessible + * when the flash access protection (FAP) is active. + */ + switch (pid) { + case 0x700301C5: + case 0x70030240: + case 0x70030242: + check_device_series = true; + device_series = has_fpu ? ARTERY_SERIES_F413 : ARTERY_SERIES_F415; + break; + default: + break; + } + + artery_info->part_info = NULL; + + for (size_t i = 0; i < ARRAY_SIZE(artery_parts); i++) { + if (check_device_series && artery_parts[i].series != device_series) + continue; + + if (artery_parts[i].pid == pid) { + artery_info->part_info = &artery_parts[i]; + break; + } + } + + if (!artery_info->part_info) { + LOG_ERROR("Cannot identify target as an Artery device"); + return ERROR_FAIL; + } + + const struct artery_part_info *part_info = artery_info->part_info; + + LOG_INFO("Device ID = 0x%08" PRIx32 " (%s)", artery_info->idcode, + part_info->name); + LOG_INFO("Flash size = %d KiB", part_info->flash_size); + + free(bank->sectors); + + bank->base = FLASH_BASE; + bank->size = part_info->flash_size * 1024; + + const unsigned int num_pages = (bank->size) / part_info->page_size; + + // Ensure that the flash infrastructure uses an alignment of 4 bytes. + bank->write_start_alignment = 4; + bank->write_end_alignment = 4; + + bank->num_sectors = num_pages; + bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); + + if (!bank->sectors) { + LOG_ERROR("Failed to allocate bank sectors"); + return ERROR_FAIL; + } + + for (unsigned int i = 0; i < bank->num_sectors; i++) { + bank->sectors[i].offset = i * part_info->page_size; + bank->sectors[i].size = part_info->page_size; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + free(bank->prot_blocks); + + /* + * Flash erase/program protection (EPPx) registers configuration for each + * device series. + * + * - AT32F403A / AT32F407 + * - AT32F413 + * + * Each bit represents a sector of 4 KiB. The last bit represents the + * entire remaining flash memory and extension area. + * + * - AT32F415 + * - AT32WB415 + * + * Each bit represents a sector of 2 KiB. The last bit represents the + * entire remaining flash memory and extension area. + * + * - AT32F421 + * - AT32F423 + * - AT32F425 + * + * Each bit represents a sector of 4 KiB. Some bits may not used + * depending on the flash memory size. The last bit represents only the + * flash memory extension area. + * + * - AT32F435 / AT32F437 + * + * This device series has an additional erase/program protection (EPP) + * register. + * + * The first 32 bits represent a flash sector of 4 KiB per bit. + * + * The additional 32 bits represent a sector of 128 KiB each. The + * second last bit covers the remaining flash memory. The last bit is + * always reserved. + * + */ + if (part_info->series == ARTERY_SERIES_F435_F437) { + // See description above. + const unsigned int num_prot_blocks_1 = 32; + const unsigned int num_prot_blocks_2 = MIN(31, DIV_ROUND_UP(part_info->flash_size - 128, 128)); + const unsigned int num_prot_blocks = num_prot_blocks_1 + num_prot_blocks_2; + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); + + if (!bank->prot_blocks) { + LOG_ERROR("Failed to allocate protection blocks"); + return ERROR_FAIL; + } + + const uint32_t prot_block_size = 4096; + + unsigned int i; + uint32_t block_offset = 0; + + for (i = 0; i < 32; i++) { + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = prot_block_size; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + + block_offset += prot_block_size; + } + + const uint32_t prot_block_size_2 = 128 * 1024; + + for (; i < (num_prot_blocks - 1); i++) { + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = prot_block_size_2; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + + block_offset += prot_block_size_2; + } + + bank->prot_blocks[i].offset = block_offset; + bank->prot_blocks[i].size = bank->size - block_offset; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } else { + uint32_t prot_block_size; + + switch (part_info->series) { + case ARTERY_SERIES_F403A_F407: + case ARTERY_SERIES_F413: + case ARTERY_SERIES_F421: + case ARTERY_SERIES_F423: + case ARTERY_SERIES_F425: + prot_block_size = 4096; + break; + case ARTERY_SERIES_F415: + case ARTERY_SERIES_WB415: + prot_block_size = 2048; + break; + default: + LOG_ERROR("Unknown Artery device series"); + return ERROR_FAIL; + } + + const unsigned int num_prot_blocks = MIN(bank->size / prot_block_size, 32); + bank->num_prot_blocks = num_prot_blocks; + bank->prot_blocks = malloc(sizeof(struct flash_sector) * num_prot_blocks); + + if (!bank->prot_blocks) { + LOG_ERROR("Failed to allocate protection blocks"); + return ERROR_FAIL; + } + + unsigned int i; + + for (i = 0; i < (num_prot_blocks - 1); i++) { + bank->prot_blocks[i].offset = i * prot_block_size; + bank->prot_blocks[i].size = prot_block_size; + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } + + bank->prot_blocks[i].offset = i * prot_block_size; + bank->prot_blocks[i].size = (bank->size - (i * prot_block_size)); + bank->prot_blocks[i].is_erased = -1; + bank->prot_blocks[i].is_protected = -1; + } + + artery_info->probed = true; + + return ERROR_OK; +} + +static int artery_auto_probe(struct flash_bank *bank) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + + if (artery_info->probed) + return ERROR_OK; + + return artery_probe(bank); +} + +static int artery_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + if (!part_info) { + command_print_sameline(cmd, "Cannot identify target device"); + return ERROR_OK; + } + + command_print_sameline(cmd, "%s - %u KiB flash", part_info->name, + part_info->flash_size); + + return ERROR_OK; +} + +static int artery_mass_erase(struct flash_bank *bank) +{ + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + // Clear the EPPERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_EPPERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + uint32_t ctrl = FLASH_CTRL_BANKERS | FLASH_CTRL_ERSTR; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_MASS_ERASE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint32_t sts; + retval = artery_read_flash_register(bank, ARTERY_FLASH_REG_STS, &sts); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read FLASH_STS register"); + goto flash_deinit; + } + + if (sts & FLASH_STS_EPPERR) { + LOG_ERROR("Mass erase operation failed"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval != ERROR_OK) + return retval; + + return retval_deinit; +} + +COMMAND_HANDLER(artery_handle_fap_enable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + + if (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP state"); + return retval; + } + + if (fap_level != ARTERY_FAP_LEVEL_DISABLED) { + command_print(CMD, "flash access protection is already enabled"); + return ERROR_FAIL; + } + + uint8_t *usd_buffer; + retval = artery_usd_init(bank, &usd_buffer); + + if (retval != ERROR_OK) + return retval; + + retval = artery_usd_read(bank, usd_buffer); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read user system data"); + return retval; + } + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + + struct artery_usd usd; + retval = artery_usd_load(part_info, usd_buffer, &usd); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to load user system data"); + return retval; + } + + usd.fap_level = ARTERY_FAP_LEVEL_LOW; + artery_usd_update(part_info, usd_buffer, &usd); + + retval = artery_init_flash(bank); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + goto flash_deinit; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + free(usd_buffer); + command_print(CMD, "failed to erase user system data"); + goto flash_deinit; + } + + retval = artery_usd_write(bank, usd_buffer); + free(usd_buffer); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to write user system data"); + goto flash_deinit; + } + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +/* + * We use a dedicated operation to perform the FAP unlock operation that only + * writes the corresponding FAP byte(s) instead of the entire user system + * data (USD) area. The reason is that directly after the FAP byte(s) are + * written, a device reset is performed and all other writes to the USD area + * would fail and generate errors. +*/ +static int artery_disable_fap(struct flash_bank *bank) +{ + int retval = artery_init_flash(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to initialize flash controller"); + return retval; + } + + retval = artery_usd_erase(bank); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to erase user system data"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + // Clear the PRGMERR bit, otherwise we may read an invalid value later on. + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_STS, + FLASH_STS_PRGMERR); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_STS register"); + goto flash_deinit; + } + + // Set the USDULKS bit to avoid locking the USD area. + uint32_t ctrl = FLASH_CTRL_USDULKS | FLASH_CTRL_USDPRGM; + retval = artery_write_flash_register(bank, ARTERY_FLASH_REG_CTRL, ctrl); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FLASH_CTRL register"); + goto flash_deinit; + } + + retval = artery_wait_flash_busy(bank, FLASH_WRITE_TIMEOUT); + + if (retval != ERROR_OK) + goto flash_deinit; + + uint16_t buffer; + + const struct artery_flash_bank *artery_info = bank->driver_priv; + const struct artery_part_info *part_info = artery_info->part_info; + const uint32_t *usd_regs = artery_series[part_info->series].usd_offsets; + + artery_usd_write_buffer((uint8_t *)&buffer, usd_regs[ARTERY_USD_FAP_INDEX], 0, + ARTERY_FAP_LEVEL_DISABLED); + + const target_addr_t usd_base = artery_series[part_info->series].usd_base; + retval = target_write_u16(bank->target, usd_base, buffer); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write FAP level"); + goto flash_deinit; + } + + /* + * Note that we do not need to deinitialize the flash memory because the + * device performed a reset anyway. + */ + + return ERROR_OK; + + int retval_deinit; +flash_deinit: + retval_deinit = artery_deinit_flash(bank); + + if (retval_deinit != ERROR_OK) + return retval_deinit; + + return retval; +} + +COMMAND_HANDLER(artery_handle_fap_disable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + + if (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP state"); + return retval; + } + + if (fap_level == ARTERY_FAP_LEVEL_DISABLED) { + command_print(CMD, "flash access protection is not enabled"); + return ERROR_FAIL; + } + + retval = artery_disable_fap(bank); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to disable flash access protection"); + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(artery_handle_fap_state_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + + if (retval != ERROR_OK) + return retval; + + enum artery_fap_level fap_level; + retval = artery_get_fap(bank, &fap_level); + + if (retval != ERROR_OK) { + command_print(CMD, "failed to read FAP level"); + return retval; + } + + const bool fap_enabled = fap_level != ARTERY_FAP_LEVEL_DISABLED; + command_print(CMD, "%u", fap_enabled); + + return ERROR_OK; +} + +COMMAND_HANDLER(artery_handle_mass_erase_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + + if (retval != ERROR_OK) + return retval; + + retval = artery_mass_erase(bank); + + if (retval != ERROR_OK) { + command_print(CMD, "Mass erase failed"); + return retval; + } + + return ERROR_OK; +} + +static const struct command_registration artery_fap_command_handlers[] = { + { + .name = "enable", + .handler = artery_handle_fap_enable_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Enable flash access protection (FAP)", + }, + { + .name = "disable", + .handler = artery_handle_fap_disable_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Disable flash access protection (FAP)", + }, + { + .name = "state", + .handler = artery_handle_fap_state_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Get the flash access protection (FAP) state", + }, + + COMMAND_REGISTRATION_DONE, +}; + +static const struct command_registration artery_exec_command_handlers[] = { + { + .name = "fap", + .mode = COMMAND_ANY, + .help = "flash access protection (FAP) command group", + .usage = "", + .chain = artery_fap_command_handlers, + }, + { + .name = "mass_erase", + .handler = artery_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "", + .help = "Erase entire flash memory", + }, + COMMAND_REGISTRATION_DONE, +}; + +static const struct command_registration artery_command_handlers[] = { + { + .name = "artery", + .mode = COMMAND_ANY, + .help = "artery flash command group", + .usage = "", + .chain = artery_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE, +}; + +const struct flash_driver artery_flash = { + .name = "artery", + .commands = artery_command_handlers, + .flash_bank_command = artery_flash_bank_command, + .erase = artery_erase, + .protect = artery_protect, + .write = artery_write, + .read = default_flash_read, + .probe = artery_probe, + .auto_probe = artery_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = artery_protect_check, + .info = artery_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/artery.h b/src/flash/nor/artery.h new file mode 100644 index 0000000000..dcfa70a6e3 --- /dev/null +++ b/src/flash/nor/artery.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2023 by Marc Schink + */ + +#ifndef OPENOCD_FLASH_NOR_ARTERY +#define OPENOCD_FLASH_NOR_ARTERY + +#define DEBUG_IDCODE 0xE0042000 + +#define FLASH_BASE 0x08000000 + +enum artery_series { + ARTERY_SERIES_F403A_F407 = 0, + ARTERY_SERIES_F413, + ARTERY_SERIES_F415, + ARTERY_SERIES_F421, + ARTERY_SERIES_F423, + ARTERY_SERIES_F425, + ARTERY_SERIES_F435_F437, + ARTERY_SERIES_WB415, +}; + +enum artery_flash_reg_index { + ARTERY_FLASH_REG_PSR = 0, + ARTERY_FLASH_REG_UNLOCK, + ARTERY_FLASH_REG_USD_UNLOCK, + ARTERY_FLASH_REG_STS, + ARTERY_FLASH_REG_CTRL, + ARTERY_FLASH_REG_ADDR, + ARTERY_FLASH_REG_USD, + ARTERY_FLASH_REG_EPPS0, + ARTERY_FLASH_REG_EPPS1, + ARTERY_FLASH_REG_INDEX_NUM, +}; + +enum artery_usd_reg_index { + ARTERY_USD_FAP_INDEX = 0, + ARTERY_USD_SSB_INDEX, + ARTERY_USD_DATA_INDEX, + ARTERY_USD_EPP_INDEX, + ARTERY_USD_EPP_EXT_INDEX, + ARTERY_USD_DATA_EXT_INDEX, + ARTERY_USD_INDEX_NUM, +}; + +enum artery_fap_level { + ARTERY_FAP_LEVEL_DISABLED = 0xa5, + ARTERY_FAP_LEVEL_LOW = 0xff, + ARTERY_FAP_LEVEL_HIGH = 0xcc, +}; + +struct artery_part_info { + uint32_t pid; + const char *name; + enum artery_series series; + // Flash size in bytes. + uint32_t flash_size; + // Page / sector size in bytes. + uint32_t page_size; + // User system data (USD) area size including the inverse bytes. + uint32_t usd_size; + // User data area (part of the USD) size excluding the inverse bytes. + uint32_t usd_data_size; +}; + +struct artery_flash_bank { + bool probed; + uint32_t idcode; + const struct artery_part_info *part_info; +}; + +struct artery_series_info { + bool has_fap_high_level; + bool has_epp_ext; + uint32_t flash_regs_base; + const uint32_t *flash_regs; + uint32_t crm_base; + uint32_t usd_base; + const uint32_t *usd_offsets; +}; + +#define ARTERY_USD_DATA_MAX_SIZE 2012 + +struct artery_usd { + enum artery_fap_level fap_level; + uint8_t ssb; + uint32_t protection; + uint32_t protection_ext; + uint8_t data[ARTERY_USD_DATA_MAX_SIZE]; +}; + +#define CRM_REG_CTRL 0x000 + +/* CRM_CTRL register bits. */ +#define CRM_CTRL_HICKSTBL BIT(0) +#define CRM_CTRL_HICKEN BIT(1) + +/* FLASH_CTRL register bits. */ +#define FLASH_CTRL_USDULKS BIT(9) +#define FLASH_CTRL_OPLK BIT(7) +#define FLASH_CTRL_ERSTR BIT(6) +#define FLASH_CTRL_USDERS BIT(5) +#define FLASH_CTRL_USDPRGM BIT(4) +#define FLASH_CTRL_BANKERS BIT(2) +#define FLASH_CTRL_SECERS BIT(1) +#define FLASH_CTRL_FPRGM BIT(0) + +/* FLASH_STS register bits. */ +#define FLASH_STS_OBF BIT(0) +#define FLASH_STS_PRGMERR BIT(2) +#define FLASH_STS_EPPERR BIT(4) +#define FLASH_STS_ODF BIT(5) + +/* FLASH_USD register bits. */ +#define FLASH_USD_FAP BIT(1) +#define FLASH_USD_FAP_HL BIT(26) + +#define FLASH_USD_SSB_OFFSET 2 +#define FLASH_USD_USER_D0_OFFSET 10 +#define FLASH_USD_USER_D1_OFFSET 18 + +/* Flash and USD unlock keys. */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +#endif /* OPENOCD_FLASH_NOR_ARTERY */ diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index b86a18da75..5f551681d5 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -2040,40 +2040,39 @@ static int efc_start_command(struct sam3_bank_private *private, /* Check command & argument */ switch (command) { - - case AT91C_EFC_FCMD_WP: - case AT91C_EFC_FCMD_WPL: - case AT91C_EFC_FCMD_EWP: - case AT91C_EFC_FCMD_EWPL: - /* case AT91C_EFC_FCMD_EPL: */ - /* case AT91C_EFC_FCMD_EPA: */ - case AT91C_EFC_FCMD_SLB: - case AT91C_EFC_FCMD_CLB: - n = (private->size_bytes / private->page_size); - if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); - break; - - case AT91C_EFC_FCMD_SFB: - case AT91C_EFC_FCMD_CFB: - if (argument >= private->chip->details.n_gpnvms) { - LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - private->chip->details.n_gpnvms); - } - break; - - case AT91C_EFC_FCMD_GETD: - case AT91C_EFC_FCMD_EA: - case AT91C_EFC_FCMD_GLB: - case AT91C_EFC_FCMD_GFB: - case AT91C_EFC_FCMD_STUI: - case AT91C_EFC_FCMD_SPUI: - if (argument != 0) - LOG_ERROR("Argument is meaningless for cmd: %d", command); - break; - default: - LOG_ERROR("Unknown command %d", command); - break; + case AT91C_EFC_FCMD_WP: + case AT91C_EFC_FCMD_WPL: + case AT91C_EFC_FCMD_EWP: + case AT91C_EFC_FCMD_EWPL: + /* case AT91C_EFC_FCMD_EPL: */ + /* case AT91C_EFC_FCMD_EPA: */ + case AT91C_EFC_FCMD_SLB: + case AT91C_EFC_FCMD_CLB: + n = (private->size_bytes / private->page_size); + if (argument >= n) + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); + break; + + case AT91C_EFC_FCMD_SFB: + case AT91C_EFC_FCMD_CFB: + if (argument >= private->chip->details.n_gpnvms) { + LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", + private->chip->details.n_gpnvms); + } + break; + + case AT91C_EFC_FCMD_GETD: + case AT91C_EFC_FCMD_EA: + case AT91C_EFC_FCMD_GLB: + case AT91C_EFC_FCMD_GFB: + case AT91C_EFC_FCMD_STUI: + case AT91C_EFC_FCMD_SPUI: + if (argument != 0) + LOG_ERROR("Argument is meaningless for cmd: %d", command); + break; + default: + LOG_ERROR("Unknown command %d", command); + break; } if (command == AT91C_EFC_FCMD_SPUI) { @@ -2571,18 +2570,18 @@ static void sam3_explain_ckgr_mor(struct sam3_chip *chip) chip->cfg.rc_freq = 0; if (rcen) { switch (v) { - default: - chip->cfg.rc_freq = 0; - break; - case 0: - chip->cfg.rc_freq = 4 * 1000 * 1000; - break; - case 1: - chip->cfg.rc_freq = 8 * 1000 * 1000; - break; - case 2: - chip->cfg.rc_freq = 12 * 1000 * 1000; - break; + case 0: + chip->cfg.rc_freq = 4 * 1000 * 1000; + break; + case 1: + chip->cfg.rc_freq = 8 * 1000 * 1000; + break; + case 2: + chip->cfg.rc_freq = 12 * 1000 * 1000; + break; + default: + chip->cfg.rc_freq = 0; + break; } } @@ -2683,30 +2682,30 @@ static void sam3_explain_mckr(struct sam3_chip *chip) css = sam3_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { - case 0: - fin = chip->cfg.slow_freq; - cp = "slowclk"; - break; - case 1: - fin = chip->cfg.mainosc_freq; - cp = "mainosc"; - break; - case 2: - fin = chip->cfg.plla_freq; - cp = "plla"; - break; - case 3: - if (chip->cfg.CKGR_UCKR & (1 << 16)) { - fin = 480 * 1000 * 1000; - cp = "upll"; - } else { - fin = 0; - cp = "upll (*ERROR* UPLL is disabled)"; - } - break; - default: - assert(0); - break; + case 0: + fin = chip->cfg.slow_freq; + cp = "slowclk"; + break; + case 1: + fin = chip->cfg.mainosc_freq; + cp = "mainosc"; + break; + case 2: + fin = chip->cfg.plla_freq; + cp = "plla"; + break; + case 3: + if (chip->cfg.CKGR_UCKR & (1 << 16)) { + fin = 480 * 1000 * 1000; + cp = "upll"; + } else { + fin = 0; + cp = "upll (*ERROR* UPLL is disabled)"; + } + break; + default: + assert(0); + break; } LOG_USER("%s (%3.03f Mhz)", @@ -2714,41 +2713,41 @@ static void sam3_explain_mckr(struct sam3_chip *chip) _tomhz(fin)); pres = sam3_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { - case 0: - pdiv = 1; - cp = "selected clock"; - break; - case 1: - pdiv = 2; - cp = "clock/2"; - break; - case 2: - pdiv = 4; - cp = "clock/4"; - break; - case 3: - pdiv = 8; - cp = "clock/8"; - break; - case 4: - pdiv = 16; - cp = "clock/16"; - break; - case 5: - pdiv = 32; - cp = "clock/32"; - break; - case 6: - pdiv = 64; - cp = "clock/64"; - break; - case 7: - pdiv = 6; - cp = "clock/6"; - break; - default: - assert(0); - break; + case 0: + pdiv = 1; + cp = "selected clock"; + break; + case 1: + pdiv = 2; + cp = "clock/2"; + break; + case 2: + pdiv = 4; + cp = "clock/4"; + break; + case 3: + pdiv = 8; + cp = "clock/8"; + break; + case 4: + pdiv = 16; + cp = "clock/16"; + break; + case 5: + pdiv = 32; + cp = "clock/32"; + break; + case 6: + pdiv = 64; + cp = "clock/64"; + break; + case 7: + pdiv = 6; + cp = "clock/6"; + break; + default: + assert(0); + break; } LOG_USER("(%s)", cp); fin = fin / pdiv; @@ -3011,39 +3010,39 @@ FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) } switch (bank->base) { - default: - LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x " - "[at91sam3u series] or 0x%08x [at91sam3s series] or " - "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", - ((unsigned int)(bank->base)), - ((unsigned int)(FLASH_BANK0_BASE_U)), - ((unsigned int)(FLASH_BANK1_BASE_U)), - ((unsigned int)(FLASH_BANK_BASE_S)), - ((unsigned int)(FLASH_BANK_BASE_N)), - ((unsigned int)(FLASH_BANK0_BASE_AX)), - ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), - ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); - return ERROR_FAIL; - - /* at91sam3s and at91sam3n series only has bank 0*/ - /* at91sam3u and at91sam3ax series has the same address for bank 0*/ - case FLASH_BANK_BASE_S: - case FLASH_BANK0_BASE_U: - bank->driver_priv = &(chip->details.bank[0]); - bank->bank_number = 0; - chip->details.bank[0].chip = chip; - chip->details.bank[0].bank = bank; - break; - - /* Bank 1 of at91sam3u or at91sam3ax series */ - case FLASH_BANK1_BASE_U: - case FLASH_BANK1_BASE_256K_AX: - case FLASH_BANK1_BASE_512K_AX: - bank->driver_priv = &(chip->details.bank[1]); - bank->bank_number = 1; - chip->details.bank[1].chip = chip; - chip->details.bank[1].bank = bank; - break; + /* at91sam3s and at91sam3n series only has bank 0*/ + /* at91sam3u and at91sam3ax series has the same address for bank 0*/ + case FLASH_BANK_BASE_S: + case FLASH_BANK0_BASE_U: + bank->driver_priv = &chip->details.bank[0]; + bank->bank_number = 0; + chip->details.bank[0].chip = chip; + chip->details.bank[0].bank = bank; + break; + + /* Bank 1 of at91sam3u or at91sam3ax series */ + case FLASH_BANK1_BASE_U: + case FLASH_BANK1_BASE_256K_AX: + case FLASH_BANK1_BASE_512K_AX: + bank->driver_priv = &chip->details.bank[1]; + bank->bank_number = 1; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; + break; + + default: + LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08x or 0x%08x " + "[at91sam3u series] or 0x%08x [at91sam3s series] or " + "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", + bank->base, + FLASH_BANK0_BASE_U, + FLASH_BANK1_BASE_U, + FLASH_BANK_BASE_S, + FLASH_BANK_BASE_N, + FLASH_BANK0_BASE_AX, + FLASH_BANK1_BASE_256K_AX, + FLASH_BANK1_BASE_512K_AX); + return ERROR_FAIL; } /* we initialize after probing. */ @@ -3574,22 +3573,22 @@ COMMAND_HANDLER(sam3_handle_gpnvm_command) } switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) { who = -1; - break; - case 2: - if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("show", CMD_ARGV[0]) == 0) { @@ -3641,26 +3640,26 @@ COMMAND_HANDLER(sam3_handle_slowclk_command) return ERROR_OK; switch (CMD_ARGC) { - case 0: - /* show */ - break; - case 1: - { - /* set */ - uint32_t v; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); - if (v > 200000) { - /* absurd slow clock of 200Khz? */ - command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - chip->cfg.slow_freq = v; - break; - } - default: - /* error */ - command_print(CMD, "Too many parameters"); + case 0: + /* show */ + break; + case 1: + { + /* set */ + uint32_t v; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); + if (v > 200000) { + /* absurd slow clock of 200Khz? */ + command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; + } + chip->cfg.slow_freq = v; + break; + } + default: + /* error */ + command_print(CMD, "Too many parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 26a803784d..dd3a1ca3f0 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -1490,40 +1490,39 @@ static int efc_start_command(struct sam4_bank_private *private, /* Check command & argument */ switch (command) { - - case AT91C_EFC_FCMD_WP: - case AT91C_EFC_FCMD_WPL: - case AT91C_EFC_FCMD_EWP: - case AT91C_EFC_FCMD_EWPL: - /* case AT91C_EFC_FCMD_EPL: */ - case AT91C_EFC_FCMD_EPA: - case AT91C_EFC_FCMD_SLB: - case AT91C_EFC_FCMD_CLB: - n = (private->size_bytes / private->page_size); - if (argument >= n) - LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); - break; - - case AT91C_EFC_FCMD_SFB: - case AT91C_EFC_FCMD_CFB: - if (argument >= private->chip->details.n_gpnvms) { - LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", - private->chip->details.n_gpnvms); - } - break; - - case AT91C_EFC_FCMD_GETD: - case AT91C_EFC_FCMD_EA: - case AT91C_EFC_FCMD_GLB: - case AT91C_EFC_FCMD_GFB: - case AT91C_EFC_FCMD_STUI: - case AT91C_EFC_FCMD_SPUI: - if (argument != 0) - LOG_ERROR("Argument is meaningless for cmd: %d", command); - break; - default: - LOG_ERROR("Unknown command %d", command); - break; + case AT91C_EFC_FCMD_WP: + case AT91C_EFC_FCMD_WPL: + case AT91C_EFC_FCMD_EWP: + case AT91C_EFC_FCMD_EWPL: + /* case AT91C_EFC_FCMD_EPL: */ + case AT91C_EFC_FCMD_EPA: + case AT91C_EFC_FCMD_SLB: + case AT91C_EFC_FCMD_CLB: + n = (private->size_bytes / private->page_size); + if (argument >= n) + LOG_ERROR("*BUG*: Embedded flash has only %" PRIu32 " pages", n); + break; + + case AT91C_EFC_FCMD_SFB: + case AT91C_EFC_FCMD_CFB: + if (argument >= private->chip->details.n_gpnvms) { + LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", + private->chip->details.n_gpnvms); + } + break; + + case AT91C_EFC_FCMD_GETD: + case AT91C_EFC_FCMD_EA: + case AT91C_EFC_FCMD_GLB: + case AT91C_EFC_FCMD_GFB: + case AT91C_EFC_FCMD_STUI: + case AT91C_EFC_FCMD_SPUI: + if (argument != 0) + LOG_ERROR("Argument is meaningless for cmd: %d", command); + break; + default: + LOG_ERROR("Unknown command %d", command); + break; } if (command == AT91C_EFC_FCMD_SPUI) { @@ -1678,21 +1677,21 @@ static int flashd_erase_pages(struct sam4_bank_private *private, LOG_DEBUG("Here"); uint8_t erase_pages; switch (num_pages) { - case 4: - erase_pages = 0x00; - break; - case 8: - erase_pages = 0x01; - break; - case 16: - erase_pages = 0x02; - break; - case 32: - erase_pages = 0x03; - break; - default: - erase_pages = 0x00; - break; + case 4: + erase_pages = 0x00; + break; + case 8: + erase_pages = 0x01; + break; + case 16: + erase_pages = 0x02; + break; + case 32: + erase_pages = 0x03; + break; + default: + erase_pages = 0x00; + break; } /* AT91C_EFC_FCMD_EPA @@ -2080,18 +2079,18 @@ static void sam4_explain_ckgr_mor(struct sam4_chip *chip) chip->cfg.rc_freq = 0; if (rcen) { switch (v) { - default: - chip->cfg.rc_freq = 0; - break; - case 0: - chip->cfg.rc_freq = 4 * 1000 * 1000; - break; - case 1: - chip->cfg.rc_freq = 8 * 1000 * 1000; - break; - case 2: - chip->cfg.rc_freq = 12 * 1000 * 1000; - break; + case 0: + chip->cfg.rc_freq = 4 * 1000 * 1000; + break; + case 1: + chip->cfg.rc_freq = 8 * 1000 * 1000; + break; + case 2: + chip->cfg.rc_freq = 12 * 1000 * 1000; + break; + default: + chip->cfg.rc_freq = 0; + break; } } @@ -2192,30 +2191,30 @@ static void sam4_explain_mckr(struct sam4_chip *chip) css = sam4_reg_fieldname(chip, "CSS", chip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { - case 0: - fin = chip->cfg.slow_freq; - cp = "slowclk"; - break; - case 1: - fin = chip->cfg.mainosc_freq; - cp = "mainosc"; - break; - case 2: - fin = chip->cfg.plla_freq; - cp = "plla"; - break; - case 3: - if (chip->cfg.CKGR_UCKR & (1 << 16)) { - fin = 480 * 1000 * 1000; - cp = "upll"; - } else { - fin = 0; - cp = "upll (*ERROR* UPLL is disabled)"; - } - break; - default: - assert(0); - break; + case 0: + fin = chip->cfg.slow_freq; + cp = "slowclk"; + break; + case 1: + fin = chip->cfg.mainosc_freq; + cp = "mainosc"; + break; + case 2: + fin = chip->cfg.plla_freq; + cp = "plla"; + break; + case 3: + if (chip->cfg.CKGR_UCKR & (1 << 16)) { + fin = 480 * 1000 * 1000; + cp = "upll"; + } else { + fin = 0; + cp = "upll (*ERROR* UPLL is disabled)"; + } + break; + default: + assert(0); + break; } LOG_USER("%s (%3.03f Mhz)", @@ -2223,41 +2222,41 @@ static void sam4_explain_mckr(struct sam4_chip *chip) _tomhz(fin)); pres = sam4_reg_fieldname(chip, "PRES", chip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { - case 0: - pdiv = 1; - cp = "selected clock"; - break; - case 1: - pdiv = 2; - cp = "clock/2"; - break; - case 2: - pdiv = 4; - cp = "clock/4"; - break; - case 3: - pdiv = 8; - cp = "clock/8"; - break; - case 4: - pdiv = 16; - cp = "clock/16"; - break; - case 5: - pdiv = 32; - cp = "clock/32"; - break; - case 6: - pdiv = 64; - cp = "clock/64"; - break; - case 7: - pdiv = 6; - cp = "clock/6"; - break; - default: - assert(0); - break; + case 0: + pdiv = 1; + cp = "selected clock"; + break; + case 1: + pdiv = 2; + cp = "clock/2"; + break; + case 2: + pdiv = 4; + cp = "clock/4"; + break; + case 3: + pdiv = 8; + cp = "clock/8"; + break; + case 4: + pdiv = 16; + cp = "clock/16"; + break; + case 5: + pdiv = 32; + cp = "clock/32"; + break; + case 6: + pdiv = 64; + cp = "clock/64"; + break; + case 7: + pdiv = 6; + cp = "clock/6"; + break; + default: + assert(0); + break; } LOG_USER("(%s)", cp); fin = fin / pdiv; @@ -2504,32 +2503,32 @@ FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) } switch (bank->base) { - default: - LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x" - "[at91sam4s series] )", - ((unsigned int)(bank->base)), - ((unsigned int)(FLASH_BANK_BASE_S))); - return ERROR_FAIL; - - /* at91sam4s series only has bank 0*/ - /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ - case FLASH_BANK_BASE_S: - case FLASH_BANK_BASE_C: - bank->driver_priv = &(chip->details.bank[0]); - bank->bank_number = 0; - chip->details.bank[0].chip = chip; - chip->details.bank[0].bank = bank; - break; - - /* Bank 1 of at91sam4sd/at91sam4c32 series */ - case FLASH_BANK1_BASE_1024K_SD: - case FLASH_BANK1_BASE_2048K_SD: - case FLASH_BANK1_BASE_C32: - bank->driver_priv = &(chip->details.bank[1]); - bank->bank_number = 1; - chip->details.bank[1].chip = chip; - chip->details.bank[1].bank = bank; - break; + /* at91sam4s series only has bank 0*/ + /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ + case FLASH_BANK_BASE_S: + case FLASH_BANK_BASE_C: + bank->driver_priv = &chip->details.bank[0]; + bank->bank_number = 0; + chip->details.bank[0].chip = chip; + chip->details.bank[0].bank = bank; + break; + + /* Bank 1 of at91sam4sd/at91sam4c32 series */ + case FLASH_BANK1_BASE_1024K_SD: + case FLASH_BANK1_BASE_2048K_SD: + case FLASH_BANK1_BASE_C32: + bank->driver_priv = &chip->details.bank[1]; + bank->bank_number = 1; + chip->details.bank[1].chip = chip; + chip->details.bank[1].bank = bank; + break; + + default: + LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08x" + "[at91sam4s series] )", + bank->base, + FLASH_BANK_BASE_S); + return ERROR_FAIL; } /* we initialize after probing. */ @@ -3122,22 +3121,22 @@ COMMAND_HANDLER(sam4_handle_gpnvm_command) } switch (CMD_ARGC) { - default: - return ERROR_COMMAND_SYNTAX_ERROR; - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) { who = -1; - break; - case 2: - if ((strcmp(CMD_ARGV[0], "show") == 0) && (strcmp(CMD_ARGV[1], "all") == 0)) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (strcmp("show", CMD_ARGV[0]) == 0) { @@ -3189,26 +3188,26 @@ COMMAND_HANDLER(sam4_handle_slowclk_command) return ERROR_OK; switch (CMD_ARGC) { - case 0: - /* show */ - break; - case 1: - { - /* set */ - uint32_t v; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); - if (v > 200000) { - /* absurd slow clock of 200Khz? */ - command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); - return ERROR_COMMAND_SYNTAX_ERROR; - } - chip->cfg.slow_freq = v; - break; - } - default: - /* error */ - command_print(CMD, "Too many parameters"); + case 0: + /* show */ + break; + case 1: + { + /* set */ + uint32_t v; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); + if (v > 200000) { + /* absurd slow clock of 200Khz? */ + command_print(CMD, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; + } + chip->cfg.slow_freq = v; + break; + } + default: + /* error */ + command_print(CMD, "Too many parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD, "Slowclk freq: %d.%03dkhz", (int)(chip->cfg.slow_freq / 1000), diff --git a/src/flash/nor/at91sam4l.c b/src/flash/nor/at91sam4l.c index ddf42a8c5f..1db15377eb 100644 --- a/src/flash/nor/at91sam4l.c +++ b/src/flash/nor/at91sam4l.c @@ -282,19 +282,19 @@ static int sam4l_probe(struct flash_bank *bank) chip->ram_kb = sam4l_ram_sizes[0xF & (id >> 16)]; switch (0xF & (id >> 8)) { - case 0x07: - chip->flash_kb = 128; - break; - case 0x09: - chip->flash_kb = 256; - break; - case 0x0A: - chip->flash_kb = 512; - break; - default: - LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id); - chip->flash_kb = 128; - break; + case 0x07: + chip->flash_kb = 128; + break; + case 0x09: + chip->flash_kb = 256; + break; + case 0x0A: + chip->flash_kb = 512; + break; + default: + LOG_ERROR("Unknown flash size (chip ID is %08" PRIx32 "), assuming 128K", id); + chip->flash_kb = 128; + break; } /* Retrieve the Flash parameters */ diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 86c80765fc..a4c92a93c6 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -193,44 +193,41 @@ static void at91sam7_read_clock_info(struct flash_bank *bank) at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; switch (mckr & PMC_MCKR_CSS) { - case 0: /* Slow Clock */ + case 0: /* Slow Clock */ + at91sam7_info->mck_valid = 1; + tmp = RC_FREQ; + break; + + case 1: /* Main Clock */ + if ((mcfr & CKGR_MCFR_MAINRDY) && at91sam7_info->ext_freq == 0) { at91sam7_info->mck_valid = 1; - tmp = RC_FREQ; - break; - - case 1: /* Main Clock */ - if ((mcfr & CKGR_MCFR_MAINRDY) && - (at91sam7_info->ext_freq == 0)) { - at91sam7_info->mck_valid = 1; - tmp = RC_FREQ / 16ul * (mcfr & 0xffff); - } else if (at91sam7_info->ext_freq != 0) { - at91sam7_info->mck_valid = 1; - tmp = at91sam7_info->ext_freq; - } - break; - - case 2: /* Reserved */ - break; - - case 3: /* PLL Clock */ - if ((mcfr & CKGR_MCFR_MAINRDY) && - (at91sam7_info->ext_freq == 0)) { - target_read_u32(target, CKGR_PLLR, &pllr); - if (!(pllr & CKGR_PLLR_DIV)) - break; /* 0 Hz */ - at91sam7_info->mck_valid = 1; - mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); - /* Integer arithmetic should have sufficient precision - * as long as PLL is properly configured. */ - tmp = mainfreq / (pllr & CKGR_PLLR_DIV)* - (((pllr & CKGR_PLLR_MUL) >> 16) + 1); - } else if ((at91sam7_info->ext_freq != 0) && - ((pllr&CKGR_PLLR_DIV) != 0)) { - at91sam7_info->mck_valid = 1; - tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)* - (((pllr & CKGR_PLLR_MUL) >> 16) + 1); - } - break; + tmp = RC_FREQ / 16ul * (mcfr & 0xffff); + } else if (at91sam7_info->ext_freq != 0) { + at91sam7_info->mck_valid = 1; + tmp = at91sam7_info->ext_freq; + } + break; + + case 2: /* Reserved */ + break; + + case 3: /* PLL Clock */ + if ((mcfr & CKGR_MCFR_MAINRDY) && at91sam7_info->ext_freq == 0) { + target_read_u32(target, CKGR_PLLR, &pllr); + if (!(pllr & CKGR_PLLR_DIV)) + break; /* 0 Hz */ + at91sam7_info->mck_valid = 1; + mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); + /* Integer arithmetic should have sufficient precision + * as long as PLL is properly configured. */ + tmp = mainfreq / (pllr & CKGR_PLLR_DIV) * + (((pllr & CKGR_PLLR_MUL) >> 16) + 1); + } else if ((at91sam7_info->ext_freq != 0) && ((pllr & CKGR_PLLR_DIV) != 0)) { + at91sam7_info->mck_valid = 1; + tmp = at91sam7_info->ext_freq / (pllr & CKGR_PLLR_DIV) * + (((pllr & CKGR_PLLR_MUL) >> 16) + 1); + } + break; } /* Prescaler adjust */ @@ -277,7 +274,7 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode) if (at91sam7_info->mck_freq > 30000000ul) fws = 1; - LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn)); + LOG_DEBUG("fmcn[%u]: %" PRIu32, bank->bank_number, fmcn); fmr = fmcn << 16 | fws << 8; target_write_u32(target, mc_fmr[bank->bank_number], fmr); } @@ -291,14 +288,14 @@ static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t wait while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0)) { - LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status); + LOG_DEBUG("status[%u]: 0x%" PRIx32, bank->bank_number, status); alive_sleep(1); } - LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status); + LOG_DEBUG("status[%u]: 0x%" PRIx32, bank->bank_number, status); if (status & 0x0C) { - LOG_ERROR("status register: 0x%" PRIx32 "", status); + LOG_ERROR("status register: 0x%" PRIx32, status); if (status & 0x4) LOG_ERROR("Lock Error Bit Detected, Operation Abort"); if (status & 0x8) @@ -319,7 +316,7 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd; target_write_u32(target, mc_fcr[bank->bank_number], fcr); - LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", + LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %u, page number: %" PRIu16, fcr, bank->bank_number + 1, pagen); @@ -418,130 +415,130 @@ static int at91sam7_read_part_info(struct flash_bank *bank) /* check flash size */ switch ((cidr >> 8)&0x000F) { - case FLASH_SIZE_8KB: - break; - - case FLASH_SIZE_16KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 32; - page_size = 64; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S161/16"; - } - break; - - case FLASH_SIZE_32KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 32; - page_size = 128; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S321/32"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE32"; - } - break; - - case FLASH_SIZE_64KB: - banks_num = 1; - sectors_num = 16; - pages_per_sector = 32; - page_size = 128; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S64"; - } - break; - - case FLASH_SIZE_128KB: - banks_num = 1; - sectors_num = 8; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S128"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC128"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE128"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X128"; - } - break; - - case FLASH_SIZE_256KB: - banks_num = 1; - sectors_num = 16; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x60) { - num_nvmbits = 3; - target_name_t = "AT91SAM7A3"; - } - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S256"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC256"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE256"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X256"; - } - break; - - case FLASH_SIZE_512KB: - banks_num = 2; - sectors_num = 16; - pages_per_sector = 64; - page_size = 256; - base_address = 0x00100000; - if (arch == 0x70) { - num_nvmbits = 2; - target_name_t = "AT91SAM7S512"; - } - if (arch == 0x71) { - num_nvmbits = 3; - target_name_t = "AT91SAM7XC512"; - } - if (arch == 0x72) { - num_nvmbits = 3; - target_name_t = "AT91SAM7SE512"; - } - if (arch == 0x75) { - num_nvmbits = 3; - target_name_t = "AT91SAM7X512"; - } - break; + case FLASH_SIZE_8KB: + break; + + case FLASH_SIZE_16KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 32; + page_size = 64; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S161/16"; + } + break; + + case FLASH_SIZE_32KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 32; + page_size = 128; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S321/32"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE32"; + } + break; + + case FLASH_SIZE_64KB: + banks_num = 1; + sectors_num = 16; + pages_per_sector = 32; + page_size = 128; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S64"; + } + break; + + case FLASH_SIZE_128KB: + banks_num = 1; + sectors_num = 8; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S128"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC128"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE128"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X128"; + } + break; + + case FLASH_SIZE_256KB: + banks_num = 1; + sectors_num = 16; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x60) { + num_nvmbits = 3; + target_name_t = "AT91SAM7A3"; + } + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S256"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC256"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE256"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X256"; + } + break; + + case FLASH_SIZE_512KB: + banks_num = 2; + sectors_num = 16; + pages_per_sector = 64; + page_size = 256; + base_address = 0x00100000; + if (arch == 0x70) { + num_nvmbits = 2; + target_name_t = "AT91SAM7S512"; + } + if (arch == 0x71) { + num_nvmbits = 3; + target_name_t = "AT91SAM7XC512"; + } + if (arch == 0x72) { + num_nvmbits = 3; + target_name_t = "AT91SAM7SE512"; + } + if (arch == 0x75) { + num_nvmbits = 3; + target_name_t = "AT91SAM7X512"; + } + break; - case FLASH_SIZE_1024KB: - break; + case FLASH_SIZE_1024KB: + break; - case FLASH_SIZE_2048KB: - break; + case FLASH_SIZE_2048KB: + break; } if (strcmp(target_name_t, "Unknown") == 0) { @@ -915,7 +912,7 @@ static int at91sam7_write(struct flash_bank *bank, const uint8_t *buffer, uint32 dst_min_alignment = at91sam7_info->pagesize; if (offset % dst_min_alignment) { - LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", + LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index d6d8938b67..de0b7dd1d2 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -12,6 +12,9 @@ * atsamv, atsams, and atsame support * Copyright (C) 2015 Morgan Quigley * + * atsamv extension of user signature area + * Copyright (C) 2024-2025 Elektroline Inc. + * * Some of the lower level code was based on code supplied by * ATMEL under BSD-Source-Code License and this copyright. * ATMEL Microcontroller Software Support @@ -24,6 +27,7 @@ #include "imp.h" #include +#include #define REG_NAME_WIDTH (12) @@ -40,18 +44,39 @@ #define SAMV_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define SAMV_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define SAMV_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ +#define SAMV_EFC_FCMD_WUS (0x12) /* (EFC) Write User Signature */ +#define SAMV_EFC_FCMD_EUS (0x13) /* (EFC) Erase User Signature */ +#define SAMV_EFC_FCMD_STUS (0x14) /* (EFC) Start Read User Signature */ +#define SAMV_EFC_FCMD_SPUS (0x15) /* (EFC) Stop Read User Signature */ + +#define SAMV_EFC_FMR_SCOD BIT(16) /* Sequantial Code Optimalization Disable */ + +#define SAMV_EFC_FSR_FRDY_SET 1 +#define SAMV_EFC_FRS_FRDY_CLR 0 #define OFFSET_EFC_FMR 0 #define OFFSET_EFC_FCR 4 #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 +#define TIMEOUT_MS_FRS_CHANGE 10 /* Timeout for FRS ready bit change */ +#define TIMEOUT_MS_CMD_DEFAULT 50 /* Default timeout for command */ +#define TIMEOUT_MS_CMD_ERASE 24000 /* Timeout for erase commands */ + #define SAMV_CHIPID_CIDR (0x400E0940) #define SAMV_NUM_GPNVM_BITS 9 #define SAMV_CONTROLLER_ADDR (0x400e0c00) #define SAMV_SECTOR_SIZE 16384 #define SAMV_PAGE_SIZE 512 #define SAMV_FLASH_BASE 0x00400000 +/* This is a workaround. Flash Signature area is actually located at the + * beginning of the flash memory at the address range overlapping the + * first page of program flash. Since OpenOCD does not support write to + * a bank outside of address range, we use address above maximum 32-bit + * address space. + */ +#define SAMV_FLASH_SIGNATURE_BASE 0x100000000 +#define SAMV_FLASH_SIGNATURE_SIZE SAMV_PAGE_SIZE struct samv_flash_bank { bool probed; @@ -59,6 +84,7 @@ struct samv_flash_bank { unsigned int gpnvm[SAMV_NUM_GPNVM_BITS]; }; + /* The actual sector size of the SAMV7 flash memory is 128K bytes. * 16 sectors for a 2048KB device. The lock regions are 16KB per lock * region, with a 2048KB device having 128 lock regions. @@ -72,6 +98,36 @@ static int samv_efc_get_status(struct target *target, uint32_t *v) return r; } +static int samv_efc_wait_status(struct target *target, uint8_t desired, + int64_t timeout, uint32_t *status) +{ + uint32_t v; + int64_t ms_now, ms_end; + int r; + + if (status) + *status = 0; + + ms_end = timeout + timeval_ms(); + + do { + r = samv_efc_get_status(target, &v); + if (r != ERROR_OK) + return r; + + if (status) + *status = v; + ms_now = timeval_ms(); + if (ms_now > ms_end) { + /* error */ + LOG_ERROR("Command timeout"); + return ERROR_FLASH_BUSY; + } + } while ((v & 1) != desired); + + return ERROR_OK; +} + static int samv_efc_get_result(struct target *target, uint32_t *v) { uint32_t rv; @@ -81,15 +137,20 @@ static int samv_efc_get_result(struct target *target, uint32_t *v) return r; } +static inline int samv_efc_get_mode(struct target *target, uint32_t *v) +{ + return target_read_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v); +} + +static inline int samv_efc_set_mode(struct target *target, uint32_t v) +{ + return target_write_u32(target, SAMV_CONTROLLER_ADDR + OFFSET_EFC_FMR, v); +} + static int samv_efc_start_command(struct target *target, - unsigned int command, unsigned int argument) + uint8_t command, unsigned int argument) { uint32_t v; - samv_efc_get_status(target, &v); - if (!(v & 1)) { - LOG_ERROR("flash controller is not ready"); - return ERROR_FAIL; - } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("starting flash command: 0x%08x", (unsigned int)(v)); @@ -100,32 +161,33 @@ static int samv_efc_start_command(struct target *target, } static int samv_efc_perform_command(struct target *target, - unsigned int command, unsigned int argument, uint32_t *status) + uint8_t command, unsigned int argument, uint32_t *status) { int r; uint32_t v; - int64_t ms_now, ms_end; + int64_t timeout; if (status) *status = 0; + r = samv_efc_get_status(target, &v); + if (r != ERROR_OK) + return r; + if ((v & 1) != 0x1) + return ERROR_FAIL; r = samv_efc_start_command(target, command, argument); if (r != ERROR_OK) return r; - ms_end = 10000 + timeval_ms(); + if (command == SAMV_EFC_FCMD_EA || command == SAMV_EFC_FCMD_EPA || + command == SAMV_EFC_FCMD_EUS) + timeout = TIMEOUT_MS_CMD_ERASE; + else + timeout = TIMEOUT_MS_CMD_DEFAULT; - do { - r = samv_efc_get_status(target, &v); - if (r != ERROR_OK) - return r; - ms_now = timeval_ms(); - if (ms_now > ms_end) { - /* error */ - LOG_ERROR("Command timeout"); - return ERROR_FAIL; - } - } while ((v & 1) == 0); + r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET, timeout, &v); + if (r != ERROR_OK) + return r; /* if requested, copy the flash controller error bits back to the caller */ if (status) @@ -133,26 +195,71 @@ static int samv_efc_perform_command(struct target *target, return ERROR_OK; } +static int samv_efc_read_sequence(struct target *target, uint8_t start_cmd, + uint8_t stop_cmd, uint8_t *buf, size_t read_size) +{ + uint32_t v; + uint32_t addr = SAMV_FLASH_BASE; + int r; + + samv_efc_get_mode(target, &v); + v |= SAMV_EFC_FMR_SCOD; + samv_efc_set_mode(target, v); + + r = samv_efc_start_command(target, start_cmd, 0); + if (r != ERROR_OK) { + samv_efc_start_command(target, stop_cmd, 0); + goto rs_finish; + } + + r = samv_efc_wait_status(target, SAMV_EFC_FRS_FRDY_CLR, + TIMEOUT_MS_FRS_CHANGE, NULL); + if (r != ERROR_OK) + goto rs_finish; + + r = target_read_memory(target, addr, sizeof(uint32_t), + read_size / sizeof(uint32_t), buf); + if (r != ERROR_OK) { + LOG_ERROR("flash program failed to read page @ 0x%" PRIx32 "", addr); + goto rs_finish; + } + + r = samv_efc_start_command(target, stop_cmd, 0); + if (r != ERROR_OK) + goto rs_finish; + + r = samv_efc_wait_status(target, SAMV_EFC_FSR_FRDY_SET, + TIMEOUT_MS_FRS_CHANGE, NULL); + if (r != ERROR_OK) + goto rs_finish; + +rs_finish: + v &= ~SAMV_EFC_FMR_SCOD; + samv_efc_set_mode(target, v); + + return r; +} + static int samv_erase_pages(struct target *target, int first_page, int num_pages, uint32_t *status) { uint8_t erase_pages; switch (num_pages) { - case 4: - erase_pages = 0x00; - break; - case 8: - erase_pages = 0x01; - break; - case 16: - erase_pages = 0x02; - break; - case 32: - erase_pages = 0x03; - break; - default: - erase_pages = 0x00; - break; + case 4: + erase_pages = 0x00; + break; + case 8: + erase_pages = 0x01; + break; + case 16: + erase_pages = 0x02; + break; + case 32: + erase_pages = 0x03; + break; + default: + erase_pages = 0x00; + break; } /* SAMV_EFC_FCMD_EPA @@ -230,6 +337,17 @@ static int samv_set_gpnvm(struct target *target, unsigned int gpnvm) return r; } +static int samv_erase_user_signature(struct target *target) +{ + int r; + + r = samv_efc_perform_command(target, SAMV_EFC_FCMD_EUS, 0, NULL); + if (r != ERROR_OK) + LOG_ERROR("error performing user signature write"); + + return r; +} + static int samv_flash_unlock(struct target *target, unsigned int start_sector, unsigned int end_sector) { @@ -292,7 +410,6 @@ static int samv_protect_check(struct flash_bank *bank) FLASH_BANK_COMMAND_HANDLER(samv_flash_bank_command) { - LOG_INFO("flash bank command"); struct samv_flash_bank *samv_info; samv_info = calloc(1, sizeof(struct samv_flash_bank)); bank->driver_priv = samv_info; @@ -306,11 +423,19 @@ static int samv_get_device_id(struct flash_bank *bank, uint32_t *device_id) static int samv_probe(struct flash_bank *bank) { + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) { + bank->size = SAMV_FLASH_SIGNATURE_SIZE; + bank->num_sectors = 1; + bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); + bank->sectors[0].size = SAMV_FLASH_SIGNATURE_SIZE; + return ERROR_OK; + } + uint32_t device_id; int r = samv_get_device_id(bank, &device_id); if (r != ERROR_OK) return r; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); uint8_t eproc = (device_id >> 5) & 0x7; if (eproc != 0) { @@ -320,18 +445,18 @@ static int samv_probe(struct flash_bank *bank) uint8_t nvm_size_code = (device_id >> 8) & 0xf; switch (nvm_size_code) { - case 10: - bank->size = 512 * 1024; - break; - case 12: - bank->size = 1024 * 1024; - break; - case 14: - bank->size = 2048 * 1024; - break; - default: - LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); - return ERROR_FAIL; + case 10: + bank->size = 512 * 1024; + break; + case 12: + bank->size = 1024 * 1024; + break; + case 14: + bank->size = 2048 * 1024; + break; + default: + LOG_ERROR("unrecognized flash size code: %d", nvm_size_code); + return ERROR_FAIL; } struct samv_flash_bank *samv_info = bank->driver_priv; @@ -377,16 +502,19 @@ static int samv_erase(struct flash_bank *bank, unsigned int first, if (r != ERROR_OK) return r; + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) + return samv_erase_user_signature(bank->target); + /* easy case: we've been requested to erase the entire flash */ if ((first == 0) && ((last + 1) == bank->num_sectors)) return samv_efc_perform_command(bank->target, SAMV_EFC_FCMD_EA, 0, NULL); - LOG_INFO("erasing lock regions %u-%u...", first, last); + LOG_DEBUG("erasing lock regions %u-%u...", first, last); for (unsigned int i = first; i <= last; i++) { uint32_t status; r = samv_erase_pages(bank->target, (i * page_count), page_count, &status); - LOG_INFO("erasing lock region %u", i); + LOG_DEBUG("erasing lock region %u", i); if (r != ERROR_OK) LOG_ERROR("error performing erase page @ lock region number %u", i); if (status & (1 << 2)) { @@ -418,45 +546,134 @@ static int samv_protect(struct flash_bank *bank, int set, unsigned int first, return r; } -static int samv_page_read(struct target *target, +static int samv_read_standard_page(struct target *target, unsigned int page_num, uint8_t *buf) { uint32_t addr = SAMV_FLASH_BASE + page_num * SAMV_PAGE_SIZE; int r = target_read_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) - LOG_ERROR("flash program failed to read page @ 0x%08x", - (unsigned int)(addr)); + LOG_ERROR("flash program failed to read page @ 0x%08" PRIx32 "", + addr); return r; } -static int samv_page_write(struct target *target, +static int samv_read_user_signature(struct target *target, uint8_t *buf) +{ + int r; + + r = samv_efc_read_sequence(target, SAMV_EFC_FCMD_STUS, SAMV_EFC_FCMD_SPUS, + buf, SAMV_PAGE_SIZE); + + return r; +} + +static int samv_page_read(struct target *target, + target_addr_t base, unsigned int page_num, uint8_t *buf) +{ + int r; + if (base == SAMV_FLASH_SIGNATURE_BASE) + r = samv_read_user_signature(target, buf); + else + r = samv_read_standard_page(target, page_num, buf); + + return r; +} + +static int samv_write_user_signature(struct target *target, + unsigned int pagenum, const uint8_t *buf) +{ + const uint32_t addr = SAMV_FLASH_BASE; + int r; + + r = target_write_memory(target, addr, sizeof(uint32_t), + SAMV_PAGE_SIZE / sizeof(uint32_t), buf); + if (r != ERROR_OK) { + LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr); + return r; + } + + r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WUS, 0, NULL); + if (r != ERROR_OK) + LOG_ERROR("error performing user signature write"); + + return r; +} + +static int samv_write_standard_page(struct target *target, unsigned int pagenum, const uint8_t *buf) { uint32_t status; const uint32_t addr = SAMV_FLASH_BASE + pagenum * SAMV_PAGE_SIZE; int r; - LOG_DEBUG("write page %u at address 0x%08x", pagenum, (unsigned int)addr); + LOG_DEBUG("write page %u at address 0x%08" PRIx32 "", pagenum, addr); r = target_write_memory(target, addr, 4, SAMV_PAGE_SIZE / 4, buf); if (r != ERROR_OK) { - LOG_ERROR("failed to buffer page at 0x%08x", (unsigned int)addr); + LOG_ERROR("failed to buffer page at 0x%08" PRIx32 "", addr); return r; } r = samv_efc_perform_command(target, SAMV_EFC_FCMD_WP, pagenum, &status); if (r != ERROR_OK) - LOG_ERROR("error performing write page at 0x%08x", (unsigned int)addr); + LOG_ERROR("error performing write page at 0x%08" PRIx32 "", addr); if (status & (1 << 2)) { - LOG_ERROR("page at 0x%08x is locked", (unsigned int)addr); + LOG_ERROR("page at 0x%08" PRIx32 " is locked", addr); return ERROR_FAIL; } if (status & (1 << 1)) { - LOG_ERROR("flash command error at 0x%08x", (unsigned int)addr); + LOG_ERROR("flash command error at 0x%08" PRIx32 "", addr); return ERROR_FAIL; } return ERROR_OK; } +static int samv_page_write(struct target *target, + target_addr_t base, unsigned int pagenum, const uint8_t *buf) +{ + int r; + if (base == SAMV_FLASH_SIGNATURE_BASE) + r = samv_write_user_signature(target, pagenum, buf); + else + r = samv_write_standard_page(target, pagenum, buf); + + return r; +} + +static int samv_read(struct flash_bank *bank, uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + int r; + uint8_t pagebuffer[SAMV_PAGE_SIZE] = {0}; + struct target *target = bank->target; + + LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32 "", offset, count); + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset + count > bank->size) { + LOG_WARNING("Reads past end of flash. Extra data discarded."); + count = bank->size - offset; + } + + LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count); + + if (bank->base == SAMV_FLASH_SIGNATURE_BASE) { + r = samv_read_user_signature(target, pagebuffer); + if (r != ERROR_OK) + return r; + memcpy(buffer, pagebuffer + offset, count); + } else { + r = target_read_memory(target, offset, 1, count, buffer); + if (r != ERROR_OK) + return r; + } + + return ERROR_OK; +} + static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -470,10 +687,10 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, if ((offset + count) > bank->size) { LOG_ERROR("flash write error - past end of bank"); - LOG_ERROR(" offset: 0x%08x, count 0x%08x, bank end: 0x%08x", - (unsigned int)(offset), - (unsigned int)(count), - (unsigned int)(bank->size)); + LOG_ERROR(" offset: 0x%08" PRIx32 ", count 0x%08" PRIx32 ", bank end: 0x%08" PRIx32 "", + offset, + count, + bank->size); return ERROR_FAIL; } @@ -481,9 +698,8 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t page_cur = offset / SAMV_PAGE_SIZE; uint32_t page_end = (offset + count - 1) / SAMV_PAGE_SIZE; - LOG_DEBUG("offset: 0x%08x, count: 0x%08x", - (unsigned int)(offset), (unsigned int)(count)); - LOG_DEBUG("page start: %d, page end: %d", (int)(page_cur), (int)(page_end)); + LOG_DEBUG("offset: 0x%08" PRIx32 ", count: 0x%08" PRIx32 "", offset, count); + LOG_DEBUG("page start: %" PRIu32 ", page end: %" PRIu32 "", page_cur, page_end); /* Special case: all one page */ /* Otherwise: */ @@ -497,14 +713,14 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, /* handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("special case, all in one page"); - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; - page_offset = offset & (SAMV_PAGE_SIZE-1); + page_offset = offset & (SAMV_PAGE_SIZE - 1); memcpy(pagebuffer + page_offset, buffer, count); - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; return ERROR_OK; @@ -515,7 +731,7 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, if (page_offset) { LOG_DEBUG("non-aligned start"); /* read the partial page */ - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; @@ -523,11 +739,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t n = SAMV_PAGE_SIZE - page_offset; memcpy(pagebuffer + page_offset, buffer, n); - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; - count -= n; + count -= n; offset += n; buffer += n; page_cur++; @@ -537,11 +753,11 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, assert(offset % SAMV_PAGE_SIZE == 0); /* step 2) handle the full pages */ - LOG_DEBUG("full page loop: cur=%d, end=%d, count = 0x%08x", - (int)page_cur, (int)page_end, (unsigned int)(count)); + LOG_DEBUG("full page loop: cur=%" PRIu32 ", end=%" PRIu32 ", count = 0x%08" PRIx32 "", + page_cur, page_end, count); while ((page_cur < page_end) && (count >= SAMV_PAGE_SIZE)) { - r = samv_page_write(bank->target, page_cur, buffer); + r = samv_page_write(bank->target, bank->base, page_cur, buffer); if (r != ERROR_OK) return r; count -= SAMV_PAGE_SIZE; @@ -551,13 +767,13 @@ static int samv_write(struct flash_bank *bank, const uint8_t *buffer, /* step 3) write final page, if it's partial (otherwise it's already done) */ if (count) { - LOG_DEBUG("final partial page, count = 0x%08x", (unsigned int)(count)); + LOG_DEBUG("final partial page, count = 0x%08" PRIx32 "", count); /* we have a partial page */ - r = samv_page_read(bank->target, page_cur, pagebuffer); + r = samv_page_read(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; memcpy(pagebuffer, buffer, count); /* data goes at start of page */ - r = samv_page_write(bank->target, page_cur, pagebuffer); + r = samv_page_write(bank->target, bank->base, page_cur, pagebuffer); if (r != ERROR_OK) return r; } @@ -600,22 +816,22 @@ COMMAND_HANDLER(samv_handle_gpnvm_command) int who = 0; switch (CMD_ARGC) { - case 0: - goto showall; - case 1: + case 0: + goto showall; + case 1: + who = -1; + break; + case 2: + if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all")) { who = -1; - break; - case 2: - if (!strcmp(CMD_ARGV[0], "show") && !strcmp(CMD_ARGV[1], "all")) - who = -1; - else { - uint32_t v32; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); - who = v32; - } - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + } else { + uint32_t v32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); + who = v32; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } unsigned int v = 0; @@ -691,7 +907,7 @@ const struct flash_driver atsamv_flash = { .erase = samv_erase, .protect = samv_protect, .write = samv_write, - .read = default_flash_read, + .read = samv_read, .probe = samv_probe, .auto_probe = samv_auto_probe, .erase_check = default_flash_blank_check, diff --git a/src/flash/nor/avrf.c b/src/flash/nor/avrf.c index 1d317a10c6..af83822490 100644 --- a/src/flash/nor/avrf.c +++ b/src/flash/nor/avrf.c @@ -126,7 +126,7 @@ static int avr_jtagprg_chiperase(struct avr_common *avr) AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); + LOG_DEBUG("poll_value = 0x%04" PRIx32, poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; @@ -187,7 +187,7 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, AVR_JTAG_REG_PROGRAMMING_COMMAND_LEN); if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); + LOG_DEBUG("poll_value = 0x%04" PRIx32, poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; @@ -253,8 +253,8 @@ static int avrf_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t o return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); - LOG_DEBUG("count is %" PRIu32 "", count); + LOG_DEBUG("offset is 0x%08" PRIx32, offset); + LOG_DEBUG("count is %" PRIu32, count); if (avr_jtagprg_enterprogmode(avr) != ERROR_OK) return ERROR_FAIL; @@ -308,7 +308,7 @@ static int avrf_probe(struct flash_bank *bank) if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), @@ -373,7 +373,7 @@ static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) if (mcu_execute_queue() != ERROR_OK) return ERROR_FAIL; - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); + LOG_INFO("device id = 0x%08" PRIx32, device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), @@ -390,7 +390,7 @@ static int avrf_info(struct flash_bank *bank, struct command_invocation *cmd) if (avr_info) { /* chip found */ - command_print_sameline(cmd, "%s - Rev: 0x%" PRIx32 "", avr_info->name, + command_print_sameline(cmd, "%s - Rev: 0x%" PRIx32, avr_info->name, EXTRACT_VER(device_id)); return ERROR_OK; } else { diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c index 9ced2e9718..ccbbcc66eb 100644 --- a/src/flash/nor/bluenrg-x.c +++ b/src/flash/nor/bluenrg-x.c @@ -19,6 +19,7 @@ #define BLUENRG2_JTAG_REG (flash_priv_data_2.jtag_idcode_reg) #define BLUENRGLP_JTAG_REG (flash_priv_data_lp.jtag_idcode_reg) +#define BLUENRGLPF_JTAG_REG (flash_priv_data_lpf.jtag_idcode_reg) #define DIE_ID_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->die_id_reg) #define JTAG_IDCODE_REG(bluenrgx_info) (bluenrgx_info->flash_ptr->jtag_idcode_reg) @@ -63,7 +64,7 @@ static const struct flash_ctrl_priv_data flash_priv_data_lp = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x0201E041, - .part_name = "BLUENRG-LP", + .part_name = "STM32WB07 (BLUENRG-LP)", }; static const struct flash_ctrl_priv_data flash_priv_data_lps = { @@ -73,7 +74,17 @@ static const struct flash_ctrl_priv_data flash_priv_data_lps = { .flash_regs_base = 0x40001000, .flash_page_size = 2048, .jtag_idcode = 0x02028041, - .part_name = "BLUENRG-LPS", + .part_name = "STM32WB05 (BLUENRG-LPS)", +}; + +static const struct flash_ctrl_priv_data flash_priv_data_lpf = { + .die_id_reg = 0x40000000, + .jtag_idcode_reg = 0x40000004, + .flash_base = 0x10040000, + .flash_regs_base = 0x40001000, + .flash_page_size = 2048, + .jtag_idcode = 0x02032041, + .part_name = "STM32WB09 (BLUENRG-LPF)", }; struct bluenrgx_flash_bank { @@ -86,7 +97,9 @@ static const struct flash_ctrl_priv_data *flash_ctrl[] = { &flash_priv_data_1, &flash_priv_data_2, &flash_priv_data_lp, - &flash_priv_data_lps}; + &flash_priv_data_lps, + &flash_priv_data_lpf +}; /* flash_bank bluenrg-x 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command) @@ -130,8 +143,45 @@ static inline int bluenrgx_write_flash_reg(struct flash_bank *bank, uint32_t reg return target_write_u32(bank->target, bluenrgx_get_flash_reg(bank, reg_offset), value); } -static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) +static int bluenrgx_wait_for_interrupt(struct flash_bank *bank, uint32_t interrupt_flag) +{ + bool flag_raised = false; + for (unsigned int j = 0; j < 100; j++) { + uint32_t value; + if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value) != ERROR_OK) { + LOG_ERROR("Register read failed"); + return ERROR_FAIL; + } + + if (value & interrupt_flag) { + flag_raised = true; + break; + } + } + + /* clear the interrupt */ + if (flag_raised) { + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, interrupt_flag) != ERROR_OK) { + LOG_ERROR("Cannot clear interrupt flag"); + return ERROR_FAIL; + } + + return ERROR_OK; + } + + LOG_ERROR("Erase command failed (timeout)"); + return ERROR_TIMEOUT_REACHED; +} + +static inline int bluenrgx_wait_for_command(struct flash_bank *bank) +{ + if (bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDSTART) == ERROR_OK) + return bluenrgx_wait_for_interrupt(bank, FLASH_INT_CMDDONE); + + return ERROR_FAIL; +} + +static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, unsigned int last) { int retval = ERROR_OK; struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -173,19 +223,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int i = 0; i < 100; i++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (i == 99) { - LOG_ERROR("Mass erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } else { command = FLASH_CMD_ERASE_PAGE; @@ -209,19 +248,8 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, return ERROR_FAIL; } - for (unsigned int j = 0; j < 100; j++) { - uint32_t value; - if (bluenrgx_read_flash_reg(bank, FLASH_REG_IRQRAW, &value)) { - LOG_ERROR("Register write failed"); - return ERROR_FAIL; - } - if (value & FLASH_INT_CMDDONE) - break; - if (j == 99) { - LOG_ERROR("Erase command failed (timeout)"); - retval = ERROR_FAIL; - } - } + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; } } @@ -229,7 +257,7 @@ static int bluenrgx_erase(struct flash_bank *bank, unsigned int first, } -static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, +static int bluenrgx_write_with_loader(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -251,22 +279,6 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, #include "../../../contrib/loaders/flash/bluenrg-x/bluenrg-x_write.inc" }; - /* check preconditions */ - if (!bluenrgx_info->probed) - return ERROR_FLASH_BANK_NOT_PROBED; - - if ((offset + count) > bank->size) { - LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, - (offset + count), - bank->size); - return ERROR_FLASH_DST_OUT_OF_BANK; - } - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - if (target_alloc_working_area(target, sizeof(bluenrgx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); @@ -302,10 +314,10 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "sp", 32, PARAM_OUT); /* Put the 4th parameter at the location in the stack frame of target write() function. * See contrib/loaders/flash/bluenrg-x/bluenrg-x_write.lst - * 34 ldr r6, [sp, #80] + * 34 ldr r6, [sp, #88] * ^^^ offset */ - init_mem_param(&mem_params[0], write_algorithm_stack->address + 80, 32, PARAM_OUT); + init_mem_param(&mem_params[0], write_algorithm_stack->address + 88, 32, PARAM_OUT); /* Stack for target write algorithm - target write() function has * __attribute__((naked)) so it does not setup the new stack frame. * Therefore the stack frame uses the area from SP upwards! @@ -353,6 +365,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, if (error != 0) LOG_ERROR("flash write failed = %08" PRIx32, error); } + if (retval == ERROR_OK) { uint32_t rp; /* Read back rp and check that is valid */ @@ -364,6 +377,7 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, } } } + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); target_free_working_area(target, write_algorithm_stack); @@ -378,6 +392,80 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, return retval; } +static int bluenrgx_write_without_loader(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + unsigned int data_count = count / FLASH_DATA_WIDTH; + + while (data_count--) { + /* clear flags */ + if (bluenrgx_write_flash_reg(bank, FLASH_REG_IRQRAW, 0x3f) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_ADDRESS, offset >> 2) != ERROR_OK) { + LOG_ERROR("Register write failed"); + return ERROR_FAIL; + } + + if (target_write_memory(target, bluenrgx_get_flash_reg(bank, FLASH_REG_DATA0), + FLASH_WORD_LEN, FLASH_DATA_WIDTH_W, buffer) != ERROR_OK) { + LOG_ERROR("Failed to write data"); + return ERROR_FAIL; + } + + if (bluenrgx_write_flash_reg(bank, FLASH_REG_COMMAND, FLASH_CMD_BURSTWRITE) != ERROR_OK) { + LOG_ERROR("Failed"); + return ERROR_FAIL; + } + + if (bluenrgx_wait_for_command(bank) != ERROR_OK) + return ERROR_FAIL; + + /* increment offset, and buffer */ + offset += FLASH_DATA_WIDTH; + buffer += FLASH_DATA_WIDTH; + } + + return ERROR_OK; +} + +static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; + int retval = ERROR_OK; + + /* check preconditions */ + if (!bluenrgx_info->probed) + return ERROR_FLASH_BANK_NOT_PROBED; + + if ((offset + count) > bank->size) { + LOG_ERROR("Requested write past beyond of flash size: (offset+count) = %" PRIu32 ", size=%" PRIu32, + (offset + count), + bank->size); + return ERROR_FLASH_DST_OUT_OF_BANK; + } + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + assert(offset % FLASH_WORD_LEN == 0); + assert(count % FLASH_WORD_LEN == 0); + + retval = bluenrgx_write_with_loader(bank, buffer, offset, count); + /* if resources are not available write without a loader */ + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + LOG_WARNING("falling back to programming without a flash loader (slower)"); + retval = bluenrgx_write_without_loader(bank, buffer, offset, count); + } + return retval; +} + static int bluenrgx_probe(struct flash_bank *bank) { struct bluenrgx_flash_bank *bluenrgx_info = bank->driver_priv; @@ -387,7 +475,8 @@ static int bluenrgx_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - if ((idcode != flash_priv_data_lp.jtag_idcode) && (idcode != flash_priv_data_lps.jtag_idcode)) { + if (idcode != flash_priv_data_lp.jtag_idcode && idcode != flash_priv_data_lps.jtag_idcode + && idcode != flash_priv_data_lpf.jtag_idcode) { retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode); if (retval != ERROR_OK) return retval; @@ -414,7 +503,7 @@ static int bluenrgx_probe(struct flash_bank *bank) return retval; bank->size = (size_info + 1) * FLASH_WORD_LEN; - bank->num_sectors = bank->size/FLASH_PAGE_SIZE(bluenrgx_info); + bank->num_sectors = bank->size / FLASH_PAGE_SIZE(bluenrgx_info); bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector) * bank->num_sectors); for (unsigned int i = 0; i < bank->num_sectors; i++) { diff --git a/src/flash/nor/bluenrg-x.h b/src/flash/nor/bluenrg-x.h index 720cb6e618..03c66cd81a 100644 --- a/src/flash/nor/bluenrg-x.h +++ b/src/flash/nor/bluenrg-x.h @@ -28,7 +28,12 @@ #define FLASH_CMD_WRITE 0x33 #define FLASH_CMD_BURSTWRITE 0xCC #define FLASH_INT_CMDDONE 0x01 +#define FLASH_INT_CMDSTART 0x02 +/* Flash Controller constants */ #define FLASH_WORD_LEN 4 +#define FLASH_DATA_WIDTH_W 4 +#define FLASH_DATA_WIDTH 16 + #endif /* OPENOCD_FLASH_NOR_BLUENRGX_H */ diff --git a/src/flash/nor/cc26xx.c b/src/flash/nor/cc26xx.c index 54d61421ce..f7c2011beb 100644 --- a/src/flash/nor/cc26xx.c +++ b/src/flash/nor/cc26xx.c @@ -51,22 +51,22 @@ static uint32_t cc26xx_device_type(uint32_t icepick_id, uint32_t user_id) uint32_t device_type = 0; switch (icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - device_type = CC26X0_TYPE; - break; - case CC26X1_ICEPICK_ID: - device_type = CC26X1_TYPE; - break; - case CC13X0_ICEPICK_ID: - device_type = CC13X0_TYPE; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - if ((user_id & USER_ID_CC13_MASK) != 0) - device_type = CC13X2_TYPE; - else - device_type = CC26X2_TYPE; - break; + case CC26X0_ICEPICK_ID: + device_type = CC26X0_TYPE; + break; + case CC26X1_ICEPICK_ID: + device_type = CC26X1_TYPE; + break; + case CC13X0_ICEPICK_ID: + device_type = CC13X0_TYPE; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + if ((user_id & USER_ID_CC13_MASK) != 0) + device_type = CC13X2_TYPE; + else + device_type = CC26X2_TYPE; + break; } return device_type; @@ -77,17 +77,17 @@ static uint32_t cc26xx_sector_length(uint32_t icepick_id) uint32_t sector_length; switch (icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - case CC26X1_ICEPICK_ID: - case CC13X0_ICEPICK_ID: - /* Chameleon family device */ - sector_length = CC26X0_SECTOR_LENGTH; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - /* Agama family device */ - sector_length = CC26X2_SECTOR_LENGTH; - break; + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + sector_length = CC26X0_SECTOR_LENGTH; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + sector_length = CC26X2_SECTOR_LENGTH; + break; } return sector_length; @@ -112,10 +112,10 @@ static int cc26xx_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (status != CC26XX_BUFFER_EMPTY) { @@ -321,8 +321,6 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, struct cc26xx_bank *cc26xx_bank = bank->driver_priv; struct cc26xx_algo_params algo_params[2]; uint32_t size = 0; - long long start_ms; - long long elapsed_ms; uint32_t address; uint32_t index; @@ -343,7 +341,6 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, /* Write requested data, ping-ponging between two buffers */ index = 0; - start_ms = timeval_ms(); address = bank->base + offset; while (count > 0) { @@ -381,9 +378,7 @@ static int cc26xx_write(struct flash_bank *bank, const uint8_t *buffer, buffer += size; address += size; - elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); + keep_alive(); } /* If no error yet, wait for last buffer to finish */ @@ -427,31 +422,31 @@ static int cc26xx_probe(struct flash_bank *bank) /* Set up appropriate flash helper algorithm */ switch (cc26xx_bank->icepick_id & ICEPICK_ID_MASK) { - case CC26X0_ICEPICK_ID: - case CC26X1_ICEPICK_ID: - case CC13X0_ICEPICK_ID: - /* Chameleon family device */ - cc26xx_bank->algo_code = cc26x0_algo; - cc26xx_bank->algo_size = sizeof(cc26x0_algo); - cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; - cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; - cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; - cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; - cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; - max_sectors = CC26X0_MAX_SECTORS; - break; - case CC13X2_CC26X2_ICEPICK_ID: - default: - /* Agama family device */ - cc26xx_bank->algo_code = cc26x2_algo; - cc26xx_bank->algo_size = sizeof(cc26x2_algo); - cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; - cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; - cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; - cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; - cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; - max_sectors = CC26X2_MAX_SECTORS; - break; + case CC26X0_ICEPICK_ID: + case CC26X1_ICEPICK_ID: + case CC13X0_ICEPICK_ID: + /* Chameleon family device */ + cc26xx_bank->algo_code = cc26x0_algo; + cc26xx_bank->algo_size = sizeof(cc26x0_algo); + cc26xx_bank->algo_working_size = CC26X0_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X0_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X0_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X0_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X0_ALGO_PARAMS_1; + max_sectors = CC26X0_MAX_SECTORS; + break; + case CC13X2_CC26X2_ICEPICK_ID: + default: + /* Agama family device */ + cc26xx_bank->algo_code = cc26x2_algo; + cc26xx_bank->algo_size = sizeof(cc26x2_algo); + cc26xx_bank->algo_working_size = CC26X2_WORKING_SIZE; + cc26xx_bank->buffer_addr[0] = CC26X2_ALGO_BUFFER_0; + cc26xx_bank->buffer_addr[1] = CC26X2_ALGO_BUFFER_1; + cc26xx_bank->params_addr[0] = CC26X2_ALGO_PARAMS_0; + cc26xx_bank->params_addr[1] = CC26X2_ALGO_PARAMS_1; + max_sectors = CC26X2_MAX_SECTORS; + break; } retval = target_read_u32(target, CC26XX_FLASH_SIZE_INFO, &value); @@ -505,25 +500,25 @@ static int cc26xx_info(struct flash_bank *bank, struct command_invocation *cmd) const char *device; switch (cc26xx_bank->device_type) { - case CC26X0_TYPE: - device = "CC26x0"; - break; - case CC26X1_TYPE: - device = "CC26x1"; - break; - case CC13X0_TYPE: - device = "CC13x0"; - break; - case CC13X2_TYPE: - device = "CC13x2"; - break; - case CC26X2_TYPE: - device = "CC26x2"; - break; - case CC26XX_NO_TYPE: - default: - device = "Unrecognized"; - break; + case CC26X0_TYPE: + device = "CC26x0"; + break; + case CC26X1_TYPE: + device = "CC26x1"; + break; + case CC13X0_TYPE: + device = "CC13x0"; + break; + case CC13X2_TYPE: + device = "CC13x2"; + break; + case CC26X2_TYPE: + device = "CC26x2"; + break; + case CC26XX_NO_TYPE: + default: + device = "Unrecognized"; + break; } command_print_sameline(cmd, diff --git a/src/flash/nor/cc3220sf.c b/src/flash/nor/cc3220sf.c index 74cb7aea57..0418aeac2b 100644 --- a/src/flash/nor/cc3220sf.c +++ b/src/flash/nor/cc3220sf.c @@ -65,10 +65,10 @@ static int cc3220sf_mass_erase(struct flash_bank *bank) done = true; } else { elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); } } @@ -152,10 +152,10 @@ static int cc3220sf_erase(struct flash_bank *bank, unsigned int first, done = true; } else { elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); } } diff --git a/src/flash/nor/cfi.c b/src/flash/nor/cfi.c index 2a15e49132..108b66750c 100644 --- a/src/flash/nor/cfi.c +++ b/src/flash/nor/cfi.c @@ -945,14 +945,14 @@ int cfi_erase(struct flash_bank *bank, unsigned int first, return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_erase(bank, first, last); - case 2: - return cfi_spansion_erase(bank, first, last); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_erase(bank, first, last); + case 2: + return cfi_spansion_erase(bank, first, last); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; @@ -1084,12 +1084,12 @@ int cfi_protect(struct flash_bank *bank, int set, unsigned int first, return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_protect(bank, set, first, last); - default: - LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); - return ERROR_OK; + case 1: + case 3: + return cfi_intel_protect(bank, set, first, last); + default: + LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); + return ERROR_OK; } } @@ -1100,16 +1100,16 @@ static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) uint8_t buf[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, buf); switch (bank->bus_width) { - case 1: - return buf[0]; - case 2: - return target_buffer_get_u16(target, buf); - case 4: - return target_buffer_get_u32(target, buf); - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return 0; + case 1: + return buf[0]; + case 2: + return target_buffer_get_u16(target, buf); + case 4: + return target_buffer_get_u32(target, buf); + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return 0; } } @@ -1214,22 +1214,22 @@ static int cfi_intel_write_block(struct flash_bank *bank, const uint8_t *buffer, /* prepare algorithm code for target endian */ switch (bank->bus_width) { - case 1: - target_code_src = word_8_code; - target_code_size = sizeof(word_8_code); - break; - case 2: - target_code_src = word_16_code; - target_code_size = sizeof(word_16_code); - break; - case 4: - target_code_src = word_32_code; - target_code_size = sizeof(word_32_code); - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + case 1: + target_code_src = word_8_code; + target_code_size = sizeof(word_8_code); + break; + case 2: + target_code_src = word_16_code; + target_code_size = sizeof(word_16_code); + break; + case 4: + target_code_src = word_32_code; + target_code_size = sizeof(word_32_code); + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -1448,22 +1448,22 @@ static int cfi_spansion_write_block_mips(struct flash_bank *bank, const uint8_t const uint32_t *target_code_src = NULL; switch (bank->bus_width) { - case 2: - /* Check for DQ5 support */ - if (cfi_info->status_poll_mask & (1 << 5)) { - target_code_src = mips_word_16_code; - target_code_size = sizeof(mips_word_16_code); - } else { - LOG_ERROR("Need DQ5 support"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - /* target_code_src = mips_word_16_code_dq7only; */ - /* target_code_size = sizeof(mips_word_16_code_dq7only); */ - } - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); + case 2: + /* Check for DQ5 support */ + if (cfi_info->status_poll_mask & (1 << 5)) { + target_code_src = mips_word_16_code; + target_code_size = sizeof(mips_word_16_code); + } else { + LOG_ERROR("Need DQ5 support"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + /* target_code_src = mips_word_16_code_dq7only; */ + /* target_code_size = sizeof(mips_word_16_code_dq7only); */ + } + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -1800,49 +1800,49 @@ static int cfi_spansion_write_block(struct flash_bank *bank, const uint8_t *buff const uint32_t *target_code_src = NULL; switch (bank->bus_width) { - case 1: + case 1: + if (is_armv7m(target_to_armv7m(target))) { + LOG_ERROR("Unknown ARM architecture"); + return ERROR_FAIL; + } + target_code_src = armv4_5_word_8_code; + target_code_size = sizeof(armv4_5_word_8_code); + break; + case 2: + /* Check for DQ5 support */ + if (cfi_info->status_poll_mask & (1 << 5)) { if (is_armv7m(target_to_armv7m(target))) { - LOG_ERROR("Unknown ARM architecture"); - return ERROR_FAIL; + /* armv7m target */ + target_code_src = armv7m_word_16_code; + target_code_size = sizeof(armv7m_word_16_code); + } else { /* armv4_5 target */ + target_code_src = armv4_5_word_16_code; + target_code_size = sizeof(armv4_5_word_16_code); } - target_code_src = armv4_5_word_8_code; - target_code_size = sizeof(armv4_5_word_8_code); - break; - case 2: - /* Check for DQ5 support */ - if (cfi_info->status_poll_mask & (1 << 5)) { - if (is_armv7m(target_to_armv7m(target))) { - /* armv7m target */ - target_code_src = armv7m_word_16_code; - target_code_size = sizeof(armv7m_word_16_code); - } else { /* armv4_5 target */ - target_code_src = armv4_5_word_16_code; - target_code_size = sizeof(armv4_5_word_16_code); - } - } else { - /* No DQ5 support. Use DQ7 DATA# polling only. */ - if (is_armv7m(target_to_armv7m(target))) { - /* armv7m target */ - target_code_src = armv7m_word_16_code_dq7only; - target_code_size = sizeof(armv7m_word_16_code_dq7only); - } else { /* armv4_5 target */ - target_code_src = armv4_5_word_16_code_dq7only; - target_code_size = sizeof(armv4_5_word_16_code_dq7only); - } - } - break; - case 4: + } else { + /* No DQ5 support. Use DQ7 DATA# polling only. */ if (is_armv7m(target_to_armv7m(target))) { - LOG_ERROR("Unknown ARM architecture"); - return ERROR_FAIL; + /* armv7m target */ + target_code_src = armv7m_word_16_code_dq7only; + target_code_size = sizeof(armv7m_word_16_code_dq7only); + } else { /* armv4_5 target */ + target_code_src = armv4_5_word_16_code_dq7only; + target_code_size = sizeof(armv4_5_word_16_code_dq7only); } - target_code_src = armv4_5_word_32_code; - target_code_size = sizeof(armv4_5_word_32_code); - break; - default: - LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", - bank->bus_width); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + break; + case 4: + if (is_armv7m(target_to_armv7m(target))) { + LOG_ERROR("Unknown ARM architecture"); + return ERROR_FAIL; + } + target_code_src = armv4_5_word_32_code; + target_code_size = sizeof(armv4_5_word_32_code); + break; + default: + LOG_ERROR("Unsupported bank buswidth %u, can't do block memory writes", + bank->bus_width); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ @@ -2172,14 +2172,14 @@ int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) struct cfi_flash_bank *cfi_info = bank->driver_priv; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_write_word(bank, word, address); - case 2: - return cfi_spansion_write_word(bank, word, address); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_write_word(bank, word, address); + case 2: + return cfi_spansion_write_word(bank, word, address); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_FLASH_OPERATION_FAILED; @@ -2197,14 +2197,14 @@ static int cfi_write_words(struct flash_bank *bank, const uint8_t *word, } switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_write_words(bank, word, wordcount, address); - case 2: - return cfi_spansion_write_words(bank, word, wordcount, address); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_write_words(bank, word, wordcount, address); + case 2: + return cfi_spansion_write_words(bank, word, wordcount, address); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_FLASH_OPERATION_FAILED; @@ -2345,18 +2345,18 @@ static int cfi_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* handle blocks of bus_size aligned bytes */ blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */ switch (cfi_info->pri_id) { - /* try block writes (fails without working area) */ - case 1: - case 3: - retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); - break; - case 2: - retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + /* try block writes (fails without working area) */ + case 1: + case 3: + retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); + break; + case 2: + retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } if (retval == ERROR_OK) { /* Increment pointers and decrease count on successful block write */ @@ -2581,22 +2581,22 @@ int cfi_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; switch (bank->chip_width) { - case 1: - cfi_info->manufacturer = *value_buf0; - cfi_info->device_id = *value_buf1; - break; - case 2: - cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); - cfi_info->device_id = target_buffer_get_u16(target, value_buf1); - break; - case 4: - cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); - cfi_info->device_id = target_buffer_get_u32(target, value_buf1); - break; - default: - LOG_ERROR("Unsupported bank chipwidth %u, can't probe memory", - bank->chip_width); - return ERROR_FLASH_OPERATION_FAILED; + case 1: + cfi_info->manufacturer = *value_buf0; + cfi_info->device_id = *value_buf1; + break; + case 2: + cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); + cfi_info->device_id = target_buffer_get_u16(target, value_buf1); + break; + case 4: + cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); + cfi_info->device_id = target_buffer_get_u32(target, value_buf1); + break; + default: + LOG_ERROR("Unsupported bank chipwidth %u, can't probe memory", + bank->chip_width); + return ERROR_FLASH_OPERATION_FAILED; } LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", @@ -2722,7 +2722,7 @@ int cfi_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; LOG_DEBUG( - "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "", + "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32, i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); @@ -2734,25 +2734,25 @@ int cfi_probe(struct flash_bank *bank) * the sector layout to be able to apply fixups */ switch (cfi_info->pri_id) { - /* Intel command set (standard and extended) */ - case 0x0001: - case 0x0003: - cfi_read_intel_pri_ext(bank); - break; - /* AMD/Spansion, Atmel, ... command set */ - case 0x0002: - cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* - *default - *for - *all - *CFI - *flashes - **/ - cfi_read_0002_pri_ext(bank); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_read_intel_pri_ext(bank); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* + *default + *for + *all + *CFI + *flashes + **/ + cfi_read_0002_pri_ext(bank); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } /* return to read array mode @@ -2798,18 +2798,18 @@ int cfi_probe(struct flash_bank *bank) /* apply fixups depending on the primary command set */ switch (cfi_info->pri_id) { - /* Intel command set (standard and extended) */ - case 0x0001: - case 0x0003: - cfi_fixup(bank, cfi_0001_fixups); - break; - /* AMD/Spansion, Atmel, ... command set */ - case 0x0002: - cfi_fixup(bank, cfi_0002_fixups); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + /* Intel command set (standard and extended) */ + case 0x0001: + case 0x0003: + cfi_fixup(bank, cfi_0001_fixups); + break; + /* AMD/Spansion, Atmel, ... command set */ + case 0x0002: + cfi_fixup(bank, cfi_0002_fixups); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size) { @@ -2849,7 +2849,7 @@ int cfi_probe(struct flash_bank *bank) } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( - "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", + "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32, (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } @@ -2939,14 +2939,14 @@ int cfi_protect_check(struct flash_bank *bank) return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { - case 1: - case 3: - return cfi_intel_protect_check(bank); - case 2: - return cfi_spansion_protect_check(bank); - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + return cfi_intel_protect_check(bank); + case 2: + return cfi_spansion_protect_check(bank); + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; @@ -3011,16 +3011,16 @@ int cfi_get_info(struct flash_bank *bank, struct command_invocation *cmd) 1 << cfi_info->max_buf_write_size); switch (cfi_info->pri_id) { - case 1: - case 3: - cfi_intel_info(bank, cmd); - break; - case 2: - cfi_spansion_info(bank, cmd); - break; - default: - LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); - break; + case 1: + case 3: + cfi_intel_info(bank, cmd); + break; + case 2: + cfi_spansion_info(bank, cmd); + break; + default: + LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); + break; } return ERROR_OK; diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 3b57ef9ff0..2bd2043633 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -237,9 +237,11 @@ struct flash_driver { */ const struct flash_driver *flash_driver_find_by_name(const char *name); +// Keep in alphabetic order this list of drivers extern const struct flash_driver aduc702x_flash; extern const struct flash_driver aducm360_flash; extern const struct flash_driver ambiqmicro_flash; +extern const struct flash_driver artery_flash; extern const struct flash_driver at91sam3_flash; extern const struct flash_driver at91sam4_flash; extern const struct flash_driver at91sam4l_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3770bfbd3c..6b0def6810 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -7,6 +7,8 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + +#include #include "imp.h" /** @@ -14,9 +16,11 @@ * @todo Make this dynamically extendable with loadable modules. */ static const struct flash_driver * const flash_drivers[] = { + // Keep in alphabetic order the list of drivers &aduc702x_flash, &aducm360_flash, &ambiqmicro_flash, + &artery_flash, &at91sam3_flash, &at91sam4_flash, &at91sam4l_flash, @@ -27,8 +31,8 @@ static const struct flash_driver * const flash_drivers[] = { &atsamv_flash, &avr_flash, &bluenrgx_flash, - &cc3220sf_flash, &cc26xx_flash, + &cc3220sf_flash, &cfi_flash, &dsp5680xx_flash, &dw_spi_flash, @@ -37,9 +41,9 @@ static const struct flash_driver * const flash_drivers[] = { &eneispif_flash, &esirisc_flash, &faux_flash, + &fespi_flash, &fm3_flash, &fm4_flash, - &fespi_flash, &jtagspi_flash, &kinetis_flash, &kinetis_ke_flash, @@ -54,46 +58,45 @@ static const struct flash_driver * const flash_drivers[] = { &mspm0_flash, &niietcm4_flash, &npcx_flash, - &nrf5_flash, &nrf51_flash, + &nrf5_flash, &numicro_flash, &ocl_flash, &pic32mx_flash, &psoc4_flash, - &psoc5lp_flash, &psoc5lp_eeprom_flash, + &psoc5lp_flash, &psoc5lp_nvl_flash, &psoc6_flash, &qn908x_flash, &renesas_rpchf_flash, &rp2xxx_flash, + &rsl10_flash, &sh_qspi_flash, &sim3x_flash, &stellaris_flash, &stm32f1x_flash, &stm32f2x_flash, - &stm32lx_flash, - &stm32l4x_flash, &stm32h7x_flash, - &stmsmi_flash, + &stm32l4x_flash, + &stm32lx_flash, &stmqspi_flash, + &stmsmi_flash, &str7x_flash, &str9x_flash, &str9xpec_flash, &swm050_flash, &tms470_flash, &virtual_flash, + &w600_flash, &xcf_flash, &xmc1xxx_flash, &xmc4xxx_flash, - &w600_flash, - &rsl10_flash, - NULL, }; const struct flash_driver *flash_driver_find_by_name(const char *name) { - for (unsigned int i = 0; flash_drivers[i]; i++) { + for (size_t i = 0; i < ARRAY_SIZE(flash_drivers); i++) { if (strcmp(name, flash_drivers[i]->name) == 0) return flash_drivers[i]; } diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index f8e0886570..e402867912 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -88,14 +88,14 @@ enum efm32_bank_index { static int efm32x_get_bank_index(target_addr_t base) { switch (base) { - case EFM32_FLASH_BASE: - return EFM32_BANK_INDEX_MAIN; - case EFM32_MSC_USER_DATA: - return EFM32_BANK_INDEX_USER_DATA; - case EFM32_MSC_LOCK_BITS: - return EFM32_BANK_INDEX_LOCK_BITS; - default: - return ERROR_FAIL; + case EFM32_FLASH_BASE: + return EFM32_BANK_INDEX_MAIN; + case EFM32_MSC_USER_DATA: + return EFM32_BANK_INDEX_USER_DATA; + case EFM32_MSC_LOCK_BITS: + return EFM32_BANK_INDEX_LOCK_BITS; + default: + return ERROR_FAIL; } } @@ -282,14 +282,14 @@ static int efm32x_read_info(struct flash_bank *bank) } switch (efm32_info->family_data->series) { - case 0: - efm32x_info->reg_base = EFM32_MSC_REGBASE; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; - break; - case 1: - efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; - efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; - break; + case 0: + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + break; + case 1: + efm32x_info->reg_base = EFM32_MSC_REGBASE_SERIES1; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK_SERIES1; + break; } if (efm32_info->family_data->msc_regbase != 0) @@ -430,7 +430,7 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, if (ret != ERROR_OK) break; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if (((status & wait_mask) == 0) && (wait_for_set == 0)) break; @@ -662,18 +662,18 @@ static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) uint32_t mask = 0; switch (bank->base) { - case EFM32_FLASH_BASE: - dw = efm32x_info->lb_page[page >> 5]; - mask = 1 << (page & 0x1f); - break; - case EFM32_MSC_USER_DATA: - dw = efm32x_info->lb_page[126]; - mask = 0x1; - break; - case EFM32_MSC_LOCK_BITS: - dw = efm32x_info->lb_page[126]; - mask = 0x2; - break; + case EFM32_FLASH_BASE: + dw = efm32x_info->lb_page[page >> 5]; + mask = 1 << (page & 0x1f); + break; + case EFM32_MSC_USER_DATA: + dw = efm32x_info->lb_page[126]; + mask = 0x1; + break; + case EFM32_MSC_LOCK_BITS: + dw = efm32x_info->lb_page[126]; + mask = 0x2; + break; } return (dw & mask) ? 0 : 1; diff --git a/src/flash/nor/em357.c b/src/flash/nor/em357.c index 207346f10d..cf005ca22d 100644 --- a/src/flash/nor/em357.c +++ b/src/flash/nor/em357.c @@ -115,7 +115,7 @@ static int em357_wait_status_busy(struct flash_bank *bank, int timeout) retval = em357_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { @@ -670,36 +670,36 @@ static int em357_probe(struct flash_bank *bank) em357_info->probed = false; switch (bank->size) { - case 0x10000: - /* 64k -- 64 1k pages */ - num_pages = 64; - page_size = 1024; - break; - case 0x20000: - /* 128k -- 128 1k pages */ - num_pages = 128; - page_size = 1024; - break; - case 0x30000: - /* 192k -- 96 2k pages */ - num_pages = 96; - page_size = 2048; - break; - case 0x40000: - /* 256k -- 128 2k pages */ - num_pages = 128; - page_size = 2048; - break; - case 0x80000: - /* 512k -- 256 2k pages */ - num_pages = 256; - page_size = 2048; - break; - default: - LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); - num_pages = 96; - page_size = 2048; - break; + case 0x10000: + /* 64k -- 64 1k pages */ + num_pages = 64; + page_size = 1024; + break; + case 0x20000: + /* 128k -- 128 1k pages */ + num_pages = 128; + page_size = 1024; + break; + case 0x30000: + /* 192k -- 96 2k pages */ + num_pages = 96; + page_size = 2048; + break; + case 0x40000: + /* 256k -- 128 2k pages */ + num_pages = 128; + page_size = 2048; + break; + case 0x80000: + /* 512k -- 256 2k pages */ + num_pages = 256; + page_size = 2048; + break; + default: + LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); + num_pages = 96; + page_size = 2048; + break; } /* Enable FPEC CLK */ diff --git a/src/flash/nor/jtagspi.c b/src/flash/nor/jtagspi.c index 4b975390be..e1bb17ab1f 100644 --- a/src/flash/nor/jtagspi.c +++ b/src/flash/nor/jtagspi.c @@ -230,7 +230,7 @@ COMMAND_HANDLER(jtagspi_handle_set) */ retval = CALL_COMMAND_HANDLER(flash_command_get_bank_probe_optional, 0, &bank, false); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; info = bank->driver_priv; @@ -420,7 +420,7 @@ COMMAND_HANDLER(jtagspi_handle_always_4byte) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; jtagspi_info = bank->driver_priv; diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 85c306bd44..82e68de3fb 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -2145,24 +2145,24 @@ static int kinetis_probe_chip_s32k(struct kinetis_chip *k_chip) k_chip->max_flash_prog_size = 512; switch (k_chip->sim_sdid & KINETIS_SDID_S32K_DERIVATE_MASK) { - case KINETIS_SDID_S32K_DERIVATE_KXX6: - /* S32K116 CPU 48Mhz Flash 128KB RAM 17KB+2KB */ - /* Non-Interleaved */ - k_chip->pflash_size = 128 << 10; - k_chip->pflash_sector_size = 2 << 10; - /* Non-Interleaved */ - k_chip->nvm_size = 32 << 10; - k_chip->nvm_sector_size = 2 << 10; - break; - case KINETIS_SDID_S32K_DERIVATE_KXX8: - /* S32K118 CPU 80Mhz Flash 256KB+32KB RAM 32KB+4KB */ - /* Non-Interleaved */ - k_chip->pflash_size = 256 << 10; - k_chip->pflash_sector_size = 2 << 10; - /* Non-Interleaved */ - k_chip->nvm_size = 32 << 10; - k_chip->nvm_sector_size = 2 << 10; - break; + case KINETIS_SDID_S32K_DERIVATE_KXX6: + /* S32K116 CPU 48Mhz Flash 128KB RAM 17KB+2KB */ + /* Non-Interleaved */ + k_chip->pflash_size = 128 << 10; + k_chip->pflash_sector_size = 2 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 32 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; + case KINETIS_SDID_S32K_DERIVATE_KXX8: + /* S32K118 CPU 80Mhz Flash 256KB+32KB RAM 32KB+4KB */ + /* Non-Interleaved */ + k_chip->pflash_size = 256 << 10; + k_chip->pflash_sector_size = 2 << 10; + /* Non-Interleaved */ + k_chip->nvm_size = 32 << 10; + k_chip->nvm_sector_size = 2 << 10; + break; } break; diff --git a/src/flash/nor/kinetis_ke.c b/src/flash/nor/kinetis_ke.c index 8207504b5f..51d5cb504b 100644 --- a/src/flash/nor/kinetis_ke.c +++ b/src/flash/nor/kinetis_ke.c @@ -238,19 +238,18 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) * Trim internal clock */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Both KE02_20 and KE02_40 should get the same trim value */ - trim_value = 0x4C; - break; - - case KINETIS_KE_SRSID_KEX4: - trim_value = 0x54; - break; - - case KINETIS_KE_SRSID_KEX6: - trim_value = 0x58; - break; + case KINETIS_KE_SRSID_KEX2: + /* Both KE02_20 and KE02_40 should get the same trim value */ + trim_value = 0x4C; + break; + + case KINETIS_KE_SRSID_KEX4: + trim_value = 0x54; + break; + + case KINETIS_KE_SRSID_KEX6: + trim_value = 0x58; + break; } result = target_read_u8(target, ICS_C4, &c4); @@ -293,54 +292,52 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) * Configure SIM (bus clock) */ switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { + /* KE02 sub-family operates on SIM_BUSDIV */ + case KINETIS_KE_SRSID_KEX2: + bus_reg_val = 0; + bus_reg_addr = SIM_BUSDIV; + bus_clock = 20000000; + break; + + /* KE04 and KE06 sub-family operates on SIM_CLKDIV + * Clocks are divided by: + * DIV1 = core clock = 48MHz + * DIV2 = bus clock = 24Mhz + * DIV3 = timer clocks + * So we need to configure SIM_CLKDIV, DIV1 and DIV2 value + */ + case KINETIS_KE_SRSID_KEX4: + /* KE04 devices have the SIM_CLKDIV register at a different offset + * depending on the pin count. */ + switch (KINETIS_KE_SRSID_PINCOUNT(kinfo->sim_srsid)) { + /* 16, 20 and 24 pins */ + case 1: + case 2: + case 3: + bus_reg_addr = SIM_CLKDIV_KE04_16_20_24; + break; - /* KE02 sub-family operates on SIM_BUSDIV */ - case KINETIS_KE_SRSID_KEX2: - bus_reg_val = 0; - bus_reg_addr = SIM_BUSDIV; - bus_clock = 20000000; + /* 44, 64 and 80 pins */ + case 5: + case 7: + case 8: + bus_reg_addr = SIM_CLKDIV_KE04_44_64_80; break; - /* KE04 and KE06 sub-family operates on SIM_CLKDIV - * Clocks are divided by: - * DIV1 = core clock = 48MHz - * DIV2 = bus clock = 24Mhz - * DIV3 = timer clocks - * So we need to configure SIM_CLKDIV, DIV1 and DIV2 value - */ - case KINETIS_KE_SRSID_KEX4: - /* KE04 devices have the SIM_CLKDIV register at a different offset - * depending on the pin count. */ - switch (KINETIS_KE_SRSID_PINCOUNT(kinfo->sim_srsid)) { - - /* 16, 20 and 24 pins */ - case 1: - case 2: - case 3: - bus_reg_addr = SIM_CLKDIV_KE04_16_20_24; - break; - - /* 44, 64 and 80 pins */ - case 5: - case 7: - case 8: - bus_reg_addr = SIM_CLKDIV_KE04_44_64_80; - break; - - default: - LOG_ERROR("KE04 - Unknown pin count"); - return ERROR_FAIL; - } + default: + LOG_ERROR("KE04 - Unknown pin count"); + return ERROR_FAIL; + } - bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; - bus_clock = 24000000; - break; + bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; + bus_clock = 24000000; + break; - case KINETIS_KE_SRSID_KEX6: - bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; - bus_reg_addr = SIM_CLKDIV_KE06; - bus_clock = 24000000; - break; + case KINETIS_KE_SRSID_KEX6: + bus_reg_val = SIM_CLKDIV_OUTDIV2_MASK; + bus_reg_addr = SIM_CLKDIV_KE06; + bus_clock = 24000000; + break; } result = target_write_u32(target, bus_reg_addr, bus_reg_val); @@ -357,20 +354,19 @@ static int kinetis_ke_prepare_flash(struct flash_bank *bank) c2 &= ~ICS_C2_BDIV_MASK; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Note: since there are two KE02 types, the KE02_40 @ 40MHz and the - * KE02_20 @ 20MHz, we divide here the ~40MHz ICSFLLCLK down to 20MHz, - * for compatibility. - */ - c2 |= ICS_C2_BDIV(1); - break; - - case KINETIS_KE_SRSID_KEX4: - case KINETIS_KE_SRSID_KEX6: - /* For KE04 and KE06, the ICSFLLCLK can be 48MHz. */ - c2 |= ICS_C2_BDIV(0); - break; + case KINETIS_KE_SRSID_KEX2: + /* Note: since there are two KE02 types, the KE02_40 @ 40MHz and the + * KE02_20 @ 20MHz, we divide here the ~40MHz ICSFLLCLK down to 20MHz, + * for compatibility. + */ + c2 |= ICS_C2_BDIV(1); + break; + + case KINETIS_KE_SRSID_KEX4: + case KINETIS_KE_SRSID_KEX6: + /* For KE04 and KE06, the ICSFLLCLK can be 48MHz. */ + c2 |= ICS_C2_BDIV(0); + break; } result = target_write_u8(target, ICS_C2, c2); @@ -1052,21 +1048,21 @@ static int kinetis_ke_probe(struct flash_bank *bank) } switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - case KINETIS_KE_SRSID_KEX2: - LOG_INFO("KE02 sub-family"); - break; + case KINETIS_KE_SRSID_KEX2: + LOG_INFO("KE02 sub-family"); + break; - case KINETIS_KE_SRSID_KEX4: - LOG_INFO("KE04 sub-family"); - break; + case KINETIS_KE_SRSID_KEX4: + LOG_INFO("KE04 sub-family"); + break; - case KINETIS_KE_SRSID_KEX6: - LOG_INFO("KE06 sub-family"); - break; + case KINETIS_KE_SRSID_KEX6: + LOG_INFO("KE06 sub-family"); + break; - default: - LOG_ERROR("Unsupported KE sub-family"); - return ERROR_FLASH_OPER_UNSUPPORTED; + default: + LOG_ERROR("Unsupported KE sub-family"); + return ERROR_FLASH_OPER_UNSUPPORTED; } /* We can only retrieve the ke0x part, but there is no way to know @@ -1077,41 +1073,40 @@ static int kinetis_ke_probe(struct flash_bank *bank) kinfo->sector_size = 512; switch (KINETIS_KE_SRSID_SUBFAMID(kinfo->sim_srsid)) { - - case KINETIS_KE_SRSID_KEX2: - /* Max. 64KB */ - bank->size = 0x00010000; - bank->num_sectors = 128; - - /* KE02 uses the FTMRH flash controller, - * and registers have a different offset from the - * FTMRE flash controller. Sort this out here. - */ - kinfo->ftmrx_fclkdiv_addr = 0x40020000; - kinfo->ftmrx_fccobix_addr = 0x40020002; - kinfo->ftmrx_fstat_addr = 0x40020006; - kinfo->ftmrx_fprot_addr = 0x40020008; - kinfo->ftmrx_fccobhi_addr = 0x4002000A; - kinfo->ftmrx_fccoblo_addr = 0x4002000B; - break; - - case KINETIS_KE_SRSID_KEX6: - case KINETIS_KE_SRSID_KEX4: - /* Max. 128KB */ - bank->size = 0x00020000; - bank->num_sectors = 256; - - /* KE04 and KE06 use the FTMRE flash controller, - * and registers have a different offset from the - * FTMRH flash controller. Sort this out here. - */ - kinfo->ftmrx_fclkdiv_addr = 0x40020003; - kinfo->ftmrx_fccobix_addr = 0x40020001; - kinfo->ftmrx_fstat_addr = 0x40020005; - kinfo->ftmrx_fprot_addr = 0x4002000B; - kinfo->ftmrx_fccobhi_addr = 0x40020009; - kinfo->ftmrx_fccoblo_addr = 0x40020008; - break; + case KINETIS_KE_SRSID_KEX2: + /* Max. 64KB */ + bank->size = 0x00010000; + bank->num_sectors = 128; + + /* KE02 uses the FTMRH flash controller, + * and registers have a different offset from the + * FTMRE flash controller. Sort this out here. + */ + kinfo->ftmrx_fclkdiv_addr = 0x40020000; + kinfo->ftmrx_fccobix_addr = 0x40020002; + kinfo->ftmrx_fstat_addr = 0x40020006; + kinfo->ftmrx_fprot_addr = 0x40020008; + kinfo->ftmrx_fccobhi_addr = 0x4002000A; + kinfo->ftmrx_fccoblo_addr = 0x4002000B; + break; + + case KINETIS_KE_SRSID_KEX6: + case KINETIS_KE_SRSID_KEX4: + /* Max. 128KB */ + bank->size = 0x00020000; + bank->num_sectors = 256; + + /* KE04 and KE06 use the FTMRE flash controller, + * and registers have a different offset from the + * FTMRH flash controller. Sort this out here. + */ + kinfo->ftmrx_fclkdiv_addr = 0x40020003; + kinfo->ftmrx_fccobix_addr = 0x40020001; + kinfo->ftmrx_fstat_addr = 0x40020005; + kinfo->ftmrx_fprot_addr = 0x4002000B; + kinfo->ftmrx_fccobhi_addr = 0x40020009; + kinfo->ftmrx_fccoblo_addr = 0x40020008; + break; } free(bank->sectors); diff --git a/src/flash/nor/lpc2000.c b/src/flash/nor/lpc2000.c index 09d35f604a..1b338ee2e6 100644 --- a/src/flash/nor/lpc2000.c +++ b/src/flash/nor/lpc2000.c @@ -383,40 +383,40 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) /* variant 2 has a uniform layout, only number of sectors differs */ switch (bank->size) { - case 4 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 1; - break; - case 8 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 2; - break; - case 16 * 1024: - bank->num_sectors = 4; - break; - case 32 * 1024: - bank->num_sectors = 8; - break; - case 64 * 1024: - bank->num_sectors = 9; - break; - case 128 * 1024: - bank->num_sectors = 11; - break; - case 256 * 1024: - bank->num_sectors = 15; - break; - case 500 * 1024: - bank->num_sectors = 27; - break; - case 512 * 1024: - case 504 * 1024: - bank->num_sectors = 28; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); - break; + case 4 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 1; + break; + case 8 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 2; + break; + case 16 * 1024: + bank->num_sectors = 4; + break; + case 32 * 1024: + bank->num_sectors = 8; + break; + case 64 * 1024: + bank->num_sectors = 9; + break; + case 128 * 1024: + bank->num_sectors = 11; + break; + case 256 * 1024: + bank->num_sectors = 15; + break; + case 500 * 1024: + bank->num_sectors = 27; + break; + case 512 * 1024: + case 504 * 1024: + bank->num_sectors = 28; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); + break; } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -448,37 +448,37 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 4 * 1024: - lpc2000_info->cmd51_max_buffer = 256; - bank->num_sectors = 1; - break; - case 8 * 1024: - lpc2000_info->cmd51_max_buffer = 512; - bank->num_sectors = 2; - break; - case 16 * 1024: - lpc2000_info->cmd51_max_buffer = 512; - bank->num_sectors = 4; - break; - case 32 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; - bank->num_sectors = 8; - break; - case 64 * 1024: - bank->num_sectors = 16; - break; - case 128 * 1024: - bank->num_sectors = 18; + case 4 * 1024: + lpc2000_info->cmd51_max_buffer = 256; + bank->num_sectors = 1; break; - case 256 * 1024: - bank->num_sectors = 22; - break; - case 512 * 1024: - bank->num_sectors = 30; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 8 * 1024: + lpc2000_info->cmd51_max_buffer = 512; + bank->num_sectors = 2; + break; + case 16 * 1024: + lpc2000_info->cmd51_max_buffer = 512; + bank->num_sectors = 4; + break; + case 32 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; + bank->num_sectors = 8; + break; + case 64 * 1024: + bank->num_sectors = 16; + break; + case 128 * 1024: + bank->num_sectors = 18; + break; + case 256 * 1024: + bank->num_sectors = 22; + break; + case 512 * 1024: + bank->num_sectors = 30; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -497,18 +497,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 208; switch (bank->size) { - case 256 * 1024: - bank->num_sectors = 11; - break; - case 384 * 1024: - bank->num_sectors = 13; - break; - case 512 * 1024: - bank->num_sectors = 15; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 256 * 1024: + bank->num_sectors = 11; + break; + case 384 * 1024: + bank->num_sectors = 13; + break; + case 512 * 1024: + bank->num_sectors = 15; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -529,30 +529,30 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->cmd51_max_buffer = 256; /* smallest MCU in the series, LPC810, has 1 kB of SRAM */ switch (bank->size) { - case 4 * 1024: - bank->num_sectors = 4; - break; - case 8 * 1024: - bank->num_sectors = 8; - break; - case 16 * 1024: - bank->num_sectors = 16; - 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: - lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ - bank->num_sectors = 32; - break; - case 64 * 1024: - lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */ - bank->num_sectors = 64; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 4 * 1024: + bank->num_sectors = 4; + break; + case 8 * 1024: + bank->num_sectors = 8; + break; + case 16 * 1024: + bank->num_sectors = 16; + 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: + lpc2000_info->cmd51_max_buffer = 1024; /* For LPC824, has 8kB of SRAM */ + bank->num_sectors = 32; + break; + case 64 * 1024: + lpc2000_info->cmd51_max_buffer = 1024; /* For LPC844, has 8kB of SRAM */ + bank->num_sectors = 64; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -602,18 +602,18 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 64 * 1024: - bank->num_sectors = 16; - break; - case 128 * 1024: - bank->num_sectors = 32; - break; - case 256 * 1024: - bank->num_sectors = 64; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 64 * 1024: + bank->num_sectors = 16; + break; + case 128 * 1024: + bank->num_sectors = 32; + break; + case 256 * 1024: + bank->num_sectors = 64; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -633,15 +633,15 @@ static int lpc2000_build_sector_list(struct flash_bank *bank) lpc2000_info->iap_max_stack = 128; switch (bank->size) { - case 256 * 1024: - bank->num_sectors = 8; - break; - case 512 * 1024: - bank->num_sectors = 16; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 256 * 1024: + bank->num_sectors = 8; + break; + case 512 * 1024: + bank->num_sectors = 16; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); @@ -686,24 +686,24 @@ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working /* write IAP code to working area */ switch (lpc2000_info->variant) { - case LPC800: - case LPC1100: - case LPC1500: - case LPC1700: - case LPC4300: - case LPC54100: - case LPC_AUTO: - target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); - target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); - break; - case LPC2000_V1: - case LPC2000_V2: - target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); - target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); - break; - default: - LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); - exit(-1); + case LPC800: + case LPC1100: + case LPC1500: + case LPC1700: + case LPC4300: + case LPC54100: + case LPC_AUTO: + target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); + target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); + break; + case LPC2000_V1: + case LPC2000_V2: + target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); + target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); + break; + default: + LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); + exit(-1); } int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); @@ -729,36 +729,36 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo uint32_t iap_entry_point = 0; /* to make compiler happier */ switch (lpc2000_info->variant) { - case LPC800: - case LPC1100: - case LPC1700: - case LPC_AUTO: - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - iap_entry_point = 0x1fff1ff1; - break; - case LPC1500: - case LPC54100: - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - iap_entry_point = 0x03000205; - break; - case LPC2000_V1: - case LPC2000_V2: - arm_algo.common_magic = ARM_COMMON_MAGIC; - arm_algo.core_mode = ARM_MODE_SVC; - arm_algo.core_state = ARM_STATE_ARM; - iap_entry_point = 0x7ffffff1; - break; - case LPC4300: - armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; - armv7m_info.core_mode = ARM_MODE_THREAD; - /* read out IAP entry point from ROM driver table at 0x10400100 */ - target_read_u32(target, 0x10400100, &iap_entry_point); - break; - default: - LOG_ERROR("BUG: unknown lpc2000->variant encountered"); - exit(-1); + case LPC800: + case LPC1100: + case LPC1700: + case LPC_AUTO: + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + iap_entry_point = 0x1fff1ff1; + break; + case LPC1500: + case LPC54100: + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + iap_entry_point = 0x03000205; + break; + case LPC2000_V1: + case LPC2000_V2: + arm_algo.common_magic = ARM_COMMON_MAGIC; + arm_algo.core_mode = ARM_MODE_SVC; + arm_algo.core_state = ARM_STATE_ARM; + iap_entry_point = 0x7ffffff1; + break; + case LPC4300: + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + /* read out IAP entry point from ROM driver table at 0x10400100 */ + target_read_u32(target, 0x10400100, &iap_entry_point); + break; + default: + LOG_ERROR("BUG: unknown lpc2000->variant encountered"); + exit(-1); } if (lpc2000_info->iap_entry_alternative != 0x0) @@ -791,43 +791,43 @@ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_wo buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { - case LPC800: - case LPC1100: - case LPC1500: - case LPC1700: - case LPC4300: - case LPC54100: - case LPC_AUTO: - /* IAP stack */ - init_reg_param(®_params[3], "sp", 32, PARAM_OUT); - buf_set_u32(reg_params[3].value, 0, 32, - iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); - - /* return address */ - init_reg_param(®_params[4], "lr", 32, PARAM_OUT); - buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); - /* bit0 of LR = 1 to return in Thumb mode */ - - target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, - &armv7m_info); - break; - case LPC2000_V1: - case LPC2000_V2: - /* IAP stack */ - init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); - buf_set_u32(reg_params[3].value, 0, 32, - iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); - - /* return address */ - init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); - buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); - - target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, - iap_working_area->address + 0x4, 10000, &arm_algo); - break; - default: - LOG_ERROR("BUG: unknown lpc2000->variant encountered"); - exit(-1); + case LPC800: + case LPC1100: + case LPC1500: + case LPC1700: + case LPC4300: + case LPC54100: + case LPC_AUTO: + /* IAP stack */ + init_reg_param(®_params[3], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[3].value, 0, 32, + iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); + + /* return address */ + init_reg_param(®_params[4], "lr", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); + /* bit0 of LR = 1 to return in Thumb mode */ + + target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, + &armv7m_info); + break; + case LPC2000_V1: + case LPC2000_V2: + /* IAP stack */ + init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); + buf_set_u32(reg_params[3].value, 0, 32, + iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); + + /* return address */ + init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); + buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); + + target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, + iap_working_area->address + 0x4, 10000, &arm_algo); + break; + default: + LOG_ERROR("BUG: unknown lpc2000->variant encountered"); + exit(-1); } int status_code = target_buffer_get_u32(target, mem_params[1].value); @@ -877,24 +877,24 @@ static int lpc2000_iap_blank_check(struct flash_bank *bank, unsigned int first, int status_code = lpc2000_iap_call(bank, iap_working_area, 53, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - bank->sectors[i].is_erased = 1; - break; - case LPC2000_SECTOR_NOT_BLANK: - bank->sectors[i].is_erased = 0; - break; - case LPC2000_INVALID_SECTOR: - bank->sectors[i].is_erased = 0; - break; - case LPC2000_BUSY: - retval = ERROR_FLASH_BUSY; - break; - default: - LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); - exit(-1); + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + bank->sectors[i].is_erased = 1; + break; + case LPC2000_SECTOR_NOT_BLANK: + bank->sectors[i].is_erased = 0; + break; + case LPC2000_INVALID_SECTOR: + bank->sectors[i].is_erased = 0; + break; + case LPC2000_BUSY: + retval = ERROR_FLASH_BUSY; + break; + default: + LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); + exit(-1); } } @@ -1002,6 +1002,28 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, /* Prepare sectors */ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if (retval == ERROR_OK) { + /* Erase sectors */ + param_table[2] = lpc2000_info->cclk; + if (lpc2000_info->variant == LPC4300) + param_table[3] = lpc2000_info->lpc4300_bank; + + status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); + switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; @@ -1011,31 +1033,9 @@ static int lpc2000_erase(struct flash_bank *bank, unsigned int first, retval = ERROR_FLASH_SECTOR_INVALID; break; default: - LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + LOG_WARNING("lpc2000 erase sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; - } - - if (retval == ERROR_OK) { - /* Erase sectors */ - param_table[2] = lpc2000_info->cclk; - if (lpc2000_info->variant == LPC4300) - param_table[3] = lpc2000_info->lpc4300_bank; - - status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); - switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 erase sectors returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; } } @@ -1145,18 +1145,18 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } /* Exit if error occurred */ @@ -1187,18 +1187,18 @@ static int lpc2000_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, iap_working_area, 51, param_table, result_table); switch (status_code) { - case ERROR_FLASH_OPERATION_FAILED: - retval = ERROR_FLASH_OPERATION_FAILED; - break; - case LPC2000_CMD_SUCCESS: - break; - case LPC2000_INVALID_SECTOR: - retval = ERROR_FLASH_SECTOR_INVALID; - break; - default: - LOG_WARNING("lpc2000 returned %i", status_code); - retval = ERROR_FLASH_OPERATION_FAILED; - break; + case ERROR_FLASH_OPERATION_FAILED: + retval = ERROR_FLASH_OPERATION_FAILED; + break; + case LPC2000_CMD_SUCCESS: + break; + case LPC2000_INVALID_SECTOR: + retval = ERROR_FLASH_SECTOR_INVALID; + break; + default: + LOG_WARNING("lpc2000 returned %i", status_code); + retval = ERROR_FLASH_OPERATION_FAILED; + break; } /* Exit if error occurred */ @@ -1267,240 +1267,240 @@ static int lpc2000_auto_probe_flash(struct flash_bank *bank) } switch (part_id) { - case LPC1110_1: - case LPC1110_2: - lpc2000_info->variant = LPC1100; - bank->size = 4 * 1024; - break; - - case LPC1111_002_1: - case LPC1111_002_2: - case LPC1111_101_1: - case LPC1111_101_2: - case LPC1111_103_1: - case LPC1111_201_1: - case LPC1111_201_2: - case LPC1111_203_1: - case LPC11A11_001_1: - case LPC11E11_101: - case LPC1311: - case LPC1311_1: - lpc2000_info->variant = LPC1100; - bank->size = 8 * 1024; - break; - - case LPC1112_101_1: - case LPC1112_101_2: - case LPC1112_102_1: - case LPC1112_102_2: - case LPC1112_103_1: - case LPC1112_201_1: - case LPC1112_201_2: - case LPC1112_203_1: - case LPC11A02_1: - case LPC11C12_301_1: - case LPC11C22_301_1: - case LPC11A12_101_1: - case LPC11E12_201: - case LPC11U12_201_1: - case LPC11U12_201_2: - case LPC1342: - lpc2000_info->variant = LPC1100; - bank->size = 16 * 1024; - break; - - case LPC1113_201_1: - case LPC1113_201_2: - case LPC1113_203_1: - case LPC1113_301_1: - case LPC1113_301_2: - case LPC1113_303_1: - case LPC11A13_201_1: - case LPC11E13_301: - case LPC11U13_201_1: - case LPC11U13_201_2: - case LPC11U23_301: - lpc2000_info->variant = LPC1100; - bank->size = 24 * 1024; - break; - - case LPC1114_102_1: - case LPC1114_102_2: - case LPC1114_201_1: - case LPC1114_201_2: - case LPC1114_203_1: - case LPC1114_301_1: - case LPC1114_301_2: - case LPC1114_303_1: - case LPC11A04_1: - case LPC11A14_301_1: - case LPC11A14_301_2: - case LPC11C14_301_1: - case LPC11C24_301_1: - case LPC11E14_401: - case LPC11U14_201_1: - case LPC11U14_201_2: - case LPC11U24_301: - case LPC11U24_401: - case LPC1313: - case LPC1313_1: - case LPC1315: - case LPC1343: - case LPC1343_1: - case LPC1345: - lpc2000_info->variant = LPC1100; - bank->size = 32 * 1024; - break; - - case LPC1751_1: - case LPC1751_2: - lpc2000_info->variant = LPC1700; - bank->size = 32 * 1024; - break; - - case LPC11U34_311: - lpc2000_info->variant = LPC1100; - bank->size = 40 * 1024; - break; - - case LPC1114_323_1: - case LPC11U34_421: - case LPC1316: - case LPC1346: - lpc2000_info->variant = LPC1100; - bank->size = 48 * 1024; - break; - - case LPC1114_333_1: - lpc2000_info->variant = LPC1100; - bank->size = 56 * 1024; - break; - - case LPC1115_303_1: - case LPC11U35_401: - case LPC11U35_501: - case LPC11E66: - case LPC11U66: - case LPC1317: - case LPC1347: - lpc2000_info->variant = LPC1100; - bank->size = 64 * 1024; - break; - - case LPC1752: - case LPC4072: - lpc2000_info->variant = LPC1700; - bank->size = 64 * 1024; - break; + case LPC1110_1: + case LPC1110_2: + lpc2000_info->variant = LPC1100; + bank->size = 4 * 1024; + break; + + case LPC1111_002_1: + case LPC1111_002_2: + case LPC1111_101_1: + case LPC1111_101_2: + case LPC1111_103_1: + case LPC1111_201_1: + case LPC1111_201_2: + case LPC1111_203_1: + case LPC11A11_001_1: + case LPC11E11_101: + case LPC1311: + case LPC1311_1: + lpc2000_info->variant = LPC1100; + bank->size = 8 * 1024; + break; + + case LPC1112_101_1: + case LPC1112_101_2: + case LPC1112_102_1: + case LPC1112_102_2: + case LPC1112_103_1: + case LPC1112_201_1: + case LPC1112_201_2: + case LPC1112_203_1: + case LPC11A02_1: + case LPC11C12_301_1: + case LPC11C22_301_1: + case LPC11A12_101_1: + case LPC11E12_201: + case LPC11U12_201_1: + case LPC11U12_201_2: + case LPC1342: + lpc2000_info->variant = LPC1100; + bank->size = 16 * 1024; + break; + + case LPC1113_201_1: + case LPC1113_201_2: + case LPC1113_203_1: + case LPC1113_301_1: + case LPC1113_301_2: + case LPC1113_303_1: + case LPC11A13_201_1: + case LPC11E13_301: + case LPC11U13_201_1: + case LPC11U13_201_2: + case LPC11U23_301: + lpc2000_info->variant = LPC1100; + bank->size = 24 * 1024; + break; + + case LPC1114_102_1: + case LPC1114_102_2: + case LPC1114_201_1: + case LPC1114_201_2: + case LPC1114_203_1: + case LPC1114_301_1: + case LPC1114_301_2: + case LPC1114_303_1: + case LPC11A04_1: + case LPC11A14_301_1: + case LPC11A14_301_2: + case LPC11C14_301_1: + case LPC11C24_301_1: + case LPC11E14_401: + case LPC11U14_201_1: + case LPC11U14_201_2: + case LPC11U24_301: + case LPC11U24_401: + case LPC1313: + case LPC1313_1: + case LPC1315: + case LPC1343: + case LPC1343_1: + case LPC1345: + lpc2000_info->variant = LPC1100; + bank->size = 32 * 1024; + break; - case LPC11E36_501: - case LPC11U36_401: - lpc2000_info->variant = LPC1100; - bank->size = 96 * 1024; - break; + case LPC1751_1: + case LPC1751_2: + lpc2000_info->variant = LPC1700; + bank->size = 32 * 1024; + break; - case LPC11E37_401: - case LPC11E37_501: - case LPC11U37_401: - case LPC11U37H_401: - case LPC11U37_501: - case LPC11E67: - case LPC11E68: - case LPC11U67_1: - case LPC11U67_2: - lpc2000_info->variant = LPC1100; - bank->size = 128 * 1024; - break; + case LPC11U34_311: + lpc2000_info->variant = LPC1100; + bank->size = 40 * 1024; + break; - case LPC1754: - case LPC1764: - case LPC1774: - case LPC4074: - lpc2000_info->variant = LPC1700; - bank->size = 128 * 1024; - break; + case LPC1114_323_1: + case LPC11U34_421: + case LPC1316: + case LPC1346: + lpc2000_info->variant = LPC1100; + bank->size = 48 * 1024; + break; - case LPC11U68_1: - case LPC11U68_2: - lpc2000_info->variant = LPC1100; - bank->size = 256 * 1024; - break; + case LPC1114_333_1: + lpc2000_info->variant = LPC1100; + bank->size = 56 * 1024; + break; + + case LPC1115_303_1: + case LPC11U35_401: + case LPC11U35_501: + case LPC11E66: + case LPC11U66: + case LPC1317: + case LPC1347: + lpc2000_info->variant = LPC1100; + bank->size = 64 * 1024; + break; - case LPC1756: - case LPC1763: - case LPC1765: - case LPC1766: - case LPC1776: - case LPC1785: - case LPC1786: - case LPC4076: - lpc2000_info->variant = LPC1700; - bank->size = 256 * 1024; - break; + case LPC1752: + case LPC4072: + lpc2000_info->variant = LPC1700; + bank->size = 64 * 1024; + break; - case LPC1758: - case LPC1759: - case LPC1767: - case LPC1768: - case LPC1769: - case LPC1777: - case LPC1778: - case LPC1787: - case LPC1788: - case LPC4078: - case LPC4088: - lpc2000_info->variant = LPC1700; - bank->size = 512 * 1024; - break; + case LPC11E36_501: + case LPC11U36_401: + lpc2000_info->variant = LPC1100; + bank->size = 96 * 1024; + break; + + case LPC11E37_401: + case LPC11E37_501: + case LPC11U37_401: + case LPC11U37H_401: + case LPC11U37_501: + case LPC11E67: + case LPC11E68: + case LPC11U67_1: + case LPC11U67_2: + lpc2000_info->variant = LPC1100; + bank->size = 128 * 1024; + break; - case LPC810_021: - lpc2000_info->variant = LPC800; - bank->size = 4 * 1024; - break; + case LPC1754: + case LPC1764: + case LPC1774: + case LPC4074: + lpc2000_info->variant = LPC1700; + bank->size = 128 * 1024; + break; - case LPC811_001: - lpc2000_info->variant = LPC800; - bank->size = 8 * 1024; - break; + case LPC11U68_1: + case LPC11U68_2: + lpc2000_info->variant = LPC1100; + bank->size = 256 * 1024; + break; + + case LPC1756: + case LPC1763: + case LPC1765: + case LPC1766: + case LPC1776: + case LPC1785: + case LPC1786: + case LPC4076: + lpc2000_info->variant = LPC1700; + bank->size = 256 * 1024; + break; + + case LPC1758: + case LPC1759: + case LPC1767: + case LPC1768: + case LPC1769: + case LPC1777: + case LPC1778: + case LPC1787: + case LPC1788: + case LPC4078: + case LPC4088: + lpc2000_info->variant = LPC1700; + bank->size = 512 * 1024; + break; - case LPC812_101: - case LPC812_101_1: - case LPC812_101_2: - case LPC812_101_3: - case LPC822_101: - case LPC822_101_1: - lpc2000_info->variant = LPC800; - bank->size = 16 * 1024; - break; + case LPC810_021: + lpc2000_info->variant = LPC800; + bank->size = 4 * 1024; + break; - case LPC824_201: - case LPC824_201_1: - lpc2000_info->variant = LPC800; - bank->size = 32 * 1024; - break; + case LPC811_001: + lpc2000_info->variant = LPC800; + bank->size = 8 * 1024; + break; + + case LPC812_101: + case LPC812_101_1: + case LPC812_101_2: + case LPC812_101_3: + case LPC822_101: + case LPC822_101_1: + lpc2000_info->variant = LPC800; + bank->size = 16 * 1024; + break; - case LPC8N04: - case NHS3100: - case NHS3152: - case NHS3153: - lpc2000_info->variant = LPC800; - bank->size = 30 * 1024; - break; + case LPC824_201: + case LPC824_201_1: + lpc2000_info->variant = LPC800; + bank->size = 32 * 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; + 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: - LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); - exit(-1); + default: + LOG_ERROR("BUG: unknown Part ID encountered: 0x%" PRIx32, part_id); + exit(-1); } return ERROR_OK; diff --git a/src/flash/nor/lpc288x.c b/src/flash/nor/lpc288x.c index 3006db1cbf..d7a4fdf24f 100644 --- a/src/flash/nor/lpc288x.c +++ b/src/flash/nor/lpc288x.c @@ -279,7 +279,7 @@ static int lpc288x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ /* all writes must start on a sector boundary... */ if (offset % bank->sectors[i].size) { LOG_INFO( - "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", + "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, bank->sectors[i].size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; @@ -293,7 +293,7 @@ static int lpc288x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ /* Range check... */ if (first_sector == 0xffffffff || last_sector == 0xffffffff) { - LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count); + LOG_INFO("Range check failed %" PRIx32 " %" PRIx32, offset, count); return ERROR_FLASH_DST_OUT_OF_BANK; } diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c index 267fd43120..e91b9b67d5 100644 --- a/src/flash/nor/max32xxx.c +++ b/src/flash/nor/max32xxx.c @@ -2,7 +2,7 @@ /*************************************************************************** * Copyright (C) 2016 by Maxim Integrated * - * Kevin Gillespie * + * Copyright (C) 2025 Analog Devices, Inc. * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -13,90 +13,112 @@ #include #include #include - -/* Register Addresses */ -#define FLSH_ADDR 0x000 -#define FLSH_CLKDIV 0x004 -#define FLSH_CN 0x008 -#define PR1E_ADDR 0x00C -#define PR2S_ADDR 0x010 -#define PR2E_ADDR 0x014 -#define PR3S_ADDR 0x018 -#define PR3E_ADDR 0x01C -#define FLSH_MD 0x020 -#define FLSH_INT 0x024 -#define FLSH_DATA0 0x030 -#define FLSH_DATA1 0x034 -#define FLSH_DATA2 0x038 -#define FLSH_DATA3 0x03C -#define FLSH_BL_CTRL 0x170 -#define FLSH_PROT 0x300 - -#define ARM_PID_REG 0xE00FFFE0 -#define MAX326XX_ID_REG 0x40000838 - -/* Register settings */ -#define FLSH_INT_AF 0x00000002 - -#define FLSH_CN_UNLOCK_MASK 0xF0000000 -#define FLSH_CN_UNLOCK_VALUE 0x20000000 - -#define FLSH_CN_PEND 0x01000000 - -#define FLSH_CN_ERASE_CODE_MASK 0x0000FF00 -#define FLSH_CN_ERASE_CODE_PGE 0x00005500 -#define FLSH_CN_ERASE_CODE_ME 0x0000AA00 - -#define FLSH_CN_PGE 0x00000004 -#define FLSH_CN_ME 0x00000002 -#define FLSH_CN_WR 0x00000001 -#define FLASH_BL_CTRL_23 0x00020000 -#define FLASH_BL_CTRL_IFREN 0x00000001 - -#define ARM_PID_DEFAULT_CM3 0xB4C3 -#define ARM_PID_DEFAULT_CM4 0xB4C4 -#define MAX326XX_ID 0x4D +#include +#include + +// Register addresses +#define FLC_ADDR 0x00000000 +#define FLC_CLKDIV 0x00000004 +#define FLC_CN 0x00000008 +#define FLC_PR1E_ADDR 0x0000000C +#define FLC_PR2S_ADDR 0x00000010 +#define FLC_PR2E_ADDR 0x00000014 +#define FLC_PR3S_ADDR 0x00000018 +#define FLC_PR3E_ADDR 0x0000001C +#define FLC_MD 0x00000020 +#define FLC_INT 0x00000024 +#define FLC_DATA0 0x00000030 +#define FLC_DATA1 0x00000034 +#define FLC_DATA2 0x00000038 +#define FLC_DATA3 0x0000003C +#define FLC_BL_CTRL 0x00000170 +#define FLC_PROT 0x00000300 + +#define ARM_PID_REG 0xE00FFFE0 +#define MAX326XX_ID_REG 0x40000838 + +// Register settings +#define FLC_INT_AF 0x00000002 + +#define FLC_CN_UNLOCK_MASK 0xF0000000 +#define FLC_CN_UNLOCK_VALUE 0x20000000 + +#define FLC_CN_PEND 0x01000000 +#define FLC_CN_ERASE_CODE_MASK 0x0000FF00 +#define FLC_CN_ERASE_CODE_PGE 0x00005500 +#define FLC_CN_ERASE_CODE_ME 0x0000AA00 +#define FLC_CN_32BIT 0x00000010 +#define FLC_CN_PGE 0x00000004 +#define FLC_CN_ME 0x00000002 +#define FLC_CN_WR 0x00000001 +#define FLC_CN_PGE 0x00000004 +#define FLC_CN_ME 0x00000002 +#define FLC_CN_WR 0x00000001 + +#define FLC_BL_CTRL_23 0x00020000 +#define FLC_BL_CTRL_IFREN 0x00000001 + +#define MASK_FLASH_BUSY (0x048800E0 & ~0x04000000) +#define MASK_DISABLE_INTS (0xFFFFFCFC) +#define MASK_FLASH_UNLOCKED (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_LOCK (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_ERASE (0xF588FFEF & ~0x04000000) +#define MASK_FLASH_ERASED (0xF48800EB & ~0x04000000) +#define MASK_ACCESS_VIOLATIONS (0xFFFFFCFC) +#define MASK_FLASH_WRITE (0xF588FFEF & ~0x04000000) +#define MASK_WRITE_ALIGNED (0xF588FFEF & ~0x04000000) +#define MASK_WRITE_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_WRITE_BURST (0xF588FFEF & ~0x04000000) +#define MASK_BURST_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_WRITE_REMAINING (0xF588FFEF & ~0x04000000) +#define MASK_REMAINING_COMPLETE (0xF488FFEE & ~0x04000000) +#define MASK_MASS_ERASE (0xF588FFEF & ~0x04000000) +#define MASK_ERASE_COMPLETE (0xF48800ED & ~0x04000000) + +#define ARM_PID_DEFAULT_CM3 0x0000B4C3 +#define ARM_PID_DEFAULT_CM4 0x0000B4C4 +#define MAX326XX_ID 0x0000004D + +#define OPTIONS_128 0x01 // Perform 128 bit flash writes +#define OPTIONS_ENC 0x02 // Encrypt the flash contents +#define OPTIONS_AUTH 0x04 // Authenticate the flash contents +#define OPTIONS_COUNT 0x08 // Add counter values to authentication +#define OPTIONS_INTER 0x10 // Interleave the authentication and count values +#define OPTIONS_RELATIVE_XOR 0x20 // Only XOR the offset of the address when encrypting +#define OPTIONS_KEYSIZE 0x40 // Use a 256 bit KEY static int max32xxx_mass_erase(struct flash_bank *bank); struct max32xxx_flash_bank { bool probed; - int max326xx; + bool max326xx; unsigned int flash_size; unsigned int flc_base; unsigned int sector_size; unsigned int clkdiv_value; - uint32_t int_state; - unsigned int burst_size_bits; + unsigned int int_state; + unsigned int options; }; -/* see contrib/loaders/flash/max32xxx/max32xxx.s for src */ -static const uint8_t write_code[] = { -#include "../../../contrib/loaders/flash/max32xxx/max32xxx.inc" +static const uint8_t write_code_arm[] = { +#include "../../../contrib/loaders/flash/max32xxx/max32xxx_write_arm.inc" }; -/* Config Command: flash bank name driver base size chip_width bus_width target [driver_option] - flash bank max32xxx 0 0 [burst_bits] - */ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command) { struct max32xxx_flash_bank *info; - if (CMD_ARGC < 9) { - LOG_WARNING("incomplete flash bank max32xxx configuration: 0 0 [burst_bits]"); + if (CMD_ARGC != 10) { + LOG_ERROR("incorrect flash bank max32xxx configuration: 0 0 "); return ERROR_FLASH_BANK_INVALID; } info = calloc(1, sizeof(struct max32xxx_flash_bank)); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], info->flash_size); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], info->flc_base); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], info->sector_size); - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[8], info->clkdiv_value); - - if (CMD_ARGC > 9) - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[9], info->burst_size_bits); - else - info->burst_size_bits = 32; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], info->flash_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->flc_base); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->sector_size); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], info->clkdiv_value); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], info->options); info->int_state = 0; bank->driver_priv = info; @@ -114,63 +136,67 @@ static int get_info(struct flash_bank *bank, struct command_invocation *cmd) return ERROR_OK; } -/*************************************************************************** -* flash operations -***************************************************************************/ +static bool max32xxx_flash_busy(uint32_t flash_cn) +{ + if (flash_cn & (FLC_CN_PGE | FLC_CN_ME | FLC_CN_WR)) + return true; + + return false; +} static int max32xxx_flash_op_pre(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; - uint32_t flsh_cn; + uint32_t flash_cn; uint32_t bootloader; - /* Check if the flash controller is busy */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - if (flsh_cn & (FLSH_CN_PEND | FLSH_CN_ERASE_CODE_MASK | FLSH_CN_PGE | - FLSH_CN_ME | FLSH_CN_WR)) + // Check if the flash controller is busy + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + if (max32xxx_flash_busy(flash_cn)) return ERROR_FLASH_BUSY; - /* Refresh flash controller timing */ - target_write_u32(target, info->flc_base + FLSH_CLKDIV, info->clkdiv_value); + // Refresh flash controller timing + target_write_u32(target, info->flc_base + FLC_CLKDIV, info->clkdiv_value); - /* Clear and disable flash programming interrupts */ - target_read_u32(target, info->flc_base + FLSH_INT, &info->int_state); - target_write_u32(target, info->flc_base + FLSH_INT, 0x00000000); + // Clear and disable flash programming interrupts + target_read_u32(target, info->flc_base + FLC_INT, &info->int_state); + target_write_u32(target, info->flc_base + FLC_INT, 0); - /* Clear the lower bit in the bootloader configuration register in case flash page 0 has been replaced */ - if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { - LOG_ERROR("Read failure on FLSH_BL_CTRL"); + /* Clear the lower bit in the bootloader configuration register in case flash page 0 has + * been replaced */ + if (target_read_u32(target, info->flc_base + FLC_BL_CTRL, &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (bootloader & FLASH_BL_CTRL_23) { - LOG_WARNING("FLSH_BL_CTRL indicates BL mode 2 or mode 3."); - if (bootloader & FLASH_BL_CTRL_IFREN) { + if (bootloader & FLC_BL_CTRL_23) { + LOG_WARNING("FLC_BL_CTRL indicates BL mode 2 or mode 3."); + if (bootloader & FLC_BL_CTRL_IFREN) { LOG_WARNING("Flash page 0 swapped out, attempting to swap back in for programming"); - bootloader &= ~(FLASH_BL_CTRL_IFREN); - if (target_write_u32(target, info->flc_base + FLSH_BL_CTRL, bootloader) != ERROR_OK) { - LOG_ERROR("Write failure on FLSH_BL_CTRL"); + bootloader &= ~(FLC_BL_CTRL_IFREN); + if (target_write_u32(target, info->flc_base + FLC_BL_CTRL, + bootloader) != ERROR_OK) { + LOG_ERROR("Write failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) { - LOG_ERROR("Read failure on FLSH_BL_CTRL"); + if (target_read_u32(target, info->flc_base + FLC_BL_CTRL, + &bootloader) != ERROR_OK) { + LOG_ERROR("Read failure on FLC_BL_CTRL"); return ERROR_FAIL; } - if (bootloader & FLASH_BL_CTRL_IFREN) { - /* Bummer */ + if (bootloader & FLC_BL_CTRL_IFREN) LOG_ERROR("Unable to swap flash page 0 back in. Writes to page 0 will fail."); - } } } - /* Unlock flash */ - flsh_cn &= ~FLSH_CN_UNLOCK_MASK; - flsh_cn |= FLSH_CN_UNLOCK_VALUE; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Unlock flash + flash_cn &= ~(FLC_CN_UNLOCK_MASK); + flash_cn |= FLC_CN_UNLOCK_VALUE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Confirm flash is unlocked */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - if ((flsh_cn & FLSH_CN_UNLOCK_VALUE) != FLSH_CN_UNLOCK_VALUE) + // Confirm flash is unlocked + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + if ((flash_cn & FLC_CN_UNLOCK_VALUE) != FLC_CN_UNLOCK_VALUE) return ERROR_FAIL; return ERROR_OK; @@ -180,15 +206,15 @@ static int max32xxx_flash_op_post(struct flash_bank *bank) { struct target *target = bank->target; struct max32xxx_flash_bank *info = bank->driver_priv; - uint32_t flsh_cn; + uint32_t flash_cn; - /* Restore flash programming interrupts */ - target_write_u32(target, info->flc_base + FLSH_INT, info->int_state); + // Restore flash programming interrupts + target_write_u32(target, info->flc_base + FLC_INT, info->int_state); - /* Lock flash */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= ~FLSH_CN_UNLOCK_MASK; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Lock flash + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_UNLOCK_MASK); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); return ERROR_OK; } @@ -208,12 +234,12 @@ static int max32xxx_protect_check(struct flash_bank *bank) return ERROR_FLASH_OPER_UNSUPPORTED; } - /* Check the protection */ + // Check the protection for (unsigned int i = 0; i < bank->num_sectors; i++) { - if (i%32 == 0) - target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg); + if (i % 32 == 0) + target_read_u32(target, info->flc_base + FLC_PROT + ((i / 32) * 4), &temp_reg); - if (temp_reg & (0x1 << i%32)) + if (temp_reg & (0x1 << i % 32)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; @@ -222,9 +248,9 @@ static int max32xxx_protect_check(struct flash_bank *bank) } static int max32xxx_erase(struct flash_bank *bank, unsigned int first, - unsigned int last) + unsigned int last) { - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; int retval; @@ -238,13 +264,13 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - if ((last < first) || (last >= bank->num_sectors)) + if (last < first || last >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; - if ((first == 0) && (last == (bank->num_sectors - 1))) + if (first == 0 && last == (bank->num_sectors - 1)) return max32xxx_mass_erase(bank); - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) @@ -252,43 +278,43 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, int erased = 0; for (unsigned int banknr = first; banknr <= last; banknr++) { - - /* Check the protection */ + // Check the protection if (bank->sectors[banknr].is_protected == 1) { LOG_WARNING("Flash sector %u is protected", banknr); continue; - } else + } else { erased = 1; + } - /* Address is first word in page */ - target_write_u32(target, info->flc_base + FLSH_ADDR, banknr * info->sector_size); + // Address is first word in page + target_write_u32(target, info->flc_base + FLC_ADDR, banknr * info->sector_size); - /* Write page erase code */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn |= FLSH_CN_ERASE_CODE_PGE; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Write page erase code + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_ERASE_CODE_PGE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Issue page erase command */ - flsh_cn |= 0x4; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Issue page erase command + flash_cn |= FLC_CN_PGE; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Wait until erase complete */ + // Wait until erase complete retry = 1000; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash page erase @ 0x%08x", - banknr * info->sector_size); + LOG_ERROR("Timed out waiting for flash page erase @ 0x%08" PRIx32, + (banknr * info->sector_size)); return ERROR_FLASH_OPERATION_FAILED; } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Error erasing flash page %i", banknr); - target_write_u32(target, info->flc_base + FLSH_INT, 0); + target_write_u32(target, info->flc_base + FLC_INT, 0); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -307,7 +333,7 @@ static int max32xxx_erase(struct flash_bank *bank, unsigned int first, } static int max32xxx_protect(struct flash_bank *bank, int set, - unsigned int first, unsigned int last) + unsigned int first, unsigned int last) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; @@ -324,22 +350,22 @@ static int max32xxx_protect(struct flash_bank *bank, int set, if (!info->max326xx) return ERROR_FLASH_OPER_UNSUPPORTED; - if ((last < first) || (last >= bank->num_sectors)) + if (last < first || last >= bank->num_sectors) return ERROR_FLASH_SECTOR_INVALID; - /* Setup the protection on the pages given */ + // Setup the protection on the pages given for (unsigned int page = first; page <= last; page++) { if (set) { - /* Set the write/erase bit for this page */ - target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); - temp_reg |= (0x1 << page%32); - target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + // Set the write/erase bit for this page + target_read_u32(target, info->flc_base + FLC_PROT + (page / 32), &temp_reg); + temp_reg |= (0x1 << page % 32); + target_write_u32(target, info->flc_base + FLC_PROT + (page / 32), temp_reg); bank->sectors[page].is_protected = 1; } else { - /* Clear the write/erase bit for this page */ - target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg); - temp_reg &= ~(0x1 << page%32); - target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg); + // Clear the write/erase bit for this page + target_read_u32(target, info->flc_base + FLC_PROT + (page / 32), &temp_reg); + temp_reg &= ~(0x1 << page % 32); + target_write_u32(target, info->flc_base + FLC_PROT + (page / 32), temp_reg); bank->sectors[page].is_protected = 0; } } @@ -348,38 +374,41 @@ static int max32xxx_protect(struct flash_bank *bank, int set, } static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t wcount) + uint32_t offset, uint32_t len) { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; + const char *target_type_name = (const char *)target->type->name; uint32_t buffer_size = 16384; struct working_area *source; struct working_area *write_algorithm; - uint32_t address = bank->base + offset; struct reg_param reg_params[5]; + struct mem_param mem_param[2]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* power of two, and multiple of word size */ + // power of two, and multiple of word size static const unsigned int buf_min = 128; + uint8_t *write_code; + int write_code_size; + - /* for small buffers it's faster not to download an algorithm */ - if (wcount * 4 < buf_min) + if (strcmp(target_type_name, "cortex_m") == 0) { + write_code = (uint8_t *)write_code_arm; + write_code_size = sizeof(write_code_arm); + } else { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", - bank, buffer, offset, wcount); + LOG_DEBUG("bank=%p buffer=%p offset=%08" PRIx32 " len=%08" PRIx32 "", + bank, buffer, offset, len); - /* flash write code */ - if (target_alloc_working_area(target, sizeof(write_code), &write_algorithm) != ERROR_OK) { + // flash write code + if (target_alloc_working_area(target, write_code_size, &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - /* plus a buffer big enough for this data */ - if (wcount * 4 < buffer_size) - buffer_size = wcount * 4; - - /* memory buffer */ + // memory buffer while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; @@ -392,24 +421,53 @@ static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer, target_name(target), buffer_size); } - target_write_buffer(target, write_algorithm->address, sizeof(write_code), + target_write_buffer(target, write_algorithm->address, write_code_size, write_code); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - init_reg_param(®_params[0], "r0", 32, PARAM_OUT); - init_reg_param(®_params[1], "r1", 32, PARAM_OUT); - init_reg_param(®_params[2], "r2", 32, PARAM_OUT); - init_reg_param(®_params[3], "r3", 32, PARAM_OUT); - init_reg_param(®_params[4], "r4", 32, PARAM_OUT); + + // TODO: a0-a3 for RISCV + + if (strcmp(target_type_name, "cortex_m") == 0) { + init_reg_param(®_params[0], "r0", 32, PARAM_OUT); + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + } else { + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); + init_reg_param(®_params[3], "a3", 32, PARAM_OUT); + } + init_reg_param(®_params[4], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[2].value, 0, 32, address); - buf_set_u32(reg_params[3].value, 0, 32, wcount); - buf_set_u32(reg_params[4].value, 0, 32, info->flc_base); - retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, - 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); + buf_set_u32(reg_params[2].value, 0, 32, len); + buf_set_u32(reg_params[3].value, 0, 32, offset); + buf_set_u32(reg_params[4].value, 0, 32, source->address + source->size); + + // mem_params for options + init_mem_param(&mem_param[0], source->address + (source->size - 8 - 128), 4, PARAM_OUT); + init_mem_param(&mem_param[1], source->address + (source->size - 4 - 128), 4, PARAM_OUT); + buf_set_u32(mem_param[0].value, 0, 32, info->options); + buf_set_u32(mem_param[1].value, 0, 32, info->flc_base); + + // leave room for stack, 32-bit options and encryption buffer + retval = target_run_flash_async_algorithm(target, + buffer, + len, + 1, + 2, + mem_param, + 5, + reg_params, + source->address, + (source->size - 8 - 256), + write_algorithm->address, + 0, + &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("error %d executing max32xxx flash write algorithm", retval); @@ -429,10 +487,9 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, { struct max32xxx_flash_bank *info = bank->driver_priv; struct target *target = bank->target; - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; uint32_t address = offset; uint32_t remaining = count; - uint32_t words_remaining; int retval; int retry; @@ -447,67 +504,74 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - if (offset & 0x3) { - LOG_WARNING("offset size must be word aligned"); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + if ((info->options & OPTIONS_128) == 0) { + if (offset & 0x3) { + LOG_ERROR("offset size must be 32-bit aligned"); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + } else { + if (offset & 0xF) { + LOG_ERROR("offset size must be 128-bit aligned"); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + max32xxx_flash_op_post(bank); return retval; + } - if (remaining >= 4) { - /* write in 32-bit units */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - - /* try using a block write */ - words_remaining = remaining / 4; - retval = max32xxx_write_block(bank, buffer, offset, words_remaining); + if (remaining >= 16) { + // try using a block write + retval = max32xxx_write_block(bank, buffer, offset, remaining); if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + if (info->options & OPTIONS_ENC) { + LOG_ERROR("Must use algorithm in working area for encryption"); + return ERROR_FLASH_OPERATION_FAILED; + } LOG_DEBUG("writing flash word-at-a-time"); - else { + } else { max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } else { - /* all 32-bit words have been written */ - buffer += words_remaining * 4; - address += words_remaining * 4; - remaining -= words_remaining * 4; + // all words_remaining have been written + buffer += remaining; + address += remaining; + remaining -= remaining; } } - if ((remaining >= 4) && ((address & 0x1F) != 0)) { - /* write in 32-bit units until we are 128-bit aligned */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + if (((info->options & OPTIONS_128) == 0) && remaining >= 4) { + // write in 32-bit units + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_32BIT; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - while ((remaining >= 4) && ((address & 0x1F) != 0)) { - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ + while (remaining >= 4) { + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, buffer); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, + address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -517,31 +581,32 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, } } - if ((info->burst_size_bits == 128) && (remaining >= 16)) { - /* write in 128-bit bursts while we can */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - - flsh_cn &= 0xFFFFFFEF; - flsh_cn |= 0x08000000; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - target_write_u32(target, info->flc_base + FLSH_ADDR, address); + if ((info->options & OPTIONS_128) && remaining >= 16) { + // write in 128-bit units + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_32BIT); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); while (remaining >= 16) { + target_write_u32(target, info->flc_base + FLC_ADDR, address); + if ((address & 0xFFF) == 0) LOG_DEBUG("Writing @ 0x%08" PRIx32, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 16, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ + target_write_buffer(target, info->flc_base + FLC_DATA0, 16, buffer); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, + address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } @@ -551,73 +616,92 @@ static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer, } } - if (remaining >= 4) { + if (((info->options & OPTIONS_128) == 0) && remaining > 0) { + // write remaining bytes in a 32-bit unit + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_32BIT; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* write in 32-bit units while we can */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + uint8_t last_word[4] = {0xFF, 0xFF, 0xFF, 0xFF}; + uint32_t i = 0; - while (remaining >= 4) { - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ - retry = 10; + while (remaining > 0) { + last_word[i++] = *buffer; + buffer++; + remaining--; + } - do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, last_word); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - if (retry <= 0) { - LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); - return ERROR_FLASH_OPERATION_FAILED; - } + // Wait until flash operation is complete + retry = 10; - buffer += 4; - address += 4; - remaining -= 4; + do { + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); + + if (retry <= 0) { + LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + max32xxx_flash_op_post(bank); + return ERROR_FLASH_OPERATION_FAILED; } } - if (remaining > 0) { - /* write remaining bytes in a 32-bit unit */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn &= 0xF7FFFFFF; - flsh_cn |= 0x00000010; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + if ((info->options & OPTIONS_128) && remaining > 0) { + // write remaining bytes in a 128-bit unit + if (target_read_u32(target, info->flc_base + FLC_CN, &flash_cn) != ERROR_OK) { + max32xxx_flash_op_post(bank); + return ERROR_FAIL; + } + + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn &= ~(FLC_CN_32BIT); + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + + uint8_t last_words[16] = {0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; - int i = 0; + uint32_t i = 0; while (remaining > 0) { - last_word[i++] = *buffer; + last_words[i++] = *buffer; buffer++; remaining--; } - target_write_u32(target, info->flc_base + FLSH_ADDR, address); - target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, last_word); - flsh_cn |= 0x00000001; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); - /* Wait until flash operation is complete */ - retry = 10; + target_write_u32(target, info->flc_base + FLC_ADDR, address); + target_write_buffer(target, info->flc_base + FLC_DATA0, 4, last_words); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 4, 4, last_words + 4); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 8, 4, last_words + 8); + target_write_buffer(target, info->flc_base + FLC_DATA0 + 12, 4, last_words + 12); + flash_cn |= FLC_CN_WR; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); + // Wait until flash operation is complete + retry = 10; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + if (target_read_u32(target, info->flc_base + FLC_CN, + &flash_cn) != ERROR_OK) { + max32xxx_flash_op_post(bank); + return ERROR_FAIL; + } + } while ((--retry > 0) && (flash_cn & FLC_CN_PEND)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash write @ 0x%08" PRIx32, address); + max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; } } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Flash Error writing 0x%" PRIx32 " bytes at 0x%08" PRIx32, count, offset); max32xxx_flash_op_post(bank); return ERROR_FLASH_OPERATION_FAILED; @@ -638,7 +722,7 @@ static int max32xxx_probe(struct flash_bank *bank) free(bank->sectors); - /* provide this for the benefit of the NOR flash framework */ + // provide this for the benefit of the NOR flash framework bank->size = info->flash_size; bank->num_sectors = info->flash_size / info->sector_size; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); @@ -650,24 +734,24 @@ static int max32xxx_probe(struct flash_bank *bank) bank->sectors[i].is_protected = -1; } - /* Probe to determine if this part is in the max326xx family */ - info->max326xx = 0; + // Probe to determine if this part is in the max326xx family + info->max326xx = false; target_read_u32(target, ARM_PID_REG, &arm_id[0]); - target_read_u32(target, ARM_PID_REG+4, &arm_id[1]); + target_read_u32(target, ARM_PID_REG + 4, &arm_id[1]); arm_pid = (arm_id[1] << 8) + arm_id[0]; LOG_DEBUG("arm_pid = 0x%x", arm_pid); - if ((arm_pid == ARM_PID_DEFAULT_CM3) || arm_pid == ARM_PID_DEFAULT_CM4) { + if (arm_pid == ARM_PID_DEFAULT_CM3 || arm_pid == ARM_PID_DEFAULT_CM4) { uint32_t max326xx_id; target_read_u32(target, MAX326XX_ID_REG, &max326xx_id); LOG_DEBUG("max326xx_id = 0x%" PRIx32, max326xx_id); max326xx_id = ((max326xx_id & 0xFF000000) >> 24); if (max326xx_id == MAX326XX_ID) - info->max326xx = 1; + info->max326xx = true; } LOG_DEBUG("info->max326xx = %d", info->max326xx); - /* Initialize the protection bits for each flash page */ + // Initialize the protection bits for each flash page if (max32xxx_protect_check(bank) == ERROR_FLASH_OPER_UNSUPPORTED) LOG_WARNING("Flash protection not supported on this device"); @@ -679,7 +763,7 @@ static int max32xxx_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct max32xxx_flash_bank *info = NULL; - uint32_t flsh_cn, flsh_int; + uint32_t flash_cn, flash_int; int retval; int retry; info = bank->driver_priv; @@ -693,50 +777,50 @@ static int max32xxx_mass_erase(struct flash_bank *bank) if (!info->probed) return ERROR_FLASH_BANK_NOT_PROBED; - int not_protected = 0; + bool protected = true; for (unsigned int i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) LOG_WARNING("Flash sector %u is protected", i); else - not_protected = 1; + protected = false; } - if (!not_protected) { + if (protected) { LOG_ERROR("All pages protected"); return ERROR_FAIL; } - /* Prepare to issue flash operation */ + // Prepare to issue flash operation retval = max32xxx_flash_op_pre(bank); if (retval != ERROR_OK) return retval; - /* Write mass erase code */ - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - flsh_cn |= FLSH_CN_ERASE_CODE_ME; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Write mass erase code + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + flash_cn |= FLC_CN_ERASE_CODE_ME; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Issue mass erase command */ - flsh_cn |= 0x2; - target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn); + // Issue mass erase command + flash_cn |= FLC_CN_ME; + target_write_u32(target, info->flc_base + FLC_CN, flash_cn); - /* Wait until erase complete */ + // Wait until erase complete retry = 1000; do { - target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn); - } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND)); + target_read_u32(target, info->flc_base + FLC_CN, &flash_cn); + } while ((--retry > 0) && max32xxx_flash_busy(flash_cn)); if (retry <= 0) { LOG_ERROR("Timed out waiting for flash mass erase"); return ERROR_FLASH_OPERATION_FAILED; } - /* Check access violations */ - target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int); - if (flsh_int & FLSH_INT_AF) { + // Check access violations + target_read_u32(target, info->flc_base + FLC_INT, &flash_int); + if (flash_int & FLC_INT_AF) { LOG_ERROR("Error mass erasing"); - target_write_u32(target, info->flc_base + FLSH_INT, 0); + target_write_u32(target, info->flc_base + FLC_INT, 0); return ERROR_FLASH_OPERATION_FAILED; } @@ -784,34 +868,34 @@ COMMAND_HANDLER(max32xxx_handle_protection_set_command) return retval; info = bank->driver_priv; - /* Convert the range to the page numbers */ - if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { + // Convert the range to the page numbers + if (sscanf(CMD_ARGV[1], "0x%" SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_set "); return ERROR_FAIL; } - /* Mask off the top portion on the address */ + // Mask off the top portion on the address addr = (addr & 0x0FFFFFFF); - if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { + if (sscanf(CMD_ARGV[2], "0x%" SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_set "); return ERROR_FAIL; } - /* Check the address is in the range of the flash */ - if ((addr+len) >= info->flash_size) + // Check the address is in the range of the flash + if ((addr + len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; - /* Convert the address and length to the page boundaries */ + // Convert the address and length to the page boundaries addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); - /* Convert the address and length to page numbers */ + // Convert the address and length to page numbers addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; @@ -840,34 +924,34 @@ COMMAND_HANDLER(max32xxx_handle_protection_clr_command) return retval; info = bank->driver_priv; - /* Convert the range to the page numbers */ - if (sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr) != 1) { + // Convert the range to the page numbers + if (sscanf(CMD_ARGV[1], "0x%" SCNx32, &addr) != 1) { LOG_WARNING("Error parsing address"); command_print(CMD, "max32xxx protection_clr "); return ERROR_FAIL; } - /* Mask off the top portion on the address */ + // Mask off the top portion on the address addr = (addr & 0x0FFFFFFF); - if (sscanf(CMD_ARGV[2], "0x%"SCNx32, &len) != 1) { + if (sscanf(CMD_ARGV[2], "0x%" SCNx32, &len) != 1) { LOG_WARNING("Error parsing length"); command_print(CMD, "max32xxx protection_clr "); return ERROR_FAIL; } - /* Check the address is in the range of the flash */ - if ((addr+len) >= info->flash_size) + // Check the address is in the range of the flash + if ((addr + len) >= info->flash_size) return ERROR_FLASH_SECTOR_INVALID; if (len == 0) return ERROR_OK; - /* Convert the address and length to the page boundaries */ + // Convert the address and length to the page boundaries addr = addr - (addr % info->sector_size); if (len % info->sector_size) len = len + info->sector_size - (len % info->sector_size); - /* Convert the address and length to page numbers */ + // Convert the address and length to page numbers addr = (addr / info->sector_size); len = addr + (len / info->sector_size) - 1; @@ -895,7 +979,7 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) return retval; info = bank->driver_priv; - /* Update the protection array */ + // Update the protection array retval = max32xxx_protect_check(bank); if (retval != ERROR_OK) { LOG_WARNING("Error updating the protection array"); @@ -905,10 +989,10 @@ COMMAND_HANDLER(max32xxx_handle_protection_check_command) LOG_WARNING("s: a:
p:"); for (unsigned int i = 0; i < bank->num_sectors; i += 4) { LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d", - (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected, - (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected, - (i+2), (i+2)*info->sector_size, bank->sectors[(i+2)].is_protected, - (i+3), (i+3)*info->sector_size, bank->sectors[(i+3)].is_protected); + (i + 0), (i + 0) * info->sector_size, bank->sectors[(i + 0)].is_protected, + (i + 1), (i + 1) * info->sector_size, bank->sectors[(i + 1)].is_protected, + (i + 2), (i + 2) * info->sector_size, bank->sectors[(i + 2)].is_protected, + (i + 3), (i + 3) * info->sector_size, bank->sectors[(i + 3)].is_protected); } return ERROR_OK; @@ -970,4 +1054,5 @@ const struct flash_driver max32xxx_flash = { .erase_check = default_flash_blank_check, .protect_check = max32xxx_protect_check, .info = get_info, + .free_driver_priv = default_flash_free_driver_priv, }; diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index b5e2b0bf86..d7cc253ae5 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -90,56 +90,56 @@ static int msp432_device_type(uint32_t family_type, uint32_t device_id, /* Examine the device ID and hardware revision to get the device type */ switch (device_id) { - case 0xA000: - case 0xA001: - case 0xA002: - case 0xA003: - case 0xA004: - case 0xA005: - /* Device is definitely MSP432P401x, check hardware revision */ - if (hardware_rev == 0x41 || hardware_rev == 0x42) { - /* Rev A or B of the silicon has been deprecated */ - device_type = MSP432P401X_DEPR; - } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { - /* Current and future revisions of the MSP432P401x device */ - device_type = MSP432P401X; - } else { - /* Unknown or unanticipated hardware revision */ - device_type = MSP432P401X_GUESS; - } - break; - case 0xA010: - case 0xA012: - case 0xA016: - case 0xA019: - case 0xA01F: - case 0xA020: - case 0xA022: - case 0xA026: - case 0xA029: - case 0xA02F: - /* Device is definitely MSP432P411x, check hardware revision */ - if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { - /* Current and future revisions of the MSP432P411x device */ - device_type = MSP432P411X; - } else { - /* Unknown or unanticipated hardware revision */ - device_type = MSP432P411X_GUESS; - } - break; - case 0xFFFF: - /* Device is very early silicon that has been deprecated */ + case 0xA000: + case 0xA001: + case 0xA002: + case 0xA003: + case 0xA004: + case 0xA005: + /* Device is definitely MSP432P401x, check hardware revision */ + if (hardware_rev == 0x41 || hardware_rev == 0x42) { + /* Rev A or B of the silicon has been deprecated */ device_type = MSP432P401X_DEPR; - break; - default: - if (device_id < 0xA010) { - /* Wild guess that this is an MSP432P401x */ - device_type = MSP432P401X_GUESS; - } else { - /* Reasonable guess that this is a new variant */ - device_type = MSP432P411X_GUESS; - } - break; + } else if (hardware_rev >= 0x43 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P401x device */ + device_type = MSP432P401X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P401X_GUESS; + } + break; + case 0xA010: + case 0xA012: + case 0xA016: + case 0xA019: + case 0xA01F: + case 0xA020: + case 0xA022: + case 0xA026: + case 0xA029: + case 0xA02F: + /* Device is definitely MSP432P411x, check hardware revision */ + if (hardware_rev >= 0x41 && hardware_rev <= 0x49) { + /* Current and future revisions of the MSP432P411x device */ + device_type = MSP432P411X; + } else { + /* Unknown or unanticipated hardware revision */ + device_type = MSP432P411X_GUESS; + } + break; + case 0xFFFF: + /* Device is very early silicon that has been deprecated */ + device_type = MSP432P401X_DEPR; + break; + default: + if (device_id < 0xA010) { + /* Wild guess that this is an MSP432P401x */ + device_type = MSP432P401X_GUESS; + } else { + /* Reasonable guess that this is a new variant */ + device_type = MSP432P411X_GUESS; + } + break; } } @@ -149,22 +149,22 @@ static int msp432_device_type(uint32_t family_type, uint32_t device_id, static const char *msp432_return_text(uint32_t return_code) { switch (return_code) { - case FLASH_BUSY: - return "FLASH_BUSY"; - case FLASH_SUCCESS: - return "FLASH_SUCCESS"; - case FLASH_ERROR: - return "FLASH_ERROR"; - case FLASH_TIMEOUT_ERROR: - return "FLASH_TIMEOUT_ERROR"; - case FLASH_VERIFY_ERROR: - return "FLASH_VERIFY_WRONG"; - case FLASH_WRONG_COMMAND: - return "FLASH_WRONG_COMMAND"; - case FLASH_POWER_ERROR: - return "FLASH_POWER_ERROR"; - default: - return "UNDEFINED_RETURN_CODE"; + case FLASH_BUSY: + return "FLASH_BUSY"; + case FLASH_SUCCESS: + return "FLASH_SUCCESS"; + case FLASH_ERROR: + return "FLASH_ERROR"; + case FLASH_TIMEOUT_ERROR: + return "FLASH_TIMEOUT_ERROR"; + case FLASH_VERIFY_ERROR: + return "FLASH_VERIFY_WRONG"; + case FLASH_WRONG_COMMAND: + return "FLASH_WRONG_COMMAND"; + case FLASH_POWER_ERROR: + return "FLASH_POWER_ERROR"; + default: + return "UNDEFINED_RETURN_CODE"; } } @@ -219,10 +219,10 @@ static int msp432_wait_return_code(struct target *target) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (return_code != FLASH_SUCCESS) { @@ -244,14 +244,14 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) int retval; switch (buffer) { - case 1: /* Buffer 1 */ - status_addr = ALGO_BUFFER1_STATUS_ADDR; - break; - case 2: /* Buffer 2 */ - status_addr = ALGO_BUFFER2_STATUS_ADDR; - break; - default: - return ERROR_FAIL; + case 1: /* Buffer 1 */ + status_addr = ALGO_BUFFER1_STATUS_ADDR; + break; + case 2: /* Buffer 2 */ + status_addr = ALGO_BUFFER2_STATUS_ADDR; + break; + default: + return ERROR_FAIL; } start_ms = timeval_ms(); @@ -261,10 +261,10 @@ static int msp432_wait_inactive(struct target *target, uint32_t buffer) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > FLASH_TIMEOUT) break; + + keep_alive(); }; if (status_code != BUFFER_INACTIVE) { @@ -295,27 +295,27 @@ static int msp432_init(struct flash_bank *bank) /* Choose appropriate flash helper algorithm */ switch (msp432_bank->device_type) { - case MSP432P401X: - case MSP432P401X_DEPR: - case MSP432P401X_GUESS: - default: - loader_code = msp432p401x_algo; - loader_size = sizeof(msp432p401x_algo); - algo_entry_addr = P4_ALGO_ENTRY_ADDR; - break; - case MSP432P411X: - case MSP432P411X_GUESS: - loader_code = msp432p411x_algo; - loader_size = sizeof(msp432p411x_algo); - algo_entry_addr = P4_ALGO_ENTRY_ADDR; - break; - case MSP432E401Y: - case MSP432E411Y: - case MSP432E4X_GUESS: - loader_code = msp432e4x_algo; - loader_size = sizeof(msp432e4x_algo); - algo_entry_addr = E4_ALGO_ENTRY_ADDR; - break; + case MSP432P401X: + case MSP432P401X_DEPR: + case MSP432P401X_GUESS: + default: + loader_code = msp432p401x_algo; + loader_size = sizeof(msp432p401x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432P411X: + case MSP432P411X_GUESS: + loader_code = msp432p411x_algo; + loader_size = sizeof(msp432p411x_algo); + algo_entry_addr = P4_ALGO_ENTRY_ADDR; + break; + case MSP432E401Y: + case MSP432E411Y: + case MSP432E4X_GUESS: + loader_code = msp432e4x_algo; + loader_size = sizeof(msp432e4x_algo); + algo_entry_addr = E4_ALGO_ENTRY_ADDR; + break; } /* Issue warnings if this is a device we may not be able to flash */ @@ -678,8 +678,6 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, struct msp432_algo_params algo_params; uint32_t size; uint32_t data_ready = BUFFER_DATA_READY; - long long start_ms; - long long elapsed_ms; bool is_info = bank->base == P4_FLASH_INFO_BASE; @@ -753,7 +751,6 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, } /* Write requested data, one buffer at a time */ - start_ms = timeval_ms(); while (count > 0) { if (count > ALGO_BUFFER_SIZE) @@ -786,9 +783,7 @@ static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, count -= size; buffer += size; - elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); + keep_alive(); } /* Confirm that the flash helper algorithm is finished */ @@ -985,43 +980,43 @@ static int msp432_info(struct flash_bank *bank, struct command_invocation *cmd) struct msp432_bank *msp432_bank = bank->driver_priv; switch (msp432_bank->device_type) { - case MSP432P401X_DEPR: - if (msp432_bank->device_id == 0xFFFF) { - /* Very early pre-production silicon currently deprecated */ - command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" - SUPPORT_MESSAGE); - } else { - /* Revision A or B silicon, also deprecated */ - command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" - SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); - } - break; - case MSP432P401X: - command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", - (char)msp432_bank->hardware_rev); - break; - case MSP432P411X: - command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", - (char)msp432_bank->hardware_rev); - break; - case MSP432E401Y: - command_print_sameline(cmd, "MSP432E401Y Device\n"); - break; - case MSP432E411Y: - command_print_sameline(cmd, "MSP432E411Y Device\n"); - break; - case MSP432E4X_GUESS: - command_print_sameline(cmd, - "Unrecognized MSP432E4 DID0 and DID1 IDs (%08" PRIX32 ", %08" PRIX32 ")", - msp432_bank->device_id, msp432_bank->hardware_rev); - break; - case MSP432P401X_GUESS: - case MSP432P411X_GUESS: - default: - command_print_sameline(cmd, - "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", - msp432_bank->device_id, msp432_bank->hardware_rev); - break; + case MSP432P401X_DEPR: + if (msp432_bank->device_id == 0xFFFF) { + /* Very early pre-production silicon currently deprecated */ + command_print_sameline(cmd, "MSP432P401x pre-production device (deprecated silicon)\n" + SUPPORT_MESSAGE); + } else { + /* Revision A or B silicon, also deprecated */ + command_print_sameline(cmd, "MSP432P401x Device Rev %c (deprecated silicon)\n" + SUPPORT_MESSAGE, (char)msp432_bank->hardware_rev); + } + break; + case MSP432P401X: + command_print_sameline(cmd, "MSP432P401x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432P411X: + command_print_sameline(cmd, "MSP432P411x Device Rev %c\n", + (char)msp432_bank->hardware_rev); + break; + case MSP432E401Y: + command_print_sameline(cmd, "MSP432E401Y Device\n"); + break; + case MSP432E411Y: + command_print_sameline(cmd, "MSP432E411Y Device\n"); + break; + case MSP432E4X_GUESS: + command_print_sameline(cmd, + "Unrecognized MSP432E4 DID0 and DID1 IDs (%08" PRIX32 ", %08" PRIX32 ")", + msp432_bank->device_id, msp432_bank->hardware_rev); + break; + case MSP432P401X_GUESS: + case MSP432P411X_GUESS: + default: + command_print_sameline(cmd, + "Unrecognized MSP432P4 Device ID and Hardware Rev (%04" PRIX32 ", %02" PRIX32 ")", + msp432_bank->device_id, msp432_bank->hardware_rev); + break; } return ERROR_OK; diff --git a/src/flash/nor/mspm0.c b/src/flash/nor/mspm0.c index 4731c89ccf..62fd5e8c40 100644 --- a/src/flash/nor/mspm0.c +++ b/src/flash/nor/mspm0.c @@ -429,7 +429,7 @@ static int mspm0_read_part_info(struct flash_bank *bank) LOG_WARNING("Unknown Device ID[0x%" PRIx32 "], cannot identify target", did); LOG_DEBUG("did 0x%" PRIx32 ", traceid 0x%" PRIx32 ", userid 0x%" PRIx32 - ", flashram 0x%" PRIx32 "", did, mspm0_info->traceid, userid, + ", flashram 0x%" PRIx32, did, mspm0_info->traceid, userid, flashram); return ERROR_FLASH_OPERATION_FAILED; } @@ -737,10 +737,10 @@ static int mspm0_fctl_wait_cmd_ok(struct flash_bank *bank) return retval; elapsed_ms = timeval_ms() - start_ms; - if (elapsed_ms > 500) - keep_alive(); if (elapsed_ms > MSPM0_FLASH_TIMEOUT_MS) break; + + keep_alive(); } if ((return_code & FCTL_STATCMD_CMDPASS_MASK) != FCTL_STATCMD_CMDPASS_STATPASS) { diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index a0c6e0c815..5809494df0 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -567,7 +567,7 @@ static int numicro_reg_unlock(struct target *target) if (retval != ERROR_OK) return retval; - LOG_DEBUG("protected = 0x%08" PRIx32 "", is_protected); + LOG_DEBUG("protected = 0x%08" PRIx32, is_protected); if (is_protected == 0) { /* means protected - so unlock it */ /* unlock flash registers */ retval = target_write_u32(target, NUMICRO_SYS_WRPROT - m_address_bias_offset, REG_KEY1); @@ -828,7 +828,7 @@ static int numicro_protect_check(struct flash_bank *bank) numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG0 - m_address_bias_offset, 0, &config[0]); numicro_fmc_cmd(target, ISPCMD_READ, NUMICRO_CONFIG1 - m_address_bias_offset, 0, &config[1]); - LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32 "", config[0], config[1]); + LOG_DEBUG("CONFIG0: 0x%" PRIx32 ",CONFIG1: 0x%" PRIx32, config[0], config[1]); if ((config[0] & (1<<7)) == 0) LOG_INFO("CBS=0: Boot From LPROM"); @@ -908,7 +908,7 @@ static int numicro_erase(struct flash_bank *bank, unsigned int first, if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { - LOG_DEBUG("failure: 0x%" PRIx32 "", status); + LOG_DEBUG("failure: 0x%" PRIx32, status); /* if bit is set, then must write to it to clear it. */ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, (status | ISPCON_ISPFF)); if (retval != ERROR_OK) @@ -1007,7 +1007,7 @@ static int numicro_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { - LOG_DEBUG("failure: 0x%" PRIx32 "", status); + LOG_DEBUG("failure: 0x%" PRIx32, status); /* if bit is set, then must write to it to clear it. */ retval = target_write_u32(target, NUMICRO_FLASH_ISPCON - m_address_bias_offset, @@ -1037,7 +1037,7 @@ static int numicro_get_cpu_type(struct target *target, const struct numicro_cpu_ return ERROR_FLASH_OPERATION_FAILED; } - LOG_INFO("Device ID: 0x%08" PRIx32 "", part_id); + LOG_INFO("Device ID: 0x%08" PRIx32, part_id); /* search part numbers */ for (size_t i = 0; i < ARRAY_SIZE(numicro_parts); i++) { if (part_id == numicro_parts[i].partid) { diff --git a/src/flash/nor/ocl.c b/src/flash/nor/ocl.c index 61af908f58..6db7368f94 100644 --- a/src/flash/nor/ocl.c +++ b/src/flash/nor/ocl.c @@ -82,9 +82,9 @@ static int ocl_erase(struct flash_bank *bank, unsigned int first, if (dcc_buffer[1] != OCL_CMD_DONE) { if (dcc_buffer[0] == OCL_ERASE_ALL) - LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]); + LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32, dcc_buffer[1]); else - LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]); + LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32, dcc_buffer[1]); return ERROR_FLASH_OPERATION_FAILED; } @@ -132,21 +132,21 @@ static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of /* copy data to DCC buffer in proper byte order and properly aligned */ for (i = 0; i < runlen; i++) { switch (byteofs++) { - case 0: - *dcc_bufptr &= *(buffer++) | 0xffffff00; - break; - case 1: - *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; - break; - case 2: - *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; - break; - case 3: - *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; - chksum ^= *(dcc_bufptr++); - *dcc_bufptr = 0xffffffff; - byteofs = 0; - break; + case 0: + *dcc_bufptr &= *(buffer++) | 0xffffff00; + break; + case 1: + *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; + break; + case 2: + *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; + break; + case 3: + *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; + chksum ^= *(dcc_bufptr++); + *dcc_bufptr = 0xffffffff; + byteofs = 0; + break; } } @@ -178,7 +178,7 @@ static int ocl_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t of } if (dcc_buffer[0] != OCL_CMD_DONE) { - LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]); + LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32, dcc_buffer[0]); free(dcc_buffer); return ERROR_FLASH_OPERATION_FAILED; } @@ -217,7 +217,7 @@ static int ocl_probe(struct flash_bank *bank) return retval; if (dcc_buffer[0] != OCL_CMD_DONE) { - LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]); + LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32, dcc_buffer[0]); return ERROR_FLASH_OPERATION_FAILED; } diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c index 982c9610a4..59e67cfe22 100644 --- a/src/flash/nor/pic32mx.c +++ b/src/flash/nor/pic32mx.c @@ -608,7 +608,7 @@ static int pic32mx_write(struct flash_bank *bank, const uint8_t *buffer, uint32_ } LOG_DEBUG("writing to flash at address " TARGET_ADDR_FMT " at offset 0x%8.8" PRIx32 - " count: 0x%8.8" PRIx32 "", bank->base, offset, count); + " count: 0x%8.8" PRIx32, bank->base, offset, count); if (offset & 0x3) { LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset); @@ -900,7 +900,7 @@ COMMAND_HANDLER(pic32mx_handle_unlock_command) mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (timeout-- == 0) { - LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx8 "", mchip_cmd); + LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx8, mchip_cmd); break; } alive_sleep(1); diff --git a/src/flash/nor/psoc4.c b/src/flash/nor/psoc4.c index 72cf0ee05b..88f9b1310e 100644 --- a/src/flash/nor/psoc4.c +++ b/src/flash/nor/psoc4.c @@ -178,7 +178,7 @@ static const char *psoc4_decode_chip_protection(uint8_t protection) case PSOC4_CHIP_PROT_KILL: return "protection KILL"; default: - LOG_WARNING("Unknown protection state 0x%02" PRIx8 "", protection); + LOG_WARNING("Unknown protection state 0x%02" PRIx8, protection); return ""; } } @@ -658,7 +658,7 @@ static int psoc4_write(struct flash_bank *bank, const uint8_t *buffer, memset(row_buffer + chunk_size, bank->default_padded_value, psoc4_info->row_size - chunk_size); } memcpy(row_buffer + row_offset, buffer, chunk_size); - LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32 "", + LOG_DEBUG("offset / row: 0x%08" PRIx32 " / %" PRIu32 ", size %" PRIu32, offset, row_offset, chunk_size); uint32_t macro_idx = row_num / PSOC4_ROWS_PER_MACRO; @@ -858,7 +858,7 @@ static int get_psoc4_info(struct flash_bank *bank, struct command_invocation *cm "/0x%02" PRIx16 ", silicon id 0x%08" PRIx32, psoc4_info->family_id, family_id, silicon_id); else { - command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32 "", + command_print_sameline(cmd, "%s silicon id 0x%08" PRIx32, family->name, silicon_id); } diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c index 662910aa04..3c7b06666b 100644 --- a/src/flash/nor/psoc6.c +++ b/src/flash/nor/psoc6.c @@ -420,17 +420,17 @@ static int psoc6_protect_check(struct flash_bank *bank) return hr; switch (psoc6_info->protection) { - case PROTECTION_VIRGIN: - case PROTECTION_NORMAL: - is_protected = 0; - break; - - case PROTECTION_UNKNOWN: - case PROTECTION_SECURE: - case PROTECTION_DEAD: - default: - is_protected = 1; - break; + case PROTECTION_VIRGIN: + case PROTECTION_NORMAL: + is_protected = 0; + break; + + case PROTECTION_UNKNOWN: + case PROTECTION_SECURE: + case PROTECTION_DEAD: + default: + is_protected = 1; + break; } for (unsigned int i = 0; i < bank->num_sectors; i++) @@ -463,17 +463,17 @@ static int psoc6_protect(struct flash_bank *bank, int set, unsigned int first, static const char *protection_to_str(uint8_t protection) { switch (protection) { - case PROTECTION_VIRGIN: - return "VIRGIN"; - case PROTECTION_NORMAL: - return "NORMAL"; - case PROTECTION_SECURE: - return "SECURE"; - case PROTECTION_DEAD: - return "DEAD"; - case PROTECTION_UNKNOWN: - default: - return "UNKNOWN"; + case PROTECTION_VIRGIN: + return "VIRGIN"; + case PROTECTION_NORMAL: + return "NORMAL"; + case PROTECTION_SECURE: + return "SECURE"; + case PROTECTION_DEAD: + return "DEAD"; + case PROTECTION_UNKNOWN: + default: + return "UNKNOWN"; } } diff --git a/src/flash/nor/qn908x.c b/src/flash/nor/qn908x.c index 8cd7a2f04a..a881d549b1 100644 --- a/src/flash/nor/qn908x.c +++ b/src/flash/nor/qn908x.c @@ -257,7 +257,7 @@ static int qn908x_update_reg(struct target *target, target_addr_t reg, } if (mask == 0xffffffff) { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": ?? -> 0x%.08" - PRIx32 "", reg, new_value); + PRIx32, reg, new_value); } else { LOG_DEBUG("Updated reg at " TARGET_ADDR_FMT ": 0x%.08" PRIx32 " -> 0x%.08" PRIx32, reg, orig_value, new_value); diff --git a/src/flash/nor/rp2xxx.c b/src/flash/nor/rp2xxx.c index 85c5911041..30c6e99141 100644 --- a/src/flash/nor/rp2xxx.c +++ b/src/flash/nor/rp2xxx.c @@ -41,10 +41,18 @@ #define BOOTROM_STATE_RESET_OTHER_CORE 0x02 #define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 -#define ACCESSCTRL_LOCK_OFFSET 0x40060000u -#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u -#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u -#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u +#define ACCESSCTRL_LOCK_OFFSET 0x40060000u +#define ACCESSCTRL_CFGRESET_OFFSET 0x40060008u +#define ACCESSCTRL_GPIO_NSMASK0_OFFSET 0x4006000cu +#define ACCESSCTRL_GPIO_ROM_OFFSET 0x40060014u +#define ACCESSCTRL_GPIO_XIP_AUX_OFFSET 0x400600e8u + +#define ACCESSCTRL_SAVE_BASE ACCESSCTRL_GPIO_NSMASK0_OFFSET +#define ACCESSCTRL_SAVE_SIZE \ + (ACCESSCTRL_GPIO_XIP_AUX_OFFSET + 4 - ACCESSCTRL_SAVE_BASE) + +#define ACCESSCTRL_LOCK_DEBUG_BITS 0x00000008u +#define ACCESSCTRL_WRITE_PASSWORD 0xacce0000u #define RP2040_SSI_DR0 0x18000060 #define RP2040_QSPI_CTRL 0x4001800c @@ -209,6 +217,10 @@ struct rp2xxx_flash_bank { bool size_override; struct flash_device spi_dev; /* detected model of SPI flash */ unsigned int sfdp_dummy, sfdp_dummy_detect; + + struct cortex_m_saved_security saved_security; + bool accessctrl_dirty; + uint8_t saved_accessctrl[ACCESSCTRL_SAVE_SIZE]; /* in target byte order */ }; #ifndef LOG_ROM_SYMBOL_DEBUG @@ -599,8 +611,28 @@ static int rp2xxx_call_rom_func(struct target *target, struct rp2xxx_flash_bank return rp2xxx_call_rom_func_batch(target, priv, &call, 1); } -static int rp2350_init_accessctrl(struct target *target) +static int rp2350_save_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) +{ + return target_read_memory(target, ACCESSCTRL_SAVE_BASE, 4, ACCESSCTRL_SAVE_SIZE / 4, + priv->saved_accessctrl); +} + +static int rp2350_restore_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) { + // Add write passwords to all ACCESSCTRL regs from ACCESSCTRL_GPIO_ROM to the end + // (exclude not keyed ACCESSCTRL_GPIO_NSMASK0 and ACCESSCTRL_GPIO_NSMASK1 + for (unsigned int i = ACCESSCTRL_GPIO_ROM_OFFSET - ACCESSCTRL_SAVE_BASE; + i < ACCESSCTRL_SAVE_SIZE; i += 4) + target_buffer_set_u32(target, priv->saved_accessctrl + i, + target_buffer_get_u32(target, priv->saved_accessctrl + i) | ACCESSCTRL_WRITE_PASSWORD); + + return target_write_memory(target, ACCESSCTRL_SAVE_BASE, 4, ACCESSCTRL_SAVE_SIZE / 4, + priv->saved_accessctrl); +} + +static int rp2350_init_accessctrl(struct target *target, struct rp2xxx_flash_bank *priv) +{ + priv->accessctrl_dirty = false; // Attempt to reset ACCESSCTRL, in case Secure access to SRAM has been // blocked, which will stop us from loading/running algorithms such as RCP // init. (Also ROM, QMI regs are needed later) @@ -618,6 +650,13 @@ static int rp2350_init_accessctrl(struct target *target) if (accessctrl_lock_reg & ACCESSCTRL_LOCK_DEBUG_BITS) { LOG_ERROR("ACCESSCTRL is locked, so can't reset permissions. Following steps might fail"); } else { + int retval = rp2350_save_accessctrl(target, priv); + if (retval == ERROR_OK) + priv->accessctrl_dirty = true; + // If the ACCESSCTRL backup copy is valid, mark it dirty + // as we immediately proceed to ACCESSCTRL config reset. + // Don't fail on save ACCESSCTRL error, not vital for ROM API call + LOG_DEBUG("Reset ACCESSCTRL permissions via CFGRESET"); return target_write_u32(target, ACCESSCTRL_CFGRESET_OFFSET, ACCESSCTRL_WRITE_PASSWORD | 1u); } @@ -630,23 +669,12 @@ static int rp2350_init_arm_core0(struct target *target, struct rp2xxx_flash_bank // run in the Secure state, so flip the state now before attempting to // execute any code on the core. int retval; - uint32_t dscsr; - retval = target_read_u32(target, DCB_DSCSR, &dscsr); + retval = cortex_m_set_secure(target, &priv->saved_security); if (retval != ERROR_OK) { - LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); + LOG_ERROR("RP2350 init ARM core: set secure mode failed"); return retval; } - LOG_DEBUG("DSCSR: 0x%08" PRIx32, dscsr); - if (!(dscsr & DSCSR_CDS)) { - LOG_DEBUG("Setting Current Domain Secure in DSCSR"); - retval = target_write_u32(target, DCB_DSCSR, (dscsr & ~DSCSR_CDSKEY) | DSCSR_CDS); - if (retval != ERROR_OK) { - LOG_ERROR("RP2350 init ARM core: DSCSR read failed"); - return retval; - } - } - if (!priv->stack) { LOG_ERROR("No stack for flash programming code"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -713,7 +741,7 @@ static int setup_for_raw_flash_cmd(struct target *target, struct rp2xxx_flash_ba } if (IS_RP2350(priv->id)) { - err = rp2350_init_accessctrl(target); + err = rp2350_init_accessctrl(target, priv); if (err != ERROR_OK) { LOG_ERROR("Failed to init ACCESSCTRL before ROM call"); return err; @@ -840,6 +868,22 @@ static void cleanup_after_raw_flash_cmd(struct target *target, struct rp2xxx_fla driver state. Best to clean up our allocations manually after completing each flash call, so we know to make fresh ones next time. */ LOG_DEBUG("Cleaning up after flash operations"); + + if (IS_RP2350(priv->id)) { + int retval1 = ERROR_OK; + if (priv->accessctrl_dirty) { + retval1 = rp2350_restore_accessctrl(target, priv); + priv->accessctrl_dirty = false; + } + + int retval2 = ERROR_OK; + if (is_arm(target_to_arm(target))) + retval2 = cortex_m_security_restore(target, &priv->saved_security); + + if (retval1 != ERROR_OK || retval2 != ERROR_OK) + LOG_WARNING("RP2xxx: security state was not restored properly. Debug 'resume' will probably fail, use 'reset' instead"); + /* Don't fail on security restore error, not vital for flash operation */ + } if (priv->stack) { target_free_working_area(target, priv->stack); priv->stack = 0; diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index bf654f9f6b..7f03f1fead 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -184,6 +184,16 @@ const struct flash_device flash_devices[] = { FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000), FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000), FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000), + FLASH_ID("puya p25q05", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00106085, 0x100, 0x1000, 0x10000), + FLASH_ID("puya p25q10", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00116085, 0x100, 0x1000, 0x20000), + FLASH_ID("puya p25q20", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00126085, 0x100, 0x1000, 0x40000), + FLASH_ID("puya p25q40", 0x03, 0x6b, 0x02, 0x20, 0xc7, 0x00136085, 0x100, 0x1000, 0x80000), + FLASH_ID("puya p25q80", 0x03, 0x6b, 0x02, 0x52, 0xc7, 0x00146085, 0x100, 0x8000, 0x100000), + FLASH_ID("puya p25q16", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00156085, 0x100, 0x10000, 0x200000), + FLASH_ID("puya p25q32", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00166085, 0x100, 0x10000, 0x400000), + FLASH_ID("puya p25q64", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00176085, 0x100, 0x10000, 0x800000), + FLASH_ID("puya p25q128", 0x03, 0x6b, 0x02, 0xd8, 0xc7, 0x00186085, 0x100, 0x10000, 0x1000000), + /* FRAM, no erase commands, no write page or sectors */ diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index f7dcc6f0e3..bf598b1179 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -573,13 +573,13 @@ static void stellaris_read_clock_info(struct flash_bank *bank) unsigned long mainfreq; target_read_u32(target, SCB_BASE | RCC, &rcc); - LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc); + LOG_DEBUG("Stellaris RCC %" PRIx32, rcc); target_read_u32(target, SCB_BASE | RCC2, &rcc2); - LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc); + LOG_DEBUG("Stellaris RCC2 %" PRIx32, rcc); target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg); - LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg); + LOG_DEBUG("Stellaris PLLCFG %" PRIx32, pllcfg); stellaris_info->rcc = rcc; stellaris_info->rcc2 = rcc2; @@ -608,30 +608,30 @@ static void stellaris_read_clock_info(struct flash_bank *bank) stellaris_info->mck_desc = ""; switch (oscsrc) { - case 0: /* MOSC */ - mainfreq = rcc_xtal[xtal]; - break; - case 1: /* IOSC */ - mainfreq = stellaris_info->iosc_freq; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 2: /* IOSC/4 */ - mainfreq = stellaris_info->iosc_freq / 4; - stellaris_info->mck_desc = stellaris_info->iosc_desc; - break; - case 3: /* lowspeed */ - /* Sandstorm doesn't have this 30K +/- 30% osc */ - mainfreq = 30000; - stellaris_info->mck_desc = " (±30%)"; - break; - case 8: /* hibernation osc */ - /* not all parts support hibernation */ - mainfreq = 32768; - break; - - default: /* NOTREACHED */ - mainfreq = 0; - break; + case 0: /* MOSC */ + mainfreq = rcc_xtal[xtal]; + break; + case 1: /* IOSC */ + mainfreq = stellaris_info->iosc_freq; + stellaris_info->mck_desc = stellaris_info->iosc_desc; + break; + case 2: /* IOSC/4 */ + mainfreq = stellaris_info->iosc_freq / 4; + stellaris_info->mck_desc = stellaris_info->iosc_desc; + break; + case 3: /* lowspeed */ + /* Sandstorm doesn't have this 30K +/- 30% osc */ + mainfreq = 30000; + stellaris_info->mck_desc = " (±30%)"; + break; + case 8: /* hibernation osc */ + /* not all parts support hibernation */ + mainfreq = 32768; + break; + + default: /* NOTREACHED */ + mainfreq = 0; + break; } /* PLL is used if it's not bypassed; its output is 200 MHz @@ -659,7 +659,7 @@ static int stellaris_read_part_info(struct flash_bank *bank) target_read_u32(target, SCB_BASE | DID1, &did1); target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0); target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1); - LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "", + LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32, did0, did1, stellaris_info->dc0, stellaris_info->dc1); ver = DID0_VER(did0); @@ -702,35 +702,35 @@ static int stellaris_read_part_info(struct flash_bank *bank) } switch (stellaris_info->target_class) { - case 0: /* Sandstorm */ - /* - * Current (2009-August) parts seem to be rev C2 and use 12 MHz. - * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz - * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). - */ - if (((did0 >> 8) & 0xff) < 2) { - stellaris_info->iosc_freq = 15000000; - stellaris_info->iosc_desc = " (±50%)"; - } - break; + case 0: /* Sandstorm */ + /* + * Current (2009-August) parts seem to be rev C2 and use 12 MHz. + * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz + * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). + */ + if (((did0 >> 8) & 0xff) < 2) { + stellaris_info->iosc_freq = 15000000; + stellaris_info->iosc_desc = " (±50%)"; + } + break; - case 1: /* Fury */ - break; + case 1: /* Fury */ + break; - case 4: /* Tempest */ - case 5: /* Blizzard */ - case 6: /* Firestorm */ - case 0xa: /* Snowflake */ - stellaris_info->iosc_freq = 16000000; /* +/- 1% */ - stellaris_info->iosc_desc = " (±1%)"; - /* FALL THROUGH */ + case 4: /* Tempest */ + case 5: /* Blizzard */ + case 6: /* Firestorm */ + case 0xa: /* Snowflake */ + stellaris_info->iosc_freq = 16000000; /* +/- 1% */ + stellaris_info->iosc_desc = " (±1%)"; + /* FALL THROUGH */ - case 3: /* DustDevil */ - stellaris_info->xtal_mask = 0x1f; - break; + case 3: /* DustDevil */ + stellaris_info->xtal_mask = 0x1f; + break; - default: - LOG_WARNING("Unknown did0 class"); + default: + LOG_WARNING("Unknown did0 class"); } for (i = 0; stellaris_parts[i].partno; i++) { @@ -871,7 +871,7 @@ static int stellaris_erase(struct flash_bank *bank, unsigned int first, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", + LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32, banknr, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; @@ -967,7 +967,7 @@ static int stellaris_protect(struct flash_bank *bank, int set, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris); + LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } @@ -1035,7 +1035,7 @@ static int stellaris_write_block(struct flash_bank *bank, if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32, bank, buffer, offset, wcount); /* flash write code */ @@ -1115,7 +1115,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32, bank, buffer, offset, count); if (stellaris_info->did1 == 0) @@ -1153,7 +1153,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, /* if an error occurred, we examine the reason, and quit */ target_read_u32(target, FLASH_CRIS, &flash_cris); - LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris); + LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32, flash_cris); return ERROR_FLASH_OPERATION_FAILED; } } else { @@ -1165,7 +1165,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, while (words_remaining > 0) { if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); + LOG_DEBUG("0x%" PRIx32, address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); @@ -1189,7 +1189,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, memcpy(last_word, buffer+bytes_written, bytes_remaining); if (!(address & 0xff)) - LOG_DEBUG("0x%" PRIx32 "", address); + LOG_DEBUG("0x%" PRIx32, address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); @@ -1205,7 +1205,7 @@ static int stellaris_write(struct flash_bank *bank, const uint8_t *buffer, /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { - LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris); + LOG_DEBUG("flash_cris 0x%" PRIx32, flash_cris); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 5a3c2da663..f512a26e9c 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -170,7 +170,7 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { @@ -825,7 +825,7 @@ static int stm32x_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - LOG_INFO("device id = 0x%08" PRIx32 "", dbgmcu_idcode); + LOG_INFO("device id = 0x%08" PRIx32, dbgmcu_idcode); uint16_t device_id = dbgmcu_idcode & 0xfff; uint16_t rev_id = dbgmcu_idcode >> 16; @@ -1444,8 +1444,8 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) if (optionbyte & (1 << OPT_ERROR)) command_print(CMD, "option byte complement error"); - command_print(CMD, "option byte register = 0x%" PRIx32 "", optionbyte); - command_print(CMD, "write protection register = 0x%" PRIx32 "", protection); + command_print(CMD, "option byte register = 0x%" PRIx32, optionbyte); + command_print(CMD, "write protection register = 0x%" PRIx32, protection); command_print(CMD, "read protection: %s", (optionbyte & (1 << OPT_READOUT)) ? "on" : "off"); @@ -1465,7 +1465,7 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) if (stm32x_info->has_dual_banks) command_print(CMD, "boot: bank %d", (optionbyte & (1 << OPT_BFB2)) ? 0 : 1); - command_print(CMD, "user data = 0x%02" PRIx16 "", user_data); + command_print(CMD, "user data = 0x%02" PRIx16, user_data); return ERROR_OK; } diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index f16333201b..4c25875ab0 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -152,6 +152,9 @@ /* this flag indicates that programming should be done in quad-word * the default programming word size is double-word */ #define F_QUAD_WORD_PROG BIT(4) +/* the registers WRPxyR have UNLOCK bit - writing zero locks the write + * protection region permanently! */ +#define F_WRP_HAS_LOCK BIT(5) /* end of STM32L4 flags ******************************************************/ @@ -284,7 +287,7 @@ struct stm32l4_wrp { }; /* human readable list of families this drivers supports (sorted alphabetically) */ -static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U0/U5/WB/WL"; +static const char *device_families = "STM32C0/G0/G4/L4/L4+/L5/U0/U3/U5/WB/WL"; static const struct stm32l4_rev stm32l47_l48xx_revs[] = { { 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" } @@ -347,6 +350,10 @@ static const struct stm32l4_rev stm32u0xx_revs[] = { { 0x1000, "A" }, }; +static const struct stm32l4_rev stm32u37_u38xx_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, +}; + static const struct stm32l4_rev stm32g43_g44xx_revs[] = { { 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" }, }; @@ -500,7 +507,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32u53_u54xx_revs), .device_str = "STM32U535/U545", .max_flash_size_kb = 512, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -686,13 +694,26 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .otp_base = 0x1FFF6800, .otp_size = 1024, }, + { + .id = DEVID_STM32U37_U38XX, + .revs = stm32u37_u38xx_revs, + .num_revs = ARRAY_SIZE(stm32u37_u38xx_revs), + .device_str = "STM32U37/U38xx", + .max_flash_size_kb = 1024, + .flags = F_HAS_DUAL_BANK | F_HAS_TZ | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, + .flash_regs_base = 0x40022000, + .fsize_addr = 0x0BFA07A0, + .otp_base = 0x0BFA0000, + .otp_size = 512, + }, { .id = DEVID_STM32U59_U5AXX, .revs = stm32u59_u5axx_revs, .num_revs = ARRAY_SIZE(stm32u59_u5axx_revs), .device_str = "STM32U59/U5Axx", .max_flash_size_kb = 4096, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -704,7 +725,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32u57_u58xx_revs), .device_str = "STM32U57/U58xx", .max_flash_size_kb = 2048, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -716,7 +738,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = { .num_revs = ARRAY_SIZE(stm32u5f_u5gxx_revs), .device_str = "STM32U5F/U5Gxx", .max_flash_size_kb = 4096, - .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS, + .flags = F_HAS_DUAL_BANK | F_QUAD_WORD_PROG | F_HAS_TZ + | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK, .flash_regs_base = 0x40022000, .fsize_addr = 0x0BFA07A0, .otp_base = 0x0BFA0000, @@ -974,7 +997,7 @@ static int stm32l4_wait_status_busy(struct flash_bank *bank, int timeout) retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &status); if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & stm32l4_info->sr_bsy_mask) == 0) break; if (timeout-- <= 0) { @@ -1287,6 +1310,8 @@ static int stm32l4_write_one_wrpxy(struct flash_bank *bank, struct stm32l4_wrp * int wrp_end = wrpxy->last - wrpxy->offset; uint32_t wrp_value = (wrp_start & stm32l4_info->wrpxxr_mask) | ((wrp_end & stm32l4_info->wrpxxr_mask) << 16); + if (stm32l4_info->part_info->flags & F_WRP_HAS_LOCK) + wrp_value |= FLASH_WRPXYR_UNLOCK; return stm32l4_write_option(bank, stm32l4_info->flash_regs[wrpxy->reg_idx], wrp_value, 0xffffffff); } @@ -1371,6 +1396,10 @@ static int stm32l4_erase(struct flash_bank *bank, unsigned int first, 4. Wait for the BSY bit to be cleared */ + retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + if (retval != ERROR_OK) + goto err_lock; + for (unsigned int i = first; i <= last; i++) { uint32_t erase_flags; erase_flags = FLASH_PER | FLASH_STRT; @@ -1776,6 +1805,9 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto err_lock; + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto err_lock; /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, * the debug is possible only in non-secure state. @@ -2142,6 +2174,15 @@ static int stm32l4_probe(struct flash_bank *bank) stm32l4_info->bank1_sectors = num_pages / 2; } break; + case DEVID_STM32U37_U38XX: + page_size_kb = 4; + num_pages = flash_size_kb / page_size_kb; + stm32l4_info->bank1_sectors = num_pages; + if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) { + stm32l4_info->dual_bank_mode = true; + stm32l4_info->bank1_sectors = num_pages / 2; + } + break; case DEVID_STM32U53_U54XX: case DEVID_STM32U57_U58XX: case DEVID_STM32U59_U5AXX: @@ -2400,19 +2441,18 @@ COMMAND_HANDLER(stm32l4_handle_option_read_command) if (retval != ERROR_OK) return retval; - uint32_t reg_offset, reg_addr; + uint32_t reg_offset; uint32_t value = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset); - reg_addr = stm32l4_get_flash_reg(bank, reg_offset); retval = stm32l4_read_flash_reg(bank, reg_offset, &value); if (retval != ERROR_OK) return retval; - command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value); + command_print(CMD, "0x%" PRIx32, value); - return retval; + return ERROR_OK; } COMMAND_HANDLER(stm32l4_handle_option_write_command) diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h index 07b3615a24..8e6cb4309f 100644 --- a/src/flash/nor/stm32l4x.h +++ b/src/flash/nor/stm32l4x.h @@ -69,6 +69,9 @@ #define FLASH_U5_DUALBANK BIT(21) #define FLASH_TZEN BIT(31) +/* FLASH_WRPxyR register bits */ +#define FLASH_WRPXYR_UNLOCK BIT(31) + /* FLASH secure block based bank 1/2 register offsets */ #define FLASH_SECBB1(X) (0x80 + 4 * (X - 1)) #define FLASH_SECBB2(X) (0xA0 + 4 * (X - 1)) @@ -91,6 +94,7 @@ #define DEVID_STM32C05XX 0x44C #define DEVID_STM32C09XX 0x44D #define DEVID_STM32C03XX 0x453 +#define DEVID_STM32U37_U38XX 0x454 #define DEVID_STM32U53_U54XX 0x455 #define DEVID_STM32G05_G06XX 0x456 #define DEVID_STM32U031XX 0x459 diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 1459e942d1..2c7563e95a 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -745,7 +745,7 @@ static int stm32lx_probe(struct flash_bank *bank) stm32lx_info->idcode = device_id; - LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id); + LOG_DEBUG("device id = 0x%08" PRIx32, device_id); for (n = 0; n < ARRAY_SIZE(stm32lx_parts); n++) { if ((device_id & 0xfff) == stm32lx_parts[n].id) { @@ -1204,7 +1204,7 @@ static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int tim if (retval != ERROR_OK) return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); + LOG_DEBUG("status: 0x%" PRIx32, status); if ((status & FLASH_SR__BSY) == 0) break; diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index df58f6c55d..bd72fe050e 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -1978,24 +1978,24 @@ static int read_flash_id(struct flash_bank *bank, uint32_t *id1, uint32_t *id2) /* Read id: one particular flash chip (N25Q128) switches back to SPI mode when receiving * SPI_FLASH_READ_ID in QPI mode, hence try SPIFLASH_READ_MID first */ switch (type) { - case 0: - if (IS_OCTOSPI) - retval = octospi_cmd(bank, OCTOSPI_READ_MODE, - OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); - else - retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID); - break; - - case 1: - if (IS_OCTOSPI) - retval = octospi_cmd(bank, OCTOSPI_READ_MODE, - OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); - else - retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID); - break; - - default: - return ERROR_FAIL; + case 0: + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_MID, SPIFLASH_READ_MID); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_MID); + break; + + case 1: + if (IS_OCTOSPI) + retval = octospi_cmd(bank, OCTOSPI_READ_MODE, + OCTOSPI_CCR_READ_ID, SPIFLASH_READ_ID); + else + retval = target_write_u32(target, io_base + QSPI_CCR, QSPI_CCR_READ_ID); + break; + + default: + return ERROR_FAIL; } if (retval != ERROR_OK) diff --git a/src/flash/nor/stmsmi.c b/src/flash/nor/stmsmi.c index 1aa244728f..85f3580788 100644 --- a/src/flash/nor/stmsmi.c +++ b/src/flash/nor/stmsmi.c @@ -531,21 +531,21 @@ static int stmsmi_probe(struct flash_bank *bank) } switch (bank->base - target_device->smi_base) { - case 0: - stmsmi_info->bank_num = SMI_SEL_BANK0; - break; - case SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK1; - break; - case 2*SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK2; - break; - case 3*SMI_BANK_SIZE: - stmsmi_info->bank_num = SMI_SEL_BANK3; - break; - default: - LOG_ERROR("Invalid SMI base address " TARGET_ADDR_FMT, bank->base); - return ERROR_FAIL; + case 0: + stmsmi_info->bank_num = SMI_SEL_BANK0; + break; + case SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK1; + break; + case 2 * SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK2; + break; + case 3 * SMI_BANK_SIZE: + stmsmi_info->bank_num = SMI_SEL_BANK3; + break; + default: + LOG_ERROR("Invalid SMI base address " TARGET_ADDR_FMT, bank->base); + return ERROR_FAIL; } io_base = target_device->io_base; stmsmi_info->io_base = io_base; diff --git a/src/flash/nor/str7x.c b/src/flash/nor/str7x.c index b91e22e044..0177095cb9 100644 --- a/src/flash/nor/str7x.c +++ b/src/flash/nor/str7x.c @@ -131,21 +131,21 @@ static int str7x_build_block_list(struct flash_bank *bank) int b0_sectors = 0, b1_sectors = 0; switch (bank->size) { - case 16 * 1024: - b1_sectors = 2; - break; - case 64 * 1024: - b0_sectors = 5; - break; - case 128 * 1024: - b0_sectors = 6; - break; - case 256 * 1024: - b0_sectors = 8; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case 16 * 1024: + b1_sectors = 2; + break; + case 64 * 1024: + b0_sectors = 5; + break; + case 128 * 1024: + b0_sectors = 6; + break; + case 256 * 1024: + b0_sectors = 8; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; @@ -335,7 +335,7 @@ static int str7x_erase(struct flash_bank *bank, unsigned int first, for (unsigned int i = first; i <= last; i++) sectors |= str7x_info->sector_bits[i]; - LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors); + LOG_DEBUG("sectors: 0x%" PRIx32, sectors); /* clear FLASH_ER register */ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); diff --git a/src/flash/nor/str9x.c b/src/flash/nor/str9x.c index 1a26b839e9..9efac241a0 100644 --- a/src/flash/nor/str9x.c +++ b/src/flash/nor/str9x.c @@ -66,36 +66,36 @@ static int str9x_build_block_list(struct flash_bank *bank) str9x_info->bank1 = 0; switch (bank->size) { - case (256 * 1024): - b0_sectors = 4; - break; - case (512 * 1024): - b0_sectors = 8; - break; - case (1024 * 1024): - bank1start = 0x00100000; - str9x_info->variant = 1; - b0_sectors = 16; - break; - case (2048 * 1024): - bank1start = 0x00200000; - str9x_info->variant = 1; - b0_sectors = 32; - break; - case (128 * 1024): - str9x_info->variant = 1; - str9x_info->bank1 = 1; - b1_sectors = 8; - bank1start = bank->base; - break; - case (32 * 1024): - str9x_info->bank1 = 1; - b1_sectors = 4; - bank1start = bank->base; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case (256 * 1024): + b0_sectors = 4; + break; + case (512 * 1024): + b0_sectors = 8; + break; + case (1024 * 1024): + bank1start = 0x00100000; + str9x_info->variant = 1; + b0_sectors = 16; + break; + case (2048 * 1024): + bank1start = 0x00200000; + str9x_info->variant = 1; + b0_sectors = 32; + break; + case (128 * 1024): + str9x_info->variant = 1; + str9x_info->bank1 = 1; + b1_sectors = 8; + bank1start = bank->base; + break; + case (32 * 1024): + str9x_info->bank1 = 1; + b1_sectors = 4; + bank1start = bank->base; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; diff --git a/src/flash/nor/str9xpec.c b/src/flash/nor/str9xpec.c index eff7df5a11..be0089879a 100644 --- a/src/flash/nor/str9xpec.c +++ b/src/flash/nor/str9xpec.c @@ -206,28 +206,28 @@ static int str9xpec_build_block_list(struct flash_bank *bank) int b1_size = 0x2000; switch (bank->size) { - case (256 * 1024): - b0_sectors = 4; - break; - case (512 * 1024): - b0_sectors = 8; - break; - case (1024 * 1024): - b0_sectors = 16; - break; - case (2048 * 1024): - b0_sectors = 32; - break; - case (128 * 1024): - b1_size = 0x4000; - b1_sectors = 8; - break; - case (32 * 1024): - b1_sectors = 4; - break; - default: - LOG_ERROR("BUG: unknown bank->size encountered"); - exit(-1); + case (256 * 1024): + b0_sectors = 4; + break; + case (512 * 1024): + b0_sectors = 8; + break; + case (1024 * 1024): + b0_sectors = 16; + break; + case (2048 * 1024): + b0_sectors = 32; + break; + case (128 * 1024): + b1_size = 0x4000; + b1_sectors = 8; + break; + case (32 * 1024): + b1_sectors = 4; + break; + default: + LOG_ERROR("BUG: unknown bank->size encountered"); + exit(-1); } num_sectors = b0_sectors + b1_sectors; @@ -735,7 +735,7 @@ COMMAND_HANDLER(str9xpec_handle_part_id_command) idcode = buf_get_u32(buffer, 0, 32); - command_print(CMD, "str9xpec part id: 0x%8.8" PRIx32 "", idcode); + command_print(CMD, "str9xpec part id: 0x%8.8" PRIx32, idcode); free(buffer); diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index a19b1a6833..517d9aca1d 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -535,20 +535,20 @@ COMMAND_HANDLER(handle_flash_fill_command) return retval; switch (CMD_NAME[4]) { - case 'd': - wordsize = 8; - break; - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'd': + wordsize = 8; + break; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if ((wordsize < sizeof(pattern)) && (pattern >> (8 * wordsize) != 0)) { @@ -588,25 +588,25 @@ COMMAND_HANDLER(handle_flash_fill_command) uint8_t *ptr = buffer + padding_at_start; switch (wordsize) { - case 8: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u64(target, ptr, pattern); - break; - case 4: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u32(target, ptr, pattern); - break; - case 2: - for (i = 0; i < count; i++, ptr += wordsize) - target_buffer_set_u16(target, ptr, pattern); - break; - case 1: - memset(ptr, pattern, count); - ptr += count; - break; - default: - LOG_ERROR("BUG: can't happen"); - exit(-1); + case 8: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u64(target, ptr, pattern); + break; + case 4: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u32(target, ptr, pattern); + break; + case 2: + for (i = 0; i < count; i++, ptr += wordsize) + target_buffer_set_u16(target, ptr, pattern); + break; + case 1: + memset(ptr, pattern, count); + ptr += count; + break; + default: + LOG_ERROR("BUG: can't happen"); + exit(-1); } if (padding_at_end) { @@ -631,18 +631,18 @@ COMMAND_HANDLER(handle_flash_fill_command) uint64_t readback = 0; switch (wordsize) { - case 8: - readback = target_buffer_get_u64(target, ptr); - break; - case 4: - readback = target_buffer_get_u32(target, ptr); - break; - case 2: - readback = target_buffer_get_u16(target, ptr); - break; - case 1: - readback = *ptr; - break; + case 8: + readback = target_buffer_get_u64(target, ptr); + break; + case 4: + readback = target_buffer_get_u32(target, ptr); + break; + case 2: + readback = target_buffer_get_u16(target, ptr); + break; + case 1: + readback = *ptr; + break; } if (readback != pattern) { LOG_ERROR( @@ -683,17 +683,17 @@ COMMAND_HANDLER(handle_flash_md_command) unsigned int wordsize; switch (CMD_NAME[2]) { - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (count == 0) @@ -728,6 +728,124 @@ COMMAND_HANDLER(handle_flash_md_command) return retval; } +COMMAND_HANDLER(handle_flash_read_memory_command) +{ + /* + * CMD_ARGV[0] = memory address + * CMD_ARGV[1] = desired element width in bits + * CMD_ARGV[2] = number of elements to read + */ + + if (CMD_ARGC != 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* Arg 1: Memory address. */ + target_addr_t addr; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); + + /* Arg 2: Bit width of one element. */ + unsigned int width_bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits); + + /* Arg 3: Number of elements to read. */ + unsigned int count; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); + + switch (width_bits) { + case 8: + case 16: + case 32: + case 64: + break; + default: + command_print(CMD, "invalid width, must be 8, 16, 32 or 64"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (count > 65536) { + command_print(CMD, "too large read request, exceeds 64K elements"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + const unsigned int width = width_bits / 8; + /* -1 is needed to handle cases when (addr + count * width) results in zero + * due to overflow. + */ + if ((addr + count * width - 1) < addr) { + command_print(CMD, "memory region wraps over address zero"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + struct target *target = get_current_target(CMD_CTX); + struct flash_bank *bank; + int retval = get_flash_bank_by_addr(target, addr, true, &bank); + if (retval != ERROR_OK) + return retval; + + uint32_t offset = addr - bank->base; + uint32_t sizebytes = count * width_bits; + if (offset + sizebytes > bank->size) { + command_print(CMD, "cannot cross flash bank borders"); + return ERROR_FAIL; + } + + const size_t buffer_size = 4096; + uint8_t *buffer = malloc(buffer_size); + + if (!buffer) { + command_print(CMD, "failed to allocate memory"); + return ERROR_FAIL; + } + + char *separator = ""; + while (count > 0) { + const unsigned int max_chunk_len = buffer_size / width; + const size_t chunk_len = MIN(count, max_chunk_len); + + retval = flash_driver_read(bank, buffer, offset, chunk_len * width); + + if (retval != ERROR_OK) { + LOG_DEBUG("read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + addr, width_bits, chunk_len); + /* + * FIXME: we append the errmsg to the list of value already read. + * Add a way to flush and replace old output, but LOG_DEBUG() it + */ + command_print(CMD, "failed to read memory"); + free(buffer); + return retval; + } + + for (size_t i = 0; i < chunk_len ; i++) { + uint64_t v = 0; + + switch (width) { + case 8: + v = target_buffer_get_u64(target, &buffer[i * width]); + break; + case 4: + v = target_buffer_get_u32(target, &buffer[i * width]); + break; + case 2: + v = target_buffer_get_u16(target, &buffer[i * width]); + break; + case 1: + v = buffer[i]; + break; + } + + command_print_sameline(CMD, "%s0x%" PRIx64, separator, v); + separator = " "; + } + + count -= chunk_len; + offset += chunk_len * width; + } + + free(buffer); + + return ERROR_OK; +} COMMAND_HANDLER(handle_flash_write_bank_command) { @@ -1171,6 +1289,13 @@ static const struct command_registration flash_exec_command_handlers[] = { .usage = "address [count]", .help = "Display words from flash.", }, + { + .name = "read_memory", + .mode = COMMAND_EXEC, + .handler = handle_flash_read_memory_command, + .help = "Read Tcl list of 8/16/32/64 bit numbers from flash memory", + .usage = "address width count", + }, { .name = "write_bank", .handler = handle_flash_write_bank_command, diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c index 00ee77bb80..fa0b5b68ec 100644 --- a/src/flash/nor/tms470.c +++ b/src/flash/nor/tms470.c @@ -125,7 +125,7 @@ static int tms470_read_part_info(struct flash_bank *bank) /* read and parse the device identification register */ target_read_u32(target, 0xFFFFFFF0, &device_ident_reg); - LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg); + LOG_INFO("device_ident_reg = 0x%08" PRIx32, device_ident_reg); if ((device_ident_reg & 7) == 0) { LOG_WARNING("Cannot identify target as a TMS470 family."); @@ -148,100 +148,100 @@ static int tms470_read_part_info(struct flash_bank *bank) * bank structure. */ switch (part_number) { - case 0x0a: - part_name = "TMS470R1A256"; - - if (bank->base >= 0x00040000) { - LOG_ERROR("No %s flash bank contains base address " - TARGET_ADDR_FMT ".", - part_name, - bank->base); - return ERROR_FLASH_OPERATION_FAILED; - } + case 0x0a: + part_name = "TMS470R1A256"; + + if (bank->base >= 0x00040000) { + LOG_ERROR("No %s flash bank contains base address " + TARGET_ADDR_FMT ".", + part_name, + bank->base); + return ERROR_FLASH_OPERATION_FAILED; + } + tms470_info->ordinal = 0; + bank->base = 0x00000000; + bank->size = 256 * 1024; + bank->num_sectors = TMS470R1A256_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a256_sectors)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); + break; + + case 0x2b: + part_name = "TMS470R1A288"; + + if (bank->base < 0x00008000) { tms470_info->ordinal = 0; bank->base = 0x00000000; + bank->size = 32 * 1024; + bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a288_bank0_sectors)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (void)memcpy(bank->sectors, tms470r1a288_bank0_sectors, + sizeof(tms470r1a288_bank0_sectors)); + } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { + tms470_info->ordinal = 1; + bank->base = 0x00040000; bank->size = 256 * 1024; - bank->num_sectors = TMS470R1A256_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a256_sectors)); + bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a288_bank1_sectors)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a256_sectors, sizeof(tms470r1a256_sectors)); - break; + (void)memcpy(bank->sectors, tms470r1a288_bank1_sectors, + sizeof(tms470r1a288_bank1_sectors)); + } else { + LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", + part_name, bank->base); + return ERROR_FLASH_OPERATION_FAILED; + } + break; - case 0x2b: - part_name = "TMS470R1A288"; - - if (bank->base < 0x00008000) { - tms470_info->ordinal = 0; - bank->base = 0x00000000; - bank->size = 32 * 1024; - bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a288_bank0_sectors)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a288_bank0_sectors, - sizeof(tms470r1a288_bank0_sectors)); - } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { - tms470_info->ordinal = 1; - bank->base = 0x00040000; - bank->size = 256 * 1024; - bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a288_bank1_sectors)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a288_bank1_sectors, - sizeof(tms470r1a288_bank1_sectors)); - } else { - LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", - part_name, bank->base); - return ERROR_FLASH_OPERATION_FAILED; - } - break; + case 0x2d: + part_name = "TMS470R1A384"; - case 0x2d: - part_name = "TMS470R1A384"; - - if (bank->base < 0x00020000) { - tms470_info->ordinal = 0; - bank->base = 0x00000000; - bank->size = 128 * 1024; - bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a384_bank0_sectors)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a384_bank0_sectors, - sizeof(tms470r1a384_bank0_sectors)); - } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) { - tms470_info->ordinal = 1; - bank->base = 0x00020000; - bank->size = 128 * 1024; - bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a384_bank1_sectors)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a384_bank1_sectors, - sizeof(tms470r1a384_bank1_sectors)); - } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) { - tms470_info->ordinal = 2; - bank->base = 0x00040000; - bank->size = 128 * 1024; - bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS; - bank->sectors = malloc(sizeof(tms470r1a384_bank2_sectors)); - if (!bank->sectors) - return ERROR_FLASH_OPERATION_FAILED; - (void)memcpy(bank->sectors, tms470r1a384_bank2_sectors, - sizeof(tms470r1a384_bank2_sectors)); - } else { - LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", - part_name, bank->base); + if (bank->base < 0x00020000) { + tms470_info->ordinal = 0; + bank->base = 0x00000000; + bank->size = 128 * 1024; + bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a384_bank0_sectors)); + if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; - } - break; - - default: - LOG_WARNING("Could not identify part 0x%02" PRIx32 " as a member of the TMS470 family.", - part_number); + (void)memcpy(bank->sectors, tms470r1a384_bank0_sectors, + sizeof(tms470r1a384_bank0_sectors)); + } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) { + tms470_info->ordinal = 1; + bank->base = 0x00020000; + bank->size = 128 * 1024; + bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a384_bank1_sectors)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (void)memcpy(bank->sectors, tms470r1a384_bank1_sectors, + sizeof(tms470r1a384_bank1_sectors)); + } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) { + tms470_info->ordinal = 2; + bank->base = 0x00040000; + bank->size = 128 * 1024; + bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS; + bank->sectors = malloc(sizeof(tms470r1a384_bank2_sectors)); + if (!bank->sectors) + return ERROR_FLASH_OPERATION_FAILED; + (void)memcpy(bank->sectors, tms470r1a384_bank2_sectors, + sizeof(tms470r1a384_bank2_sectors)); + } else { + LOG_ERROR("No %s flash bank contains base address " TARGET_ADDR_FMT ".", + part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; + } + break; + + default: + LOG_WARNING("Could not identify part 0x%02" PRIx32 " as a member of the TMS470 family.", + part_number); + return ERROR_FLASH_OPERATION_FAILED; } /* turn off memory selects */ @@ -300,7 +300,7 @@ COMMAND_HANDLER(tms470_handle_flash_keyset_command) if (keys_set) { command_print(CMD, - "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "", + "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32, flash_keys[0], flash_keys[1], flash_keys[2], @@ -419,7 +419,7 @@ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) */ target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); - LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]); + LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32, key_set[i]); target_write_u32(target, 0xFFE89C0C, key_set[i]); } @@ -500,7 +500,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban fmmac2 &= ~0x0007; fmmac2 |= (tms470_info->ordinal & 7); target_write_u32(target, 0xFFE8BC04, fmmac2); - LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2); + LOG_DEBUG("set fmmac2 = 0x%04" PRIx32, fmmac2); /* * Disable level 1 sector protection by setting bit 15 of FMMAC1. @@ -508,7 +508,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban target_read_u32(target, 0xFFE8BC00, &fmmac1); fmmac1 |= 0x8000; target_write_u32(target, 0xFFE8BC00, fmmac1); - LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1); + LOG_DEBUG("set fmmac1 = 0x%04" PRIx32, fmmac1); /* * FMTCREG = 0x2fc0; @@ -542,7 +542,7 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban LOG_DEBUG("set fmptr3 = 0x9b64"); } target_write_u32(target, 0xFFE8A080, fmmaxep); - LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep); + LOG_DEBUG("set fmmaxep = 0x%04" PRIx32, fmmaxep); /* * FMPTR4 = 0xa000 @@ -562,56 +562,56 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * osc_mhz / (1 + (glbctrl & 7)); delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5; target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8)); - LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8)); + LOG_DEBUG("set fmpsetup = 0x%04" PRIx32, (delay << 4) | (delay << 8)); /* * FMPVEVACCESS, based on delay. */ k = delay | (delay << 8); target_write_u32(target, 0xFFE8A05C, k); - LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32, k); /* * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay. */ k <<= 1; target_write_u32(target, 0xFFE8A034, k); - LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpchold = 0x%04" PRIx32, k); target_write_u32(target, 0xFFE8A040, k); - LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32, k); target_write_u32(target, 0xFFE8A024, k); - LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32, k); /* * FMCVACCESS, based on delay. */ k = delay * 16; target_write_u32(target, 0xFFE8A060, k); - LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32, k); /* * FMCSETUP, based on delay. */ k = 0x3000 | delay * 20; target_write_u32(target, 0xFFE8A020, k); - LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmcsetup = 0x%04" PRIx32, k); /* * FMEHOLD, based on delay. */ k = (delay * 20) << 2; target_write_u32(target, 0xFFE8A038, k); - LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k); + LOG_DEBUG("set fmehold = 0x%04" PRIx32, k); /* * PWIDTH, CWIDTH, EWIDTH, based on delay. */ target_write_u32(target, 0xFFE8A050, delay * 8); - LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8); + LOG_DEBUG("set fmpwidth = 0x%04" PRIx32, delay * 8); target_write_u32(target, 0xFFE8A058, delay * 1000); - LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000); + LOG_DEBUG("set fmcwidth = 0x%04" PRIx32, delay * 1000); target_write_u32(target, 0xFFE8A054, delay * 5400); - LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400); + LOG_DEBUG("set fmewidth = 0x%04" PRIx32, delay * 5400); return result; } @@ -625,7 +625,7 @@ static int tms470_flash_status(struct flash_bank *bank) uint32_t fmmstat; target_read_u32(target, 0xFFE8BC0C, &fmmstat); - LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat); + LOG_DEBUG("set fmmstat = 0x%04" PRIx32, fmmstat); if (fmmstat & 0x0080) { LOG_WARNING("tms470 flash command: erase still active after busy clear."); @@ -680,7 +680,7 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); - LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10); + LOG_DEBUG("set glbctrl = 0x%08" PRIx32, glbctrl | 0x10); /* Force normal read mode. */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); @@ -697,11 +697,11 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); - LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector)); + LOG_DEBUG("set fmbsea = 0x%04" PRIx32, fmbsea | (1 << sector)); } else { target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16))); - LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16))); + LOG_DEBUG("set fmbseb = 0x%04" PRIx32, fmbseb | (1 << (sector - 16))); } bank->sectors[sector].is_protected = 0; @@ -729,17 +729,17 @@ static int tms470_erase_sector(struct flash_bank *bank, int sector) if (sector < 16) { target_write_u32(target, 0xFFE88008, fmbsea); - LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea); + LOG_DEBUG("set fmbsea = 0x%04" PRIx32, fmbsea); bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1; } else { target_write_u32(target, 0xFFE8800C, fmbseb); - LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb); + LOG_DEBUG("set fmbseb = 0x%04" PRIx32, fmbseb); bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; } target_write_u32(target, 0xFFE89C00, orig_fmregopt); - LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt); + LOG_DEBUG("set fmregopt = 0x%08" PRIx32, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); - LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl); + LOG_DEBUG("set glbctrl = 0x%08" PRIx32, glbctrl); return result; } @@ -920,7 +920,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1]; if (word != 0xffff) { - LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr); + LOG_INFO("writing 0x%04x at 0x%08" PRIx32, word, addr); /* clear status register */ target_write_u16(target, addr, 0x0040); @@ -940,7 +940,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t } while (fmmstat & 0x0100); if (fmmstat & 0x3ff) { - LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat); + LOG_ERROR("fmstat = 0x%04" PRIx32, fmmstat); LOG_ERROR( "Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, @@ -949,7 +949,7 @@ static int tms470_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t break; } } else - LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr); + LOG_INFO("skipping 0xffff at 0x%08" PRIx32, addr); } /* restore */ diff --git a/src/flash/nor/w600.c b/src/flash/nor/w600.c index 20968dcaaa..ba4a42969b 100644 --- a/src/flash/nor/w600.c +++ b/src/flash/nor/w600.c @@ -128,13 +128,13 @@ static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr, if (len > 0) cmd |= QFLASH_CMD_DATALEN(len - 1) | QFLASH_CMD_DATA; - LOG_DEBUG("WRITE CMD: 0x%08" PRIx32 "", cmd); + 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); + LOG_DEBUG("WRITE START: 0x%08" PRIx32, addr); retval = target_write_u32(target, QFLASH_CMD_START, addr); if (retval != ERROR_OK) return retval; @@ -148,7 +148,7 @@ static int w600_start_do(struct flash_bank *bank, uint32_t cmd, uint32_t addr, 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); + LOG_DEBUG("READ START: 0x%08" PRIx32, status); else LOG_DEBUG("READ START FAILED"); @@ -283,7 +283,7 @@ static int w600_probe(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - LOG_INFO("flash_id id = 0x%08" PRIx32 "", flash_id); + 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++) { @@ -360,7 +360,7 @@ static int get_w600_info(struct flash_bank *bank, struct command_invocation *cmd if (retval != ERROR_OK) return retval; - command_print_sameline(cmd, "w600 : 0x%08" PRIx32 "", flash_id); + command_print_sameline(cmd, "w600 : 0x%08" PRIx32, flash_id); return ERROR_OK; } diff --git a/src/flash/nor/xcf.c b/src/flash/nor/xcf.c index 4011fa42be..04ee0d34a3 100644 --- a/src/flash/nor/xcf.c +++ b/src/flash/nor/xcf.c @@ -87,14 +87,14 @@ static const char *product_name(const struct flash_bank *bank) { switch (bank->target->tap->idcode & ID_MEANINGFUL_MASK) { - case ID_XCF08P: - return xcf_name_list[0]; - case ID_XCF16P: - return xcf_name_list[1]; - case ID_XCF32P: - return xcf_name_list[2]; - default: - return xcf_name_list[3]; + case ID_XCF08P: + return xcf_name_list[0]; + case ID_XCF16P: + return xcf_name_list[1]; + case ID_XCF32P: + return xcf_name_list[2]; + default: + return xcf_name_list[3]; } } @@ -601,18 +601,18 @@ static int xcf_probe(struct flash_bank *bank) /* guess number of blocks using chip ID */ id = bank->target->tap->idcode; switch (id & ID_MEANINGFUL_MASK) { - case ID_XCF08P: - bank->num_sectors = 1; - break; - case ID_XCF16P: - bank->num_sectors = 2; - break; - case ID_XCF32P: - bank->num_sectors = 4; - break; - default: - LOG_ERROR("Unknown flash device ID 0x%" PRIX32, id); - return ERROR_FAIL; + case ID_XCF08P: + bank->num_sectors = 1; + break; + case ID_XCF16P: + bank->num_sectors = 2; + break; + case ID_XCF32P: + bank->num_sectors = 4; + break; + default: + LOG_ERROR("Unknown flash device ID 0x%" PRIX32, id); + return ERROR_FAIL; } bank->sectors = malloc(bank->num_sectors * sizeof(struct flash_sector)); diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index 39d93d66ac..1b51ce056a 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %C%_libhelper_la_SOURCES = \ + %D%/base64.c \ %D%/binarybuffer.c \ %D%/options.c \ %D%/time_support_common.c \ @@ -18,7 +19,9 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/jim-nvp.c \ %D%/nvp.c \ %D%/align.h \ + %D%/base64.h \ %D%/binarybuffer.h \ + %D%/bitfield.h \ %D%/bits.h \ %D%/configuration.h \ %D%/list.h \ @@ -29,6 +32,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ + %D%/string_choices.h \ %D%/fileio.h \ %D%/system.h \ %D%/jep106.h \ diff --git a/src/helper/base64.c b/src/helper/base64.c index effa8acda0..5e0ee0846e 100644 --- a/src/helper/base64.c +++ b/src/helper/base64.c @@ -1,9 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause + /* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005-2011, Jouni Malinen * - * This software may be distributed under the terms of the BSD license. - * See README for more details. + * Original file from FreeBSD code + * https://cgit.freebsd.org/src/tree/contrib/wpa/src/utils/base64.c?id=f05cddf940db */ @@ -42,7 +44,7 @@ unsigned char *base64_encode(const unsigned char *src, size_t len, if (olen < len) return NULL; /* integer overflow */ out = malloc(olen); - if (out == NULL) + if (!out) return NULL; end = src + len; @@ -105,7 +107,7 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, memset(dtable, 0x80, 256); for (i = 0; i < sizeof(base64_table) - 1; i++) - dtable[base64_table[i]] = (unsigned char) i; + dtable[base64_table[i]] = (unsigned char)i; dtable['='] = 0; count = 0; @@ -118,9 +120,10 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, return NULL; olen = count / 4 * 3; - pos = out = malloc(olen); - if (out == NULL) + out = malloc(olen); + if (!out) return NULL; + pos = out; count = 0; for (i = 0; i < len; i++) { @@ -138,11 +141,11 @@ unsigned char *base64_decode(const unsigned char *src, size_t len, *pos++ = (block[2] << 6) | block[3]; count = 0; if (pad) { - if (pad == 1) + if (pad == 1) { pos--; - else if (pad == 2) + } else if (pad == 2) { pos -= 2; - else { + } else { /* Invalid padding */ free(out); return NULL; diff --git a/src/helper/base64.h b/src/helper/base64.h index dbabb606ab..d3e0462131 100644 --- a/src/helper/base64.h +++ b/src/helper/base64.h @@ -1,9 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + /* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005, Jouni Malinen * - * This software may be distributed under the terms of the BSD license. - * See README for more details. + * Original file from FreeBSD code + * https://cgit.freebsd.org/src/tree/contrib/wpa/src/utils/base64.h?id=f05cddf940db */ #ifndef BASE64_H diff --git a/src/helper/bitfield.h b/src/helper/bitfield.h new file mode 100644 index 0000000000..9f397282cf --- /dev/null +++ b/src/helper/bitfield.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* +* Copyright (c) 2020-2024 The FreeBSD Foundation +* +* This software was developed by Björn Zeeb under sponsorship from +* the FreeBSD Foundation. +*/ + +#ifndef OPENOCD_HELPER_BITFIELD_H +#define OPENOCD_HELPER_BITFIELD_H + +/** + * These macros come from FreeBSD, check source on + * https://cgit.freebsd.org/src/tree/sys/compat/linuxkpi/common/include/linux/bitfield.h + * Which does not include example usages of them. + */ + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +/** + * FIELD_FIT(_mask, _value) - Check if a value fits in the specified bitfield mask + * @_mask: Bitfield mask + * @_value: Value to check + * + * This macro checks whether a given value fits within the range defined by the + * specified bitfield mask. It ensures that no bits outside the mask are set. + * + * Return: true if the value fits, false otherwise. + */ +#define FIELD_FIT(_mask, _value) \ + (!(((typeof(_mask))(_value) << __bf_shf(_mask)) & ~(_mask))) + +/** + * FIELD_PREP(_mask, _value) - Prepare a value for insertion into a bitfield + * @_mask: Bitfield mask + * @_value: Value to insert + * + * This macro prepares a value for insertion into a bitfield by shifting the + * value into the position defined by the mask and applying the mask. + * + * Return: The prepared bitfield value. + */ +#define FIELD_PREP(_mask, _value) \ + (((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask)) + +/** + * FIELD_GET(_mask, _value) - Extract a value from a bitfield + * @_mask: Bitfield mask + * @_value: Bitfield value to extract from + * + * This macro extracts a value from a bitfield by masking and shifting the + * relevant bits down to the least significant position. + * + * Return: The extracted value. + */ +#define FIELD_GET(_mask, _value) \ + ((typeof(_mask))(((_value) & (_mask)) >> __bf_shf(_mask))) + +#endif /* OPENOCD_HELPER_BITFIELD_H */ diff --git a/src/helper/command.c b/src/helper/command.c index 218f0581ef..4cce57f756 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -45,26 +45,22 @@ static enum command_mode get_command_mode(Jim_Interp *interp, const char *cmd_na /* set of functions to wrap jimtcl internal data */ static inline bool jimcmd_is_proc(Jim_Cmd *cmd) { +#if defined(JIM_CMD_ISPROC) + // JIM_VERSION >= 84 + return cmd->flags & JIM_CMD_ISPROC; +#else return cmd->isproc; +#endif } bool jimcmd_is_oocd_command(Jim_Cmd *cmd) { - return !cmd->isproc && cmd->u.native.cmdProc == jim_command_dispatch; + return !jimcmd_is_proc(cmd) && cmd->u.native.cmdProc == jim_command_dispatch; } void *jimcmd_privdata(Jim_Cmd *cmd) { - return cmd->isproc ? NULL : cmd->u.native.privData; -} - -static int command_retval_set(Jim_Interp *interp, int retval) -{ - int *return_retval = Jim_GetAssocData(interp, "retval"); - if (return_retval) - *return_retval = retval; - - return (retval == ERROR_OK) ? JIM_OK : retval; + return jimcmd_is_proc(cmd) ? NULL : cmd->u.native.privData; } extern struct command_context *global_cmd_ctx; @@ -73,7 +69,7 @@ extern struct command_context *global_cmd_ctx; * Do nothing in case we are not at debug level 3 */ static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj * const *argv) { - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return; char *dbg = alloc_printf("command -"); @@ -130,13 +126,13 @@ static struct command *command_new(struct command_context *cmd_ctx, assert(cr->name); /* - * If it is a non-jim command with no .usage specified, + * If it is a command with no .usage specified, * log an error. * * strlen(.usage) == 0 means that the command takes no * arguments. */ - if (!cr->jim_handler && !cr->usage) + if (!cr->usage) LOG_ERROR("BUG: command '%s' does not have the " "'.usage' field filled out", full_name); @@ -152,7 +148,6 @@ static struct command *command_new(struct command_context *cmd_ctx, } c->handler = cr->handler; - c->jim_handler = cr->jim_handler; c->mode = cr->mode; if (cr->help || cr->usage) @@ -406,28 +401,25 @@ static bool command_can_run(struct command_context *cmd_ctx, struct command *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; + 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'.", full_name ? full_name : c->name, when); return false; } -static int exec_command(Jim_Interp *interp, struct command_context *context, +static int jim_exec_command(Jim_Interp *interp, struct command_context *context, struct command *c, int argc, Jim_Obj * const *argv) { - if (c->jim_handler) - return c->jim_handler(interp, argc, argv); - /* use c->handler */ const char **words = malloc(argc * sizeof(char *)); if (!words) { @@ -474,7 +466,15 @@ static int exec_command(Jim_Interp *interp, struct command_context *context, Jim_DecrRefCount(context->interp, cmd.output); free(words); - return command_retval_set(interp, retval); + + if (retval == ERROR_OK) + return JIM_OK; + + // used by telnet server to close one connection + if (retval == ERROR_COMMAND_CLOSE_CONNECTION) + return JIM_EXIT; + + return JIM_ERR; } int command_run_line(struct command_context *context, char *line) @@ -484,7 +484,6 @@ int command_run_line(struct command_context *context, char *line) * results */ /* run the line thru a script engine */ - int retval = ERROR_FAIL; int retcode; /* Beware! This code needs to be reentrant. It is also possible * for OpenOCD commands to be invoked directly from Tcl. This would @@ -499,20 +498,17 @@ int command_run_line(struct command_context *context, char *line) Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); if (retcode == JIM_OK) { - /* associated the return value */ - Jim_DeleteAssocData(interp, "retval"); - retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); - if (retcode == JIM_OK) { - retcode = Jim_Eval_Named(interp, line, NULL, 0); - - Jim_DeleteAssocData(interp, "retval"); - } + retcode = Jim_Eval_Named(interp, line, NULL, 0); Jim_DeleteAssocData(interp, "context"); int inner_retcode = Jim_SetAssocData(interp, "context", NULL, old_context); if (retcode == JIM_OK) retcode = inner_retcode; } context->current_target_override = saved_target_override; + + if (retcode == JIM_RETURN) + retcode = interp->returnCode; + if (retcode == JIM_OK) { const char *result; int reslen; @@ -522,25 +518,19 @@ int command_run_line(struct command_context *context, char *line) command_output_text(context, result); command_output_text(context, "\n"); } - retval = ERROR_OK; - } else if (retcode == JIM_EXIT) { - /* ignore. - * exit(Jim_GetExitCode(interp)); */ - } else if (retcode == ERROR_COMMAND_CLOSE_CONNECTION) { - return retcode; - } else { - Jim_MakeErrorMessage(interp); - /* error is broadcast */ - LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + return ERROR_OK; + } - if (retval == ERROR_OK) { - /* It wasn't a low level OpenOCD command that failed */ - return ERROR_FAIL; - } - return retval; + if (retcode == JIM_EXIT) { + // used by telnet server to close one connection + return ERROR_COMMAND_CLOSE_CONNECTION; } - return retval; + Jim_MakeErrorMessage(interp); + /* error is broadcast */ + LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); + + return ERROR_FAIL; } int command_run_linef(struct command_context *context, const char *format, ...) @@ -742,16 +732,16 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c, const char *stage_msg = ""; switch (mode) { - case COMMAND_CONFIG: - stage_msg = " (configuration command)"; - break; - case COMMAND_ANY: - stage_msg = " (command valid any time)"; - break; - case COMMAND_UNKNOWN: - default: - stage_msg = " (?mode error?)"; - break; + case COMMAND_CONFIG: + stage_msg = " (configuration command)"; + break; + case COMMAND_ANY: + stage_msg = " (command valid any time)"; + break; + case COMMAND_UNKNOWN: + default: + stage_msg = " (?mode error?)"; + break; } msg = alloc_printf("%s%s", c->help ? c->help : "", stage_msg); } else @@ -841,7 +831,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a script_debug(interp, argc, argv); struct command *c = jim_to_command(interp); - if (!c->jim_handler && !c->handler) { + if (!c->handler) { Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp, "usage", -1), 1, argv); return JIM_ERR; } @@ -867,7 +857,7 @@ static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj * const *a if (c->jim_override_target) cmd_ctx->current_target_override = c->jim_override_target; - int retval = exec_command(interp, cmd_ctx, c, argc, argv); + int retval = jim_exec_command(interp, cmd_ctx, c, argc, argv); if (c->jim_override_target) cmd_ctx->current_target_override = saved_target_override; @@ -912,19 +902,19 @@ COMMAND_HANDLER(handle_command_mode) const char *mode_str; switch (mode) { - case COMMAND_ANY: - mode_str = "any"; - break; - case COMMAND_CONFIG: - mode_str = "config"; - break; - case COMMAND_EXEC: - mode_str = "exec"; - break; - case COMMAND_UNKNOWN: - default: - mode_str = "unknown"; - break; + case COMMAND_ANY: + mode_str = "any"; + break; + case COMMAND_CONFIG: + mode_str = "config"; + break; + case COMMAND_EXEC: + mode_str = "exec"; + break; + case COMMAND_UNKNOWN: + default: + mode_str = "unknown"; + break; } command_print(CMD, "%s", mode_str); return ERROR_OK; @@ -1329,19 +1319,19 @@ COMMAND_HELPER(command_parse_str_to_buf, const char *str, void *buf, unsigned in COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) { switch (CMD_ARGC) { - case 1: { - const char *in = CMD_ARGV[0]; - if (command_parse_bool_arg(in, out) != ERROR_OK) { - LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); - return ERROR_COMMAND_SYNTAX_ERROR; - } - } - /* fallthrough */ - case 0: - LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); - break; - default: + case 1: { + const char *in = CMD_ARGV[0]; + if (command_parse_bool_arg(in, out) != ERROR_OK) { + LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; + } + } + /* fallthrough */ + case 0: + LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } diff --git a/src/helper/command.h b/src/helper/command.h index 18fe561782..8bd2430e0b 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -197,7 +197,6 @@ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { char *name; command_handler_t handler; - Jim_CmdProc *jim_handler; void *jim_handler_data; /* Command handlers can use it for any handler specific data */ struct target *jim_override_target; @@ -234,7 +233,6 @@ static inline struct command *jim_to_command(Jim_Interp *interp) struct command_registration { const char *name; command_handler_t handler; - Jim_CmdProc *jim_handler; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ diff --git a/src/helper/configuration.c b/src/helper/configuration.c index 16732eb3dd..447b0dfefa 100644 --- a/src/helper/configuration.c +++ b/src/helper/configuration.c @@ -71,17 +71,18 @@ char *find_file(const char *file) full_path = alloc_printf("%s", file); fp = fopen(full_path, mode); - while (!fp) { - free(full_path); - full_path = NULL; - dir = *search_dirs++; + if (script_search_dirs) + while (!fp) { + free(full_path); + full_path = NULL; + dir = *search_dirs++; - if (!dir) - break; + if (!dir) + break; - full_path = alloc_printf("%s/%s", dir, file); - fp = fopen(full_path, mode); - } + full_path = alloc_printf("%s/%s", dir, file); + fp = fopen(full_path, mode); + } if (fp) { fclose(fp); diff --git a/src/helper/fileio.c b/src/helper/fileio.c index a290a5d2ff..1059c67060 100644 --- a/src/helper/fileio.c +++ b/src/helper/fileio.c @@ -49,24 +49,24 @@ static inline int fileio_open_local(struct fileio *fileio) ssize_t file_size; switch (fileio->access) { - case FILEIO_READ: - strcpy(file_access, "r"); - break; - case FILEIO_WRITE: - strcpy(file_access, "w"); - break; - case FILEIO_READWRITE: - strcpy(file_access, "w+"); - break; - case FILEIO_APPEND: - strcpy(file_access, "a"); - break; - case FILEIO_APPENDREAD: - strcpy(file_access, "a+"); - break; - default: - LOG_ERROR("BUG: access neither read, write nor readwrite"); - return ERROR_COMMAND_SYNTAX_ERROR; + case FILEIO_READ: + strcpy(file_access, "r"); + break; + case FILEIO_WRITE: + strcpy(file_access, "w"); + break; + case FILEIO_READWRITE: + strcpy(file_access, "w+"); + break; + case FILEIO_APPEND: + strcpy(file_access, "a"); + break; + case FILEIO_APPENDREAD: + strcpy(file_access, "a+"); + break; + default: + LOG_ERROR("BUG: access neither read, write nor readwrite"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* win32 always opens in binary mode */ diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index 8bbaf4ca5c..5e50e19550 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -8,7 +8,7 @@ * identification code list, please visit the JEDEC website at www.jedec.org . */ -/* This file is aligned to revision JEP106BL February 2025. */ +/* This file is aligned to revision JEP106BM June 2025. */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", @@ -78,7 +78,7 @@ [0][0x42 - 1] = "Macronix", [0][0x43 - 1] = "Xerox", [0][0x44 - 1] = "Plus Logic", -[0][0x45 - 1] = "Western Digital Technologies Inc", +[0][0x45 - 1] = "SanDisk Technologies Inc", [0][0x46 - 1] = "Elan Circuit Tech.", [0][0x47 - 1] = "European Silicon Str.", [0][0x48 - 1] = "Apple Computer", @@ -1798,7 +1798,7 @@ [14][0x16 - 1] = "Chiplego Technology (Shanghai) Co Ltd", [14][0x17 - 1] = "StoreSkill", [14][0x18 - 1] = "Shenzhen Astou Technology Company", -[14][0x19 - 1] = "Guangdong LeafFive Technology Limited", +[14][0x19 - 1] = "Guangdong LeapFive Technology Limited", [14][0x1a - 1] = "Jin JuQuan", [14][0x1b - 1] = "Huaxuan Technology (Shenzhen) Co Ltd", [14][0x1c - 1] = "Gigastone Corporation", @@ -2049,4 +2049,39 @@ [16][0x15 - 1] = "Hangzhou Lishu Technology Co Ltd", [16][0x16 - 1] = "Tier IV Inc", [16][0x17 - 1] = "Wuhan Xuanluzhe Network Technology Co", +[16][0x18 - 1] = "EA Semi (Shanghai) Limited", +[16][0x19 - 1] = "Tech Vision Information Technology Co", +[16][0x1a - 1] = "Zhihe Computing Technology", +[16][0x1b - 1] = "Beijing Apexichips Tech", +[16][0x1c - 1] = "Yemas Holdingsl Limited", +[16][0x1d - 1] = "Eluktronics", +[16][0x1e - 1] = "Walton Digi-Tech Industries Ltd", +[16][0x1f - 1] = "Beijing Qixin Gongli Technology Co Ltd", +[16][0x20 - 1] = "M.RED", +[16][0x21 - 1] = "Shenzhen Damay Semiconductor Co Ltd", +[16][0x22 - 1] = "Corelab Tech Singapore Holding PTE LTD", +[16][0x23 - 1] = "EmBestor Technology Inc", +[16][0x24 - 1] = "XConn Technologies", +[16][0x25 - 1] = "Flagchip", +[16][0x26 - 1] = "CUNNUC", +[16][0x27 - 1] = "SGMicro", +[16][0x28 - 1] = "Lanxin Computing (Shenzhen) Technology", +[16][0x29 - 1] = "FuturePlus Systems LLC", +[16][0x2a - 1] = "Shenzhen Jielong Storage Technology Co", +[16][0x2b - 1] = "Precision Planting LLC", +[16][0x2c - 1] = "Sichuan ZeroneStor Microelectronics Tech", +[16][0x2d - 1] = "The University of Tokyo", +[16][0x2e - 1] = "Aodu (Fujian) Information Technology Co", +[16][0x2f - 1] = "Bytera Memory Inc", +[16][0x30 - 1] = "XSemitron Technology Inc", +[16][0x31 - 1] = "Cloud Ridge Ltd", +[16][0x32 - 1] = "Shenzhen XinChiTai Technology Co Ltd", +[16][0x33 - 1] = "Shenzhen Xinxin Semiconductor Co Ltd", +[16][0x34 - 1] = "Shenzhen ShineKing Electronics Co Ltd.", +[16][0x35 - 1] = "Shenzhen Shande Semiconductor Co. Ltd.", +[16][0x36 - 1] = "AheadComputing", +[16][0x37 - 1] = "Beijing Ronghua Kangweiye Technology", +[16][0x38 - 1] = "Shanghai Yunsilicon Technology Co Ltd", +[16][0x39 - 1] = "Shenzhen Wolongtai Technology Co Ltd.", +[16][0x3a - 1] = "Vervesemi Microelectronics", /* EOF */ diff --git a/src/helper/log.c b/src/helper/log.c index 8f7ab00397..7acb154c62 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -113,7 +113,7 @@ static void log_puts(enum log_levels level, if (f) file = f + 1; - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* print with count and time information */ int64_t t = timeval_ms() - start; #ifdef _DEBUG_FREE_SPACE_ @@ -207,18 +207,19 @@ void log_printf_lf(enum log_levels level, COMMAND_HANDLER(handle_debug_level_command) { - if (CMD_ARGC == 1) { + if (!CMD_ARGC) { + command_print(CMD, "%i", debug_level); + } else if (CMD_ARGC == 1) { int new_level; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); if ((new_level > LOG_LVL_DEBUG_IO) || (new_level < LOG_LVL_SILENT)) { - LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO); - return ERROR_COMMAND_SYNTAX_ERROR; + command_print(CMD, "level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_IO); + return ERROR_COMMAND_ARGUMENT_INVALID; } debug_level = new_level; - } else if (CMD_ARGC > 1) + } else { return ERROR_COMMAND_SYNTAX_ERROR; - - command_print(CMD, "debug_level: %i", debug_level); + } return ERROR_OK; } @@ -261,11 +262,11 @@ static const struct command_registration log_command_handlers[] = { .name = "debug_level", .handler = handle_debug_level_command, .mode = COMMAND_ANY, - .help = "Sets the verbosity level of debugging output. " + .help = "Sets or display the verbosity level of debugging output. " "0 shows errors only; 1 adds warnings; " "2 (default) adds other info; 3 adds debugging; " "4 adds extra verbose debugging.", - .usage = "number", + .usage = "[number]", }, COMMAND_REGISTRATION_DONE }; @@ -353,6 +354,8 @@ char *alloc_vprintf(const char *fmt, va_list ap) int len; char *string; + assert(fmt); + /* determine the length of the buffer needed */ va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); diff --git a/src/helper/log.h b/src/helper/log.h index ac24f8e833..b8e3e339ae 100644 --- a/src/helper/log.h +++ b/src/helper/log.h @@ -15,6 +15,7 @@ #define OPENOCD_HELPER_LOG_H #include +#include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later @@ -86,9 +87,9 @@ int log_add_callback(log_callback_fn fn, void *priv); int log_remove_callback(log_callback_fn fn, void *priv); char *alloc_vprintf(const char *fmt, va_list ap) - __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 0))); + __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 0))) __nonnull((1)); char *alloc_printf(const char *fmt, ...) - __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))); + __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 1, 2))) __nonnull((1)); const char *find_nonprint_char(const char *buf, unsigned int buf_len); @@ -101,7 +102,7 @@ extern int debug_level; #define LOG_DEBUG_IO(expr ...) \ do { \ - if (debug_level >= LOG_LVL_DEBUG_IO) \ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ @@ -109,7 +110,7 @@ extern int debug_level; #define LOG_DEBUG(expr ...) \ do { \ - if (debug_level >= LOG_LVL_DEBUG) \ + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ @@ -118,7 +119,7 @@ extern int debug_level; #define LOG_CUSTOM_LEVEL(level, expr ...) \ do { \ enum log_levels _level = level; \ - if (debug_level >= _level) \ + if (LOG_LEVEL_IS(_level)) \ log_printf_lf(_level, \ __FILE__, __LINE__, __func__, \ expr); \ diff --git a/src/helper/options.c b/src/helper/options.c index 735b8af5f6..28e2221717 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -277,44 +277,44 @@ int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) break; switch (c) { - case 0: - break; - case 'h': /* --help | -h */ - help_flag = 1; - break; - case 'v': /* --version | -v */ - version_flag = 1; - break; - case 'f': /* --file | -f */ - { - char *command = alloc_printf("script {%s}", optarg); - add_config_command(command); - free(command); - break; - } - case 's': /* --search | -s */ - add_script_search_dir(optarg); - break; - case 'd': /* --debug | -d */ - { - int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3"); - if (retval != ERROR_OK) - return retval; - break; - } - case 'l': /* --log_output | -l */ - { - int retval = command_run_linef(cmd_ctx, "log_output %s", optarg); - if (retval != ERROR_OK) - return retval; - break; - } - case 'c': /* --command | -c */ - add_config_command(optarg); - break; - default: /* '?' */ - /* getopt will emit an error message, all we have to do is bail. */ - return ERROR_FAIL; + case 0: + break; + case 'h': /* --help | -h */ + help_flag = 1; + break; + case 'v': /* --version | -v */ + version_flag = 1; + break; + case 'f': /* --file | -f */ + { + char *command = alloc_printf("script {%s}", optarg); + add_config_command(command); + free(command); + break; + } + case 's': /* --search | -s */ + add_script_search_dir(optarg); + break; + case 'd': /* --debug | -d */ + { + int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3"); + if (retval != ERROR_OK) + return retval; + break; + } + case 'l': /* --log_output | -l */ + { + int retval = command_run_linef(cmd_ctx, "log_output %s", optarg); + if (retval != ERROR_OK) + return retval; + break; + } + case 'c': /* --command | -c */ + add_config_command(optarg); + break; + default: /* '?' */ + /* getopt will emit an error message, all we have to do is bail. */ + return ERROR_FAIL; } } diff --git a/src/helper/replacements.c b/src/helper/replacements.c index 782d975184..9fb7b4a35b 100644 --- a/src/helper/replacements.c +++ b/src/helper/replacements.c @@ -152,6 +152,21 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time FD_ZERO(&sock_write); FD_ZERO(&sock_except); + /* On Windows, if all provided sets are empty/NULL an error code of -1 is returned + * and WSAGetLastError() returns WSAEINVAL instead of delaying. + * We check for this case, delay and return 0 instead of calling select(). */ + if (rfds && rfds->fd_count == 0) + rfds = NULL; + if (wfds && wfds->fd_count == 0) + wfds = NULL; + if (efds && efds->fd_count == 0) + efds = NULL; + if (!rfds && !wfds && !efds && tv) { + sleep(tv->tv_sec); + usleep(tv->tv_usec); + return 0; + } + /* build an array of handles for non-sockets */ for (i = 0; i < max_fd; i++) { if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) { diff --git a/src/helper/replacements.h b/src/helper/replacements.h index ecc0e5e955..747c2ae09a 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -225,6 +225,20 @@ static inline int socket_select(int max_fd, #endif } +static inline int socket_recv_timeout(int fd, unsigned long timeout_msec) +{ +#ifdef _WIN32 + DWORD timeout = timeout_msec; + return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, + sizeof(timeout)); +#else + struct timeval tv; + tv.tv_sec = timeout_msec / 1000; + tv.tv_usec = (timeout_msec % 1000) * 1000; + return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv)); +#endif +} + #ifndef HAVE_ELF_H typedef uint32_t Elf32_Addr; diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index e6e76e68fd..89ed71b900 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -7,7 +7,8 @@ # Try flipping / and \ to find file if the filename does not # match the precise spelling -proc find {filename} { +# lappend _telnet_autocomplete_skip _find_internal +proc _find_internal {filename} { if {[catch {ocd_find $filename} t]==0} { return $t } @@ -20,6 +21,49 @@ proc find {filename} { # make sure error message matches original input string return -code error "Can't find $filename" } + +proc find {filename} { + if {[catch {_find_internal $filename} t]==0} { + return $t + } + + # Check in vendor specific folder: + + # - path/to/a/certain/vendor_config_file + # - path/to/a/certain/vendor-config_file + # replaced with + # - path/to/a/certain/vendor/config_file + regsub {([/\\])([^/\\_-]*)[_-]([^/\\]*$)} $filename "\\1\\2\\1\\3" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + + foreach vendor {nordic ti sifive st} { + # - path/to/a/certain/config_file + # replaced with + # - path/to/a/certain/${vendor}/config_file + regsub {([/\\])([^/\\]*$)} $filename "\\1$vendor\\1\\2" f + if {[catch {_find_internal $f} t]==0} { + echo "WARNING: '$filename' is deprecated, use '$f' instead" + return $t + } + } + + # at last, check for explicit renaming + if {[catch { + source [_find_internal file_renaming.cfg] + set unixname [string map {\\ /} $filename] + regsub {^(.*/|)((board|chip|cpld|cpu|fpga|interface|target|test|tools)/.*.cfg$)} $unixname {{\1} {\2}} split + set newname [lindex $split 0][dict get $_file_renaming [lindex $split 1]] + _find_internal $newname + } t]==0} { + echo "WARNING: '$filename' is deprecated, use '$newname' instead" + return $t + } + + return -code error "Can't find $filename" +} add_usage_text find "" add_help_text find "print full path to file according to OpenOCD search rules" diff --git a/src/helper/string_choices.h b/src/helper/string_choices.h new file mode 100644 index 0000000000..7e535845da --- /dev/null +++ b/src/helper/string_choices.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef OPENOCD_HELPER_STRING_CHOICES_H +#define OPENOCD_HELPER_STRING_CHOICES_H + +#include + +/* + * This file contains helper functions that return one of two strings depending + * on a boolean value. The format of these functions is 'str_$true_$false' where + * $true and $false are the two corresponding strings. + * + * These helper functions are beneficial because they improve code consistency + * and reduce the number of hardcoded strings. + */ + +static inline const char *str_enabled_disabled(bool value) +{ + return value ? "enabled" : "disabled"; +} + +#endif /* OPENOCD_HELPER_STRING_CHOICES_H */ diff --git a/src/helper/system.h b/src/helper/system.h index bd96d626ab..60308abcd6 100644 --- a/src/helper/system.h +++ b/src/helper/system.h @@ -39,13 +39,6 @@ #include #endif -#ifdef __ECOS -/* missing from eCos */ -#ifndef EFAULT -#define EFAULT 14 /* Bad address */ -#endif -#endif - #ifdef HAVE_NETINET_IN_H #include #endif diff --git a/src/helper/types.h b/src/helper/types.h index 53249e5b79..8b02d213b1 100644 --- a/src/helper/types.h +++ b/src/helper/types.h @@ -51,7 +51,7 @@ * Compute the number of elements of a variable length array. * * const char *strs[] = { "a", "b", "c" }; - * unsigned num_strs = ARRAY_SIZE(strs); + * size_t num_strs = ARRAY_SIZE(strs); * */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) @@ -276,62 +276,6 @@ static inline int parity_u32(uint32_t x) #endif } -#if defined(__ECOS) - -/* eCos plain lacks these definition... A series of upstream patches - * could probably repair it, but it seems like too much work to be - * worth it. - */ - -#if !defined(_STDINT_H) -#define PRId32 "d" -#define PRIi32 "i" -#define PRIo32 "o" -#define PRIu32 "u" -#define PRIx32 "x" -#define PRIX32 "X" -#define SCNx32 "x" -#define PRId8 PRId32 -#define SCNx64 "llx" -#define PRId64 "lld" -#define PRIi64 "lli" -#define PRIo64 "llo" -#define PRIu64 "llu" -#define PRIx64 "llx" -#define PRIX64 "llX" - -typedef CYG_ADDRWORD intptr_t; -typedef int64_t intmax_t; -typedef uint64_t uintmax_t; -#define INT8_MAX 0x7f -#define INT8_MIN (-INT8_MAX - 1) -# define UINT8_MAX (255) -#define INT16_MAX 0x7fff -#define INT16_MIN (-INT16_MAX - 1) -# define UINT16_MAX (65535) -#define INT32_MAX 0x7fffffffL -#define INT32_MIN (-INT32_MAX - 1L) -# define UINT32_MAX (4294967295U) -#define INT64_MAX 0x7fffffffffffffffLL -#define INT64_MIN (-INT64_MAX - 1LL) -#define UINT64_MAX (__CONCAT(INT64_MAX, U) * 2ULL + 1ULL) -#endif - - #ifndef LLONG_MAX - #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) - #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) - #define LLONG_MIN ULLONG_MAX - #endif - - -#define ULLONG_MAX 18446744073709551615 - -/* C99, eCos is C90 compliant (with bits of C99) */ -#define isblank(c) ((c) == ' ' || (c) == '\t') - - -#endif - typedef uint64_t target_addr_t; #define TARGET_ADDR_MAX UINT64_MAX #define TARGET_PRIdADDR PRId64 diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index 6785a74ef1..c30a26c87b 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -53,17 +53,19 @@ static const struct gpio_map { enum adapter_gpio_direction direction; bool permit_drive_option; bool permit_init_state_option; + bool permit_exit_state_option; } gpio_map[ADAPTER_GPIO_IDX_NUM] = { - [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, }, - [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, - [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, - [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, - [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, }, - [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, }, - [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, - [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, - [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, }, - [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, }, + [ADAPTER_GPIO_IDX_TDO] = { "tdo", ADAPTER_GPIO_DIRECTION_INPUT, false, true, true }, + [ADAPTER_GPIO_IDX_TDI] = { "tdi", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TMS] = { "tms", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TCK] = { "tck", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_SWDIO] = { "swdio", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, true }, + [ADAPTER_GPIO_IDX_SWDIO_DIR] = { "swdio_dir", ADAPTER_GPIO_DIRECTION_OUTPUT, true, false, false }, + [ADAPTER_GPIO_IDX_SWCLK] = { "swclk", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_TRST] = { "trst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, true }, + [ADAPTER_GPIO_IDX_SRST] = { "srst", ADAPTER_GPIO_DIRECTION_OUTPUT, false, true, true }, + [ADAPTER_GPIO_IDX_LED] = { "led", ADAPTER_GPIO_DIRECTION_OUTPUT, true, true, true }, + [ADAPTER_GPIO_IDX_USER0] = { "user0", ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL, true, true, true }, }; static int adapter_config_khz(unsigned int khz); @@ -269,15 +271,15 @@ int adapter_config_rclk(unsigned int fallback_speed_khz) int adapter_get_speed(int *speed) { switch (adapter_config.clock_mode) { - case CLOCK_MODE_KHZ: - adapter_khz_to_speed(adapter_get_speed_khz(), speed); - break; - case CLOCK_MODE_RCLK: - adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed); - break; - default: - LOG_ERROR("BUG: unknown adapter clock mode"); - return ERROR_FAIL; + case CLOCK_MODE_KHZ: + adapter_khz_to_speed(adapter_get_speed_khz(), speed); + break; + case CLOCK_MODE_RCLK: + adapter_rclk_to_speed(adapter_config.rclk_fallback_speed_khz, speed); + break; + default: + LOG_ERROR("BUG: unknown adapter clock mode"); + return ERROR_FAIL; } return ERROR_OK; } @@ -613,34 +615,34 @@ COMMAND_HANDLER(handle_reset_config_command) /* minimal JTAG has neither SRST nor TRST (so that's the default) */ switch (new_cfg & (RESET_HAS_TRST | RESET_HAS_SRST)) { - case RESET_HAS_SRST: - modes[0] = "srst_only"; - break; - case RESET_HAS_TRST: - modes[0] = "trst_only"; - break; - case RESET_TRST_AND_SRST: - modes[0] = "trst_and_srst"; - break; - default: - modes[0] = "none"; - break; + case RESET_HAS_SRST: + modes[0] = "srst_only"; + break; + case RESET_HAS_TRST: + modes[0] = "trst_only"; + break; + case RESET_TRST_AND_SRST: + modes[0] = "trst_and_srst"; + break; + default: + modes[0] = "none"; + break; } /* normally SRST and TRST are decoupled; but bugs happen ... */ switch (new_cfg & (RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST)) { - case RESET_SRST_PULLS_TRST: - modes[1] = "srst_pulls_trst"; - break; - case RESET_TRST_PULLS_SRST: - modes[1] = "trst_pulls_srst"; - break; - case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: - modes[1] = "combined"; - break; - default: - modes[1] = "separate"; - break; + case RESET_SRST_PULLS_TRST: + modes[1] = "srst_pulls_trst"; + break; + case RESET_TRST_PULLS_SRST: + modes[1] = "trst_pulls_srst"; + break; + case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: + modes[1] = "combined"; + break; + default: + modes[1] = "separate"; + break; } /* TRST-less connectors include Altera, Xilinx, and minimal JTAG */ @@ -850,6 +852,7 @@ static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config const char *drive = ""; const char *pull = ""; const char *init_state = ""; + const char *exit_state = ""; if (gpio_config->gpio_num == ADAPTER_GPIO_NOT_SET) { command_print(CMD, "adapter gpio %s: not configured", gpio_map[gpio_idx].name); @@ -908,9 +911,27 @@ static COMMAND_HELPER(helper_adapter_gpio_print_config, enum adapter_gpio_config } } - command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s", + if (gpio_map[gpio_idx].permit_exit_state_option) { + switch (gpio_config->exit_state) { + case ADAPTER_GPIO_EXIT_STATE_NO_CHANGE: + exit_state = ", exit-state no-change"; + break; + case ADAPTER_GPIO_EXIT_STATE_INACTIVE: + exit_state = ", exit-state inactive"; + break; + case ADAPTER_GPIO_EXIT_STATE_ACTIVE: + exit_state = ", exit-state active"; + break; + case ADAPTER_GPIO_EXIT_STATE_INPUT: + exit_state = ", exit-state input"; + break; + } + } + + + command_print(CMD, "adapter gpio %s (%s): num %u, chip %d, active-%s%s%s%s%s", gpio_map[gpio_idx].name, dir, gpio_config->gpio_num, (int)gpio_config->chip_num, active_state, - drive, pull, init_state); + drive, pull, init_state, exit_state); return ERROR_OK; } @@ -1031,6 +1052,31 @@ COMMAND_HANDLER(adapter_gpio_config_handler) } } + if (gpio_map[gpio_idx].permit_exit_state_option) { + if (strcmp(CMD_ARGV[i], "-exit-no-change") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_NO_CHANGE; + continue; + } + if (strcmp(CMD_ARGV[i], "-exit-inactive") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_INACTIVE; + continue; + } + if (strcmp(CMD_ARGV[i], "-exit-active") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_ACTIVE; + continue; + } + + if (gpio_map[gpio_idx].direction == ADAPTER_GPIO_DIRECTION_BIDIRECTIONAL && + strcmp(CMD_ARGV[i], "-exit-input") == 0) { + ++i; + gpio_config->exit_state = ADAPTER_GPIO_EXIT_STATE_INPUT; + continue; + } + } + LOG_ERROR("illegal option for adapter %s %s: %s", CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1168,7 +1214,8 @@ static const struct command_registration adapter_command_handlers[] = { "[-active-high|-active-low] " "[-push-pull|-open-drain|-open-source] " "[-pull-none|-pull-up|-pull-down]" - "[-init-inactive|-init-active|-init-input] ]", + "[-init-inactive|-init-active|-init-input] ]" + "[-exit-no-change|-exit-inactive|-exit-active|-exit-input] ]", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/adapter.h b/src/jtag/adapter.h index 556952f8d7..d76ea5e327 100644 --- a/src/jtag/adapter.h +++ b/src/jtag/adapter.h @@ -33,6 +33,14 @@ enum adapter_gpio_init_state { ADAPTER_GPIO_INIT_STATE_INPUT, }; +/** Supported exit states for GPIO */ +enum adapter_gpio_exit_state { + ADAPTER_GPIO_EXIT_STATE_NO_CHANGE, /* Should be zero so it is the default state */ + ADAPTER_GPIO_EXIT_STATE_INACTIVE, + ADAPTER_GPIO_EXIT_STATE_ACTIVE, + ADAPTER_GPIO_EXIT_STATE_INPUT, +}; + /** Supported pull directions for GPIO */ enum adapter_gpio_pull { ADAPTER_GPIO_PULL_NONE, @@ -52,6 +60,7 @@ enum adapter_gpio_config_index { ADAPTER_GPIO_IDX_SWCLK, ADAPTER_GPIO_IDX_SRST, ADAPTER_GPIO_IDX_LED, + ADAPTER_GPIO_IDX_USER0, ADAPTER_GPIO_IDX_NUM, /* must be the last item */ }; @@ -61,6 +70,7 @@ struct adapter_gpio_config { unsigned int chip_num; enum adapter_gpio_drive_mode drive; /* For outputs only */ enum adapter_gpio_init_state init_state; + enum adapter_gpio_exit_state exit_state; bool active_low; enum adapter_gpio_pull pull; }; diff --git a/src/jtag/core.c b/src/jtag/core.c index 6dd2144c63..3261e60796 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -967,60 +967,60 @@ int default_interface_jtag_execute_queue(void) struct jtag_command *cmd = jtag_command_queue_get(); int result = adapter_driver->jtag_ops->execute_queue(cmd); - while (debug_level >= LOG_LVL_DEBUG_IO && cmd) { + while (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO) && cmd) { switch (cmd->type) { - case JTAG_SCAN: - LOG_DEBUG_IO("JTAG %s SCAN to %s", - cmd->cmd.scan->ir_scan ? "IR" : "DR", - tap_state_name(cmd->cmd.scan->end_state)); - for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { - struct scan_field *field = cmd->cmd.scan->fields + i; - if (field->out_value) { - char *str = buf_to_hex_str(field->out_value, field->num_bits); - LOG_DEBUG_IO(" %ub out: %s", field->num_bits, str); - free(str); - } - if (field->in_value) { - char *str = buf_to_hex_str(field->in_value, field->num_bits); - LOG_DEBUG_IO(" %ub in: %s", field->num_bits, str); - free(str); - } + case JTAG_SCAN: + LOG_DEBUG_IO("JTAG %s SCAN to %s", + cmd->cmd.scan->ir_scan ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + for (unsigned int i = 0; i < cmd->cmd.scan->num_fields; i++) { + struct scan_field *field = cmd->cmd.scan->fields + i; + if (field->out_value) { + char *str = buf_to_hex_str(field->out_value, field->num_bits); + LOG_DEBUG_IO(" %ub out: %s", field->num_bits, str); + free(str); } - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("JTAG TLR RESET to %s", - tap_state_name(cmd->cmd.statemove->end_state)); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - break; - case JTAG_RESET: - { - const char *reset_str[3] = { - "leave", "deassert", "assert" - }; - LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", - reset_str[cmd->cmd.reset->trst + 1], - reset_str[cmd->cmd.reset->srst + 1]); + if (field->in_value) { + char *str = buf_to_hex_str(field->in_value, field->num_bits); + LOG_DEBUG_IO(" %ub in: %s", field->num_bits, str); + free(str); } - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("JTAG SLEEP (TODO)"); - break; - case JTAG_STABLECLOCKS: - LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); - break; - case JTAG_TMS: - LOG_DEBUG_IO("JTAG TMS (TODO)"); - break; - default: - LOG_ERROR("Unknown JTAG command: %d", cmd->type); - break; + } + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("JTAG TLR RESET to %s", + tap_state_name(cmd->cmd.statemove->end_state)); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("JTAG RUNTEST %d cycles to %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + break; + case JTAG_RESET: + { + const char *reset_str[3] = { + "leave", "deassert", "assert" + }; + LOG_DEBUG_IO("JTAG RESET %s TRST, %s SRST", + reset_str[cmd->cmd.reset->trst + 1], + reset_str[cmd->cmd.reset->srst + 1]); + } + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("JTAG PATHMOVE (TODO)"); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("JTAG SLEEP (TODO)"); + break; + case JTAG_STABLECLOCKS: + LOG_DEBUG_IO("JTAG STABLECLOCKS (TODO)"); + break; + case JTAG_TMS: + LOG_DEBUG_IO("JTAG TMS (TODO)"); + break; + default: + LOG_ERROR("Unknown JTAG command: %d", cmd->type); + break; } cmd = cmd->next; } @@ -1551,22 +1551,22 @@ int jtag_init_inner(struct command_context *cmd_ctx) */ retval = jtag_examine_chain(); switch (retval) { - case ERROR_OK: - /* complete success */ - break; - default: - /* For backward compatibility reasons, try coping with - * configuration errors involving only ID mismatches. - * We might be able to talk to the devices. - * - * Also the device might be powered down during startup. - * - * After OpenOCD starts, we can try to power on the device - * and run a reset. - */ - LOG_ERROR("Trying to use configured scan chain anyway..."); - issue_setup = false; - break; + case ERROR_OK: + /* complete success */ + break; + default: + /* For backward compatibility reasons, try coping with + * configuration errors involving only ID mismatches. + * We might be able to talk to the devices. + * + * Also the device might be powered down during startup. + * + * After OpenOCD starts, we can try to power on the device + * and run a reset. + */ + LOG_ERROR("Trying to use configured scan chain anyway..."); + issue_setup = false; + break; } /* Now look at IR values. Problems here will prevent real diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index b0dd8e3ad1..5216e5d774 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -127,8 +127,6 @@ endif if ANGIE angiedir = $(pkgdatadir)/angie DRIVERFILES += %D%/angie.c - DRIVERFILES += %D%/angie/include/msgtypes.h - EXTRA_DIST += %D%/angie/README dist_angie_DATA = %D%/angie/angie_firmware.bin dist_angie_DATA += %D%/angie/angie_bitstream.bit %C%_libocdjtagdrivers_la_LIBADD += -lm @@ -179,8 +177,8 @@ endif if LINUXSPIDEV DRIVERFILES += %D%/linuxspidev.c endif -if XLNX_PCIE_XVC -DRIVERFILES += %D%/xlnx-pcie-xvc.c +if XLNX_XVC +DRIVERFILES += %D%/xlnx-xvc.c endif if BCM2835GPIO DRIVERFILES += %D%/bcm2835gpio.c @@ -188,15 +186,17 @@ endif if OPENJTAG DRIVERFILES += %D%/openjtag.c endif +if CMSIS_DAP_CORE +DRIVERFILES += %D%/cmsis_dap.c +endif if CMSIS_DAP_HID DRIVERFILES += %D%/cmsis_dap_usb_hid.c -DRIVERFILES += %D%/cmsis_dap.c endif if CMSIS_DAP_USB DRIVERFILES += %D%/cmsis_dap_usb_bulk.c -if !CMSIS_DAP_HID -DRIVERFILES += %D%/cmsis_dap.c endif +if CMSIS_DAP_TCP +DRIVERFILES += %D%/cmsis_dap_tcp.c endif if IMX_GPIO DRIVERFILES += %D%/imx_gpio.c @@ -210,6 +210,9 @@ endif if AM335XGPIO DRIVERFILES += %D%/am335xgpio.c endif +if CH347 +DRIVERFILES += %D%/ch347.c +endif DRIVERHEADERS = \ %D%/bitbang.h \ diff --git a/src/jtag/drivers/amt_jtagaccel.c b/src/jtag/drivers/amt_jtagaccel.c index 633c20413a..6f1718896e 100644 --- a/src/jtag/drivers/amt_jtagaccel.c +++ b/src/jtag/drivers/amt_jtagaccel.c @@ -332,43 +332,43 @@ static int amt_jtagaccel_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); - amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); - amt_jtagaccel_state_move(); - break; - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - amt_jtagaccel_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); + amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); + amt_jtagaccel_state_move(); + break; + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + amt_jtagaccel_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -419,6 +419,8 @@ static int amt_jtagaccel_init(void) #endif uint8_t ar_status; + LOG_WARNING("This adapter is deprecated and support will be removed in the next release!"); + #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 56a118eaed..6d8dc2c3b1 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -1,274 +1,398 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/*************************************************************************** - File : angie.c * - Contents : OpenOCD driver code for NanoXplore USB-JTAG ANGIE * - adapter hardware. * - Based on openULINK driver code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * - ***************************************************************************/ +/**************************************************************************** + * File : angie.c + * Contents : Driver code for NanoXplore USB-JTAG ANGIE + * adapter hardware. + * Based on FT232R driver code by: Serge Vakulenko + * + * Copyright 2024, Ahmed BOUDJELIDA, NanoXplore SAS. + * + ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include -#include -#include -#include "helper/system.h" -#include +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +// project specific includes +#include #include #include +#include +#include "libusb_helper.h" #include #include -#include "libusb_helper.h" -#include "angie/include/msgtypes.h" -/** USB Vendor ID of ANGIE device in unconfigured state (no firmware loaded - * yet) or with its firmware. */ -#define ANGIE_VID 0x584e +// system includes +#include +#include +#include +#include +#include + +/* + * Sync bit bang mode is implemented as described in FTDI Application + * Note AN232R-01: "Bit Bang Modes for the ANGIE and FT245R". + */ -/** USB Product ID of ANGIE device in unconfigured state (no firmware loaded - * yet) or with its firmware. */ -#define ANGIE_PID 0x414F -#define ANGIE_PID_2 0x424e -#define ANGIE_PID_3 0x4255 -#define ANGIE_PID_4 0x4355 -#define ANGIE_PID_5 0x4a55 +/** + * USB endpoints. + */ +#define IN_EP 0x84 +#define OUT_EP 0x02 -/** Address of EZ-USB ANGIE CPU Control & Status register. This register can be - * written by issuing a Control EP0 vendor request. */ -#define CPUCS_REG 0xE600 +/** + * Address of EZ-USB ANGIE CPU Control & Status register. + * This register can be written by issuing a Control EP0 vendor request. + */ +#define CPUCS_REG 0xE600 /** USB Control EP0 bRequest: "Firmware Load". */ #define REQUEST_FIRMWARE_LOAD 0xA0 /** Value to write into CPUCS to put EZ-USB ANGIE into reset. */ -#define CPU_RESET 0x01 +#define CPU_RESET 0x01 /** Value to write into CPUCS to put EZ-USB ANGIE out of reset. */ -#define CPU_START 0x00 +#define CPU_START 0x00 /** Base address of firmware in EZ-USB ANGIE code space. */ -#define FIRMWARE_ADDR 0x0000 - -/** USB interface number */ -#define USB_INTERFACE 0 +#define FIRMWARE_ADDR 0x0000 /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ -#define ANGIE_RENUMERATION_DELAY_US 1500000 +#define ANGIE_RENUMERATION_DELAY_US 800000 /** Default location of ANGIE firmware image. */ -#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" +#define ANGIE_FIRMWARE_FILE PKGDATADIR "/angie/angie_firmware.bin" /** Default location of ANGIE firmware image. */ -#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" +#define ANGIE_BITSTREAM_FILE PKGDATADIR "/angie/angie_bitstream.bit" + +/** + * Maximum size of a single firmware section. + * Entire EZ-USB ANGIE code space = 16kB + */ +#define ANGIE_FW_SECTION_SIZE 16384 + +/** Vendor Requests */ +#define VR_CFGOPEN 0xB0 +#define VR_DATAOUTOPEN 0xB2 + +#define ANGIE_VID 0x584E /* NX Vendor id */ +#define ANGIE_NPROG_PID 0x424E /* ANGIE non programmed */ +#define ANGIE_PROG_OOCD_PID 0x414F /* ANGIE programmed OpenOCD */ +#define ANGIE_PROG_NXB2_PID 0x4a55 /* ANGIE programmed Nxbase2 */ + +#define TCK_GPIO 0 +#define TDI_GPIO 1 +#define TDO_GPIO 2 +#define TMS_GPIO 3 +#define NTRST_GPIO 4 +#define NSYSRST_GPIO 6 -/** Maximum size of a single firmware section. Entire EZ-USB ANGIE code space = 16kB */ -#define SECTION_BUFFERSIZE 16384 +#define ANGIE_XFER_BUFFER_TOTAL_SIZE (16 * 1024) +#define ANGIE_USB_BULK_SIZE 512 -/** Tuning of OpenOCD SCAN commands split into multiple ANGIE commands. */ -#define SPLIT_SCAN_THRESHOLD 10 +/** USB timeout delay in milliseconds */ +#define ANGIE_USB_TIMEOUT_MS 1000 -/** ANGIE hardware type */ -enum angie_type { - ANGIE, +/** + * List of elements used in a multiple commands reply. + */ +struct read_queue { + struct list_head list; }; -enum angie_payload_direction { - PAYLOAD_DIRECTION_OUT, - PAYLOAD_DIRECTION_IN +/** + * Entry element used to forge a reply buffer for openocd JTAG core. + */ +struct read_queue_entry { + const struct scan_command *cmd; + int reply_buffer_offset; + uint8_t *buffer; + struct list_head list; }; -enum angie_delay_type { - DELAY_CLOCK_TCK, - DELAY_CLOCK_TMS, - DELAY_SCAN_IN, - DELAY_SCAN_OUT, - DELAY_SCAN_IO +/** + * Angie device main context + */ +struct angie { + struct libusb_device_handle *usbdev; + uint8_t xfer_buffer[ANGIE_XFER_BUFFER_TOTAL_SIZE]; + size_t xfer_buffer_len; + uint8_t reply_buffer[ANGIE_XFER_BUFFER_TOTAL_SIZE]; + size_t reply_buffer_len; + struct read_queue read_queue; }; /** - * ANGIE command (ANGIE command queue element). + * Angie device singleton + */ +struct angie *angie_handle; + +/** + * Init read queue list * - * For the OUT direction payload, things are quite easy: Payload is stored - * in a rather small array (up to 63 bytes), the payload is always allocated - * by the function generating the command and freed by angie_clear_queue(). + * @param queue: pointer on the read queue head + */ +static void angie_read_queue_init(struct read_queue *queue) +{ + INIT_LIST_HEAD(&queue->list); +} + + +/** + * Add a single entry to the read queue * - * For the IN direction payload, things get a little bit more complicated: - * The maximum IN payload size for a single command is 64 bytes. Assume that - * a single OpenOCD command needs to scan 256 bytes. This results in the - * generation of four ANGIE commands. The function generating these - * commands shall allocate an uint8_t[256] array. Each command's #payload_in - * pointer shall point to the corresponding offset where IN data shall be - * placed, while #payload_in_start shall point to the first element of the 256 - * byte array. - * - first command: #payload_in_start + 0 - * - second command: #payload_in_start + 64 - * - third command: #payload_in_start + 128 - * - fourth command: #payload_in_start + 192 + * @param queue: read queue list + * @param entry to append + */ +static void angie_read_queue_add(struct read_queue *queue, + struct read_queue_entry *entry) +{ + list_add_tail(&entry->list, &queue->list); +} + +/** + * Execute elements enqueued in the read queue list * - * The last command sets #needs_postprocessing to true. + * @param queue: read queue list + * @param device: pointer on the angie device */ -struct angie_cmd { - uint8_t id; /**< ANGIE command ID */ +static void angie_read_queue_execute(struct read_queue *queue, + struct angie *device) +{ + struct read_queue_entry *entry; + struct read_queue_entry *tmp; + + list_for_each_entry_safe(entry, tmp, &queue->list, list) { + int scan_size = jtag_scan_size(entry->cmd); + + // iterate over each bit in scan data + for (int bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { + // calculate byte index + int bytec = bit_cnt / 8; + // calculate bit mask: isolate the specific bit in corresponding byte + int bcval = 1 << (bit_cnt % 8); + // extract tdo value using index: "bit0_index + bit_cnt*2 + 1" + int val = device->reply_buffer[entry->reply_buffer_offset + bit_cnt * 2 + 1]; + if (val & (1 << TDO_GPIO)) + entry->buffer[bytec] |= bcval; + else + entry->buffer[bytec] &= ~bcval; + } + + jtag_read_buffer(entry->buffer, entry->cmd); - uint8_t *payload_out; /**< Pointer where OUT payload shall be stored */ - uint8_t payload_out_size; /**< OUT direction payload size for this command */ + list_del(&entry->list); + free(entry->buffer); + free(entry); + } +} - uint8_t *payload_in_start; /**< Pointer to first element of IN payload array */ - uint8_t *payload_in; /**< Pointer where IN payload shall be stored */ - uint8_t payload_in_size; /**< IN direction payload size for this command */ +/** + * Clear the read queue list + * + * @param queue: read queue list + */ +static void angie_read_queue_clean(struct read_queue *queue) +{ + struct read_queue_entry *entry; + struct read_queue_entry *tmp; - /** Indicates if this command needs post-processing */ - bool needs_postprocessing; + list_for_each_entry_safe(entry, tmp, &queue->list, list) { + list_del(&entry->list); + free(entry->buffer); + free(entry); + } +} - /** Indicates if angie_clear_queue() should free payload_in_start */ - bool free_payload_in_start; +/** + * Flush a chunk of Angie's buffer + * + * USB write is done by configuring GPIF register on the target and calling + * a USB bulk transfer. + * Sequentially a USB read transferred is issued of the same size. + * All the operation are synchronous. + * Then the read queue list is executed once the read buffer has been retrieved. + * + * @param device: Angie device pointer + * @param xfer_size: amount of bytes to transfer + * @param offset: total bytes already sent during this transfer, this will + * offset the receive buffer accordingly + * @param bytes_sent: will contain the amount of bytes sent + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_flush_chunk(struct angie *device, + int xfer_size, + int offset, + int *bytes_sent) +{ + uint8_t gpifcnt[4]; + int sent_chunk_size = 0, bytes_received = 0; - /** Pointer to corresponding OpenOCD command for post-processing */ - struct jtag_command *cmd_origin; + if (bytes_sent) + *bytes_sent = 0; - struct angie_cmd *next; /**< Pointer to next command (linked list) */ -}; + h_u32_to_be(gpifcnt, xfer_size); -/** Describes one driver instance */ -struct angie { - struct libusb_context *libusb_ctx; - struct libusb_device_handle *usb_device_handle; - enum angie_type type; - - unsigned int ep_in; /**< IN endpoint number */ - unsigned int ep_out; /**< OUT endpoint number */ - - /* delay value for "SLOW_CLOCK commands" in [0:255] range in units of 4 us; - -1 means no need for delay */ - int delay_scan_in; /**< Delay value for SCAN_IN commands */ - int delay_scan_out; /**< Delay value for SCAN_OUT commands */ - int delay_scan_io; /**< Delay value for SCAN_IO commands */ - int delay_clock_tck; /**< Delay value for CLOCK_TMS commands */ - int delay_clock_tms; /**< Delay value for CLOCK_TCK commands */ - - int commands_in_queue; /**< Number of commands in queue */ - struct angie_cmd *queue_start; /**< Pointer to first command in queue */ - struct angie_cmd *queue_end; /**< Pointer to last command in queue */ -}; + int ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VR_DATAOUTOPEN, 0, 0, (char *)gpifcnt, sizeof(gpifcnt), + ANGIE_USB_TIMEOUT_MS, NULL); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to send GPIF count to target"); + return ret; + } -/**************************** Function Prototypes *****************************/ - -/* USB helper functions */ -static int angie_usb_open(struct angie *device); -static int angie_usb_close(struct angie *device); - -/* ANGIE MCU (Cypress EZ-USB) specific functions */ -static int angie_cpu_reset(struct angie *device, char reset_bit); -static int angie_load_firmware_and_renumerate(struct angie *device, const char *filename, - uint32_t delay_us); -static int angie_load_firmware(struct angie *device, const char *filename); -static int angie_load_bitstream(struct angie *device, const char *filename); -static int angie_i2c_write(struct angie *device, uint8_t *i2c_data, uint8_t i2c_data_size); -static int angie_io_extender_config(struct angie *device, uint8_t i2c_adr, uint8_t cfg_value); -static int angie_write_firmware_section(struct angie *device, - struct image *firmware_image, int section_index); - -/* Generic helper functions */ -static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals); - -/* ANGIE command generation helper functions */ -static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, - enum angie_payload_direction direction); - -/* ANGIE command queue helper functions */ -static int angie_get_queue_size(struct angie *device, - enum angie_payload_direction direction); -static void angie_clear_queue(struct angie *device); -static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd); -static int angie_execute_queued_commands(struct angie *device, int timeout_ms); - -static void angie_dump_queue(struct angie *device); - -static int angie_append_scan_cmd(struct angie *device, - enum scan_type scan_type, - int scan_size_bits, - uint8_t *tdi, - uint8_t *tdo_start, - uint8_t *tdo, - uint8_t tms_count_start, - uint8_t tms_sequence_start, - uint8_t tms_count_end, - uint8_t tms_sequence_end, - struct jtag_command *origin, - bool postprocess); -static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, - uint8_t sequence); -static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count); -static int angie_append_get_signals_cmd(struct angie *device); -static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, - uint8_t high); -static int angie_append_sleep_cmd(struct angie *device, uint32_t us); -static int angie_append_configure_tck_cmd(struct angie *device, - int delay_scan_in, - int delay_scan_out, - int delay_scan_io, - int delay_tck, - int delay_tms); -static int angie_append_test_cmd(struct angie *device); - -/* ANGIE TCK frequency helper functions */ -static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay); - -/* Interface between ANGIE and OpenOCD */ -static void angie_set_end_state(enum tap_state endstate); -static int angie_queue_statemove(struct angie *device); - -static int angie_queue_scan(struct angie *device, struct jtag_command *cmd); -static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd); -static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd); -static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd); -static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd); -static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd); - -static int angie_post_process_scan(struct angie_cmd *angie_cmd); -static int angie_post_process_queue(struct angie *device); - -/* adapter driver functions */ -static int angie_execute_queue(struct jtag_command *cmd_queue); -static int angie_khz(int khz, int *jtag_speed); -static int angie_speed(int speed); -static int angie_speed_div(int speed, int *khz); -static int angie_init(void); -static int angie_quit(void); -static int angie_reset(int trst, int srst); - -/****************************** Global Variables ******************************/ - -static struct angie *angie_handle; - -/**************************** USB helper functions ****************************/ + ret = jtag_libusb_bulk_write(device->usbdev, OUT_EP, + (char *)device->xfer_buffer + offset, + xfer_size, ANGIE_USB_TIMEOUT_MS, &sent_chunk_size); + if (ret != ERROR_OK) { + LOG_ERROR("USB bulk transfer failed"); + return ret; + } + + ret = jtag_libusb_bulk_read(device->usbdev, IN_EP, + (char *)device->reply_buffer + offset, + sent_chunk_size, ANGIE_USB_TIMEOUT_MS, &bytes_received); + if (ret != ERROR_OK) { + LOG_ERROR("Failed to read USB reply"); + return ret; + } + + if (sent_chunk_size == xfer_size && bytes_received == xfer_size) { + device->reply_buffer_len += xfer_size; + device->xfer_buffer_len -= xfer_size; + if (bytes_sent) + *bytes_sent += sent_chunk_size; + } else { + return ERROR_FAIL; + } + + return ERROR_OK; +} /** - * Opens the ANGIE device + * Flush Angie transfer buffer * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * Flush is done by chunks of 512 bytes to match hardware internal FIFOs. + * Then the read queue list is executed once the read buffer has been retrieved. + * + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_usb_open(struct angie *device) +static int angie_buffer_flush(struct angie *device) +{ + if (device->xfer_buffer_len == 0) + return ERROR_OK; + + int total_bytes_sent = 0; + device->reply_buffer_len = 0; + + do { + int sent_chunk_size; + size_t xfer_size = MIN(device->xfer_buffer_len, ANGIE_USB_BULK_SIZE); + int ret = angie_buffer_flush_chunk(device, xfer_size, + total_bytes_sent, &sent_chunk_size); + if (ret != ERROR_OK) + return ret; + total_bytes_sent += sent_chunk_size; + } while (device->xfer_buffer_len > 0); + + angie_read_queue_execute(&device->read_queue, device); + + return ERROR_OK; +} + +/** + * Check if transfer buffer has enough remaining space for a given size. + * If the buffer is not large enough, flush it. + * + * @param device: Angie device pointer + * @param size to check + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_flush_check(struct angie *device, size_t size) +{ + if (device->xfer_buffer_len + size >= ANGIE_XFER_BUFFER_TOTAL_SIZE) + return angie_buffer_flush(device); + return ERROR_OK; +} + +/** + * Append a single byte value to the transfer buffer + * + * @param device: Angie device pointer + * @param value to append + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_append_simple(struct angie *device, uint8_t value) { - struct libusb_device_handle *usb_device_handle; - const uint16_t vids[] = {ANGIE_VID, ANGIE_VID, ANGIE_VID, ANGIE_VID, ANGIE_VID, 0}; - const uint16_t pids[] = {ANGIE_PID, ANGIE_PID_2, ANGIE_PID_3, ANGIE_PID_4, ANGIE_PID_5, 0}; + if (device->xfer_buffer_len >= ANGIE_XFER_BUFFER_TOTAL_SIZE) { + int ret = angie_buffer_flush(device); + if (ret != ERROR_OK) + return ret; + } + device->xfer_buffer[device->xfer_buffer_len++] = value; + return ERROR_OK; +} - int ret = jtag_libusb_open(vids, pids, NULL, &usb_device_handle, NULL); +/** + * Append a bit-bang JTAG value to the transfer buffer. + * + * @param device: Angie device pointer + * @param tck value + * @param tms value + * @param tdi value + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_buffer_append(struct angie *device, int tck, int tms, int tdi) +{ + uint8_t val = (1 << NTRST_GPIO) | (1 << NSYSRST_GPIO); + if (tck) + val |= (1 << TCK_GPIO); + if (tms) + val |= (1 << TMS_GPIO); + if (tdi) + val |= (1 << TDI_GPIO); + + return angie_buffer_append_simple(device, val); +} +/** + * Open Angie USB interface + * + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_usb_open(struct angie *device) +{ + uint16_t avids[] = { + ANGIE_VID, + ANGIE_VID, + ANGIE_VID, + 0, + }; + uint16_t apids[] = { + ANGIE_NPROG_PID, + ANGIE_PROG_OOCD_PID, + ANGIE_PROG_NXB2_PID, + 0, + }; + struct libusb_device_handle *usb_dev; + + int ret = jtag_libusb_open(avids, apids, NULL, &usb_dev, NULL); if (ret != ERROR_OK) { - LOG_ERROR("Could not find and open ANGIE"); + LOG_ERROR("Failed to open ANGIE USB interface"); return ret; } - device->usb_device_handle = usb_device_handle; - device->type = ANGIE; + device->usbdev = usb_dev; return ERROR_OK; } @@ -276,80 +400,84 @@ static int angie_usb_open(struct angie *device) /** * Releases the ANGIE interface and closes the USB device handle. * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @return ERROR_OK on success, negative error code otherwise */ static int angie_usb_close(struct angie *device) { - if (device->usb_device_handle) { - if (libusb_release_interface(device->usb_device_handle, 0) != 0) { + int ret = ERROR_OK; + + if (device->usbdev) { + if (libusb_release_interface(device->usbdev, 0) != LIBUSB_SUCCESS) { LOG_ERROR("Could not release interface 0"); - return ERROR_FAIL; + ret = ERROR_FAIL; } - jtag_libusb_close(device->usb_device_handle); - device->usb_device_handle = NULL; + jtag_libusb_close(device->usbdev); + device->usbdev = NULL; } - return ERROR_OK; -} -/******************* ANGIE CPU (EZ-USB) specific functions ********************/ + return ret; +} /** * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset * or out of reset. * - * @param device pointer to struct angie identifying ANGIE driver instance. + * @param device: Angie device pointer * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ static int angie_cpu_reset(struct angie *device, char reset_bit) { - return jtag_libusb_control_transfer(device->usb_device_handle, - (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), - REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS, NULL); + return jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, + ANGIE_USB_TIMEOUT_MS, NULL); } /** - * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads - * the firmware image, resumes the microcontroller and re-enumerates - * USB devices. + * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller + * over the USB bus. * - * @param device pointer to struct angie identifying ANGIE driver instance. - * The usb_handle member will be modified during re-enumeration. - * @param filename path to the Intel HEX file containing the firmware image. - * @param delay_us the delay to wait for the device to re-enumerate. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param address: address of the firmware section + * @param data: pointer to the data to be sent + * @param size: size of the data + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_load_firmware_and_renumerate(struct angie *device, - const char *filename, uint32_t delay_us) +static int angie_write_firmware_section(struct angie *device, uint16_t address, + uint8_t *data, size_t size) { - int ret; + int bytes_remaining = size; - /* Basic process: After downloading the firmware, the ANGIE will disconnect - * itself and re-connect after a short amount of time so we have to close - * the handle and re-enumerate USB devices */ + // Send section data in chunks of up to 64 bytes to ANGIE + while (bytes_remaining > 0) { + int chunk_size; + int transferred; - ret = angie_load_firmware(device, filename); - if (ret != ERROR_OK) - return ret; + if (bytes_remaining > 64) + chunk_size = 64; + else + chunk_size = bytes_remaining; - ret = angie_usb_close(device); - if (ret != ERROR_OK) - return ret; + int ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + REQUEST_FIRMWARE_LOAD, address, FIRMWARE_ADDR, (char *)data, + chunk_size, ANGIE_USB_TIMEOUT_MS, &transferred); - usleep(delay_us); + if (ret != ERROR_OK) + return ret; - ret = angie_usb_open(device); - if (ret != ERROR_OK) - return ret; + if (transferred != chunk_size) { + // Abort if libusb sent less data than requested + return ERROR_FAIL; + } - ret = libusb_claim_interface(angie_handle->usb_device_handle, 0); - if (ret != LIBUSB_SUCCESS) - return ERROR_FAIL; + bytes_remaining -= chunk_size; + address += chunk_size; + data += chunk_size; + } return ERROR_OK; } @@ -358,18 +486,16 @@ static int angie_load_firmware_and_renumerate(struct angie *device, * Downloads a firmware image to the ANGIE's EZ-USB microcontroller * over the USB bus. * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param filename an absolute or relative path to the Intel HEX file + * @param device: Angie device pointer + * @param filename: an absolute or relative path to the Intel HEX file * containing the firmware image. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ static int angie_load_firmware(struct angie *device, const char *filename) { struct image angie_firmware_image; - int ret; - ret = angie_cpu_reset(device, CPU_RESET); + int ret = angie_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { LOG_ERROR("Could not halt ANGIE CPU"); return ret; @@ -384,12 +510,34 @@ static int angie_load_firmware(struct angie *device, const char *filename) return ret; } - /* Download all sections in the image to ANGIE */ + uint8_t *data = malloc(ANGIE_FW_SECTION_SIZE); + if (!data) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + // Download all sections in the image to ANGIE for (unsigned int i = 0; i < angie_firmware_image.num_sections; i++) { - ret = angie_write_firmware_section(device, &angie_firmware_image, i); + size_t size_read; + uint32_t size = angie_firmware_image.sections[i].size; + int addr = angie_firmware_image.sections[i].base_address; + + LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx32 ")", + i, addr, size); + + ret = image_read_section(&angie_firmware_image, i, 0, + size, data, &size_read); + if (ret != ERROR_OK) + goto exit; + if (size_read != size) { + ret = ERROR_FAIL; + goto exit; + } + + ret = angie_write_firmware_section(device, addr, data, size); if (ret != ERROR_OK) { LOG_ERROR("Could not write firmware section"); - return ret; + goto exit; } } @@ -398,9 +546,52 @@ static int angie_load_firmware(struct angie *device, const char *filename) ret = angie_cpu_reset(device, CPU_START); if (ret != ERROR_OK) { LOG_ERROR("Could not restart ANGIE CPU"); - return ret; + goto exit; } +exit: + free(data); + return ret; +} + +/** + * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads + * the firmware image, resumes the microcontroller and re-enumerates + * USB devices. + * + * @param device: Angie device pointer + * The usb_handle member will be modified during re-enumeration. + * @param filename: path to the Intel HEX file containing the firmware image. + * @param delay_us: the delay to wait for the device to re-enumerate. + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_load_firmware_and_renumerate(struct angie *device, + const char *filename, + uint32_t delay_us) +{ + /* + * Basic process: After downloading the firmware, the ANGIE will disconnect + * itself and re-connect after a short amount of time so we have to close + * the handle and re-enumerate USB devices. + */ + + int ret = angie_load_firmware(device, filename); + if (ret != ERROR_OK) + return ret; + + ret = angie_usb_close(device); + if (ret != ERROR_OK) + return ret; + + usleep(delay_us); + + ret = angie_usb_open(device); + if (ret != ERROR_OK) + return ret; + + if (libusb_claim_interface(angie_handle->usbdev, 0) != LIBUSB_SUCCESS) + return ERROR_FAIL; + return ERROR_OK; } @@ -408,1982 +599,766 @@ static int angie_load_firmware(struct angie *device, const char *filename) * Downloads a bitstream file to the ANGIE's FPGA through the EZ-USB microcontroller * over the USB bus. * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param filename an absolute or relative path to the Xilinx .bit file + * @param device: Angie device pointer + * @param filename: an absolute or relative path to the Xilinx .bit file * containing the bitstream data. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ static int angie_load_bitstream(struct angie *device, const char *filename) { - int ret, transferred; + int ret = ERROR_OK, transferred; const char *bitstream_file_path = filename; FILE *bitstream_file = NULL; char *bitstream_data = NULL; - size_t bitstream_size = 0; uint8_t gpifcnt[4]; - /* Open the bitstream file */ + // Open the bitstream file bitstream_file = fopen(bitstream_file_path, "rb"); if (!bitstream_file) { LOG_ERROR("Failed to open bitstream file: %s\n", bitstream_file_path); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto exit; } - /* Get the size of the bitstream file */ + // Get the size of the bitstream file fseek(bitstream_file, 0, SEEK_END); - bitstream_size = ftell(bitstream_file); + size_t bitstream_size = ftell(bitstream_file); fseek(bitstream_file, 0, SEEK_SET); - /* Allocate memory for the bitstream data */ + // Allocate memory for the bitstream data bitstream_data = malloc(bitstream_size); if (!bitstream_data) { LOG_ERROR("Failed to allocate memory for bitstream data."); - fclose(bitstream_file); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto exit; } - /* Read the bitstream data from the file */ + // Read the bitstream data from the file if (fread(bitstream_data, 1, bitstream_size, bitstream_file) != bitstream_size) { LOG_ERROR("Failed to read bitstream data."); - free(bitstream_data); - fclose(bitstream_file); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto exit; } + // CFG Open h_u32_to_be(gpifcnt, bitstream_size); - - /* CFGopen */ - ret = jtag_libusb_control_transfer(device->usb_device_handle, - 0x00, 0xB0, 0, 0, (char *)gpifcnt, 4, LIBUSB_TIMEOUT_MS, &transferred); + ret = jtag_libusb_control_transfer(device->usbdev, + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VR_CFGOPEN, 0, 0, (char *)gpifcnt, sizeof(gpifcnt), + ANGIE_USB_TIMEOUT_MS, &transferred); if (ret != ERROR_OK) { LOG_ERROR("Failed opencfg"); - /* Abort if libusb sent less data than requested */ - return ERROR_FAIL; + goto exit; } - /* Send the bitstream data to the microcontroller */ + // Send the bitstream data to the microcontroller int actual_length = 0; - ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x02, bitstream_data, bitstream_size, 1000, &actual_length); + ret = jtag_libusb_bulk_write(device->usbdev, OUT_EP, bitstream_data, + bitstream_size, ANGIE_USB_TIMEOUT_MS, &actual_length); if (ret != ERROR_OK) { LOG_ERROR("Failed to send bitstream data: %s", libusb_strerror(ret)); - free(bitstream_data); - fclose(bitstream_file); - return ERROR_FAIL; + goto exit; } LOG_INFO("Bitstream sent successfully."); - /* Clean up */ +exit: free(bitstream_data); - fclose(bitstream_file); + if (bitstream_file) + fclose(bitstream_file); - /* CFGclose */ - transferred = 0; - ret = jtag_libusb_control_transfer(device->usb_device_handle, - 0x00, 0xB1, 0, 0, NULL, 0, LIBUSB_TIMEOUT_MS, &transferred); - if (ret != ERROR_OK) { - LOG_ERROR("Failed cfgclose"); - /* Abort if libusb sent less data than requested */ - return ERROR_FAIL; - } - return ERROR_OK; + return ret; } /** - * Send an i2c write operation to dev-board components. + * Check if Angie firmware must be updated * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param i2c_data table of i2c data that we want to write to slave device. - * @param i2c_data_size the size of i2c data table. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @return true if update is needed, false otherwise */ -static int angie_i2c_write(struct angie *device, uint8_t *i2c_data, uint8_t i2c_data_size) +static bool angie_is_firmware_needed(struct angie *device) { - char i2c_data_buffer[i2c_data_size + 2]; - char buffer_received[1]; - int ret, transferred; - i2c_data_buffer[0] = 0; // write = 0 - i2c_data_buffer[1] = i2c_data_size - 1; // i2c_data count (without address) - - for (uint8_t i = 0; i < i2c_data_size; i++) - i2c_data_buffer[i + 2] = i2c_data[i]; - - // Send i2c packet to Dev-board and configure its clock source / - ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x06, i2c_data_buffer, - i2c_data_size + 2, 1000, &transferred); - if (ret != ERROR_OK) { - LOG_ERROR("Error in i2c clock gen configuration : ret ERROR"); - return ret; - } - if (transferred != i2c_data_size + 2) { - LOG_ERROR("Error in i2c clock gen configuration : bytes transferred"); - return ERROR_FAIL; - } + struct libusb_device_descriptor desc; - usleep(500); + // Get String Descriptor to determine if firmware needs to be loaded + int ret = libusb_get_device_descriptor(libusb_get_device(angie_handle->usbdev), + &desc); + if (ret != LIBUSB_SUCCESS) + // Could not get descriptor -> Unconfigured or original Keil firmware + return true; + else if (desc.idProduct != ANGIE_PROG_OOCD_PID) + return true; - // Receive packet from ANGIE / - ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x88, buffer_received, 1, 1000, &transferred); - if (ret != ERROR_OK) { - LOG_ERROR("Error in i2c clock gen configuration : ret ERROR"); - return ret; + return false; +} + +/** + * Set TAP end state + * + * @param state + */ +static void angie_set_end_state(enum tap_state state) +{ + if (tap_is_state_stable(state)) { + tap_set_end_state(state); + } else { + LOG_ERROR("BUG: %i is not a valid end state", state); + exit(-1); } - return ERROR_OK; } /** - * Configure dev-board gpio extender modules by configuring their - * register 3 and register 1 responsible for IO directions and values. + * Move TAP to given state * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param i2c_adr i2c address of the gpio extender. - * @param cfg_value IOs configuration to be written in register Number 3. - * @param value the IOs value to be written in register Number 1. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param skip: number of state to skip during move + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_io_extender_config(struct angie *device, uint8_t i2c_adr, uint8_t cfg_value) +static int angie_state_move(struct angie *device, int skip) { - uint8_t ioconfig[3] = {i2c_adr, 3, cfg_value}; - int ret = angie_i2c_write(device, ioconfig, 3); + int ret; + int tms = 0; + uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + // tms_scan has 8 bits that we bitbang one by one + for (int i = skip; i < tms_count; i++) { + tms = (tms_scan >> i) & 1; + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; + } + ret = angie_buffer_append(device, 0, tms, 0); if (ret != ERROR_OK) return ret; - usleep(500); - return ret; + tap_set_state(tap_get_end_state()); + + return ERROR_OK; } /** - * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller - * over the USB bus. + * Return JTAG SCAN command size in bytes * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param firmware_image pointer to the firmware image that contains the section - * which should be sent to the ANGIE's EZ-USB microcontroller. - * @param section_index index of the section within the firmware image. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return size of command in the transfer buffer in bytes */ -static int angie_write_firmware_section(struct angie *device, - struct image *firmware_image, int section_index) +static int angie_jtag_scan_size(struct angie *device, + const struct scan_command *cmd) { - int addr, bytes_remaining, chunk_size; - uint8_t data[SECTION_BUFFERSIZE]; - uint8_t *data_ptr = data; - uint16_t size; - size_t size_read; - int ret, transferred; + int cmd_size = 0; + int count = 0; - size = (uint16_t)firmware_image->sections[section_index].size; - addr = (uint16_t)firmware_image->sections[section_index].base_address; + // move to TAP_IRSHIFT or TAP_DRSHIFT state + if (cmd->ir_scan) + count = tap_get_tms_path_len(tap_get_state(), TAP_IRSHIFT); + else + count = tap_get_tms_path_len(tap_get_state(), TAP_DRSHIFT); + cmd_size += count * 2 + 1; + + // add scan size + cmd_size += jtag_scan_size(cmd) * 2; + + /* + * move to cmd specified end state + * Also, see below function + * we *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + if (cmd->ir_scan) + count = tap_get_tms_path_len(TAP_IRSHIFT, cmd->end_state) - 1; + else + count = tap_get_tms_path_len(TAP_DRSHIFT, cmd->end_state) - 1; + cmd_size += count * 2 + 1; - LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04" PRIx16 ")", section_index, addr, - size); + return cmd_size; +} - /* Copy section contents to local buffer */ - ret = image_read_section(firmware_image, section_index, 0, size, data, - &size_read); +/** + * Execute JTAG SCAN command + * + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_jtag_execute_scan(struct angie *device, + const struct scan_command *cmd) +{ + uint8_t *buffer = NULL; + LOG_DEBUG_IO("SCAN: size=%d %s scan end in %s", jtag_scan_size(cmd), + (cmd->ir_scan) ? "IR" : "DR", tap_state_name(cmd->end_state)); + if (cmd->ir_scan) { + if (tap_get_state() != TAP_IRSHIFT) + angie_set_end_state(TAP_IRSHIFT); + } else { + if (tap_get_state() != TAP_DRSHIFT) + angie_set_end_state(TAP_DRSHIFT); + } + int ret = angie_state_move(device, 0); if (ret != ERROR_OK) return ret; - if (size_read != size) - return ERROR_FAIL; + angie_set_end_state(cmd->end_state); + + // Execute scan + int scan_size = jtag_build_buffer(cmd, &buffer); + enum scan_type type = jtag_scan_type(cmd); + + // starting byte index + int start_offset = device->xfer_buffer_len; + + // iterate over each bit in all scan data + int tms = 0; + int tdi = 0; + for (int i = 0; i < scan_size; i++) { + // calculate tms + // if we finish shifting tdi bits : '1' , else '0' + tms = (i == scan_size - 1) ? 1 : 0; + // calculate byte index + int bytec = i / 8; + // calculate bit mask: isolate the specific bit in corresponding byte + int bcval = 1 << (i % 8); + // if type is not SCAN_IN (not just reading data) + // and the bit masked is '1' then tdi = '1' + tdi = 0; + if (type != SCAN_IN && (buffer[bytec] & bcval)) + tdi = 1; + // write tdi and tms twice in tck=0 and tck=1 + ret = angie_buffer_append(device, 0, tms, tdi); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, tdi); + if (ret != ERROR_OK) + return ret; + } - bytes_remaining = size; + angie_set_end_state(cmd->end_state); + if (tap_get_state() != tap_get_end_state()) { + /* + * We *KNOW* the above loop transitioned out of + * the shift state, so we skip the first state + * and move directly to the end state. + */ + ret = angie_state_move(device, 1); + if (ret != ERROR_OK) + return ret; + } - /* Send section data in chunks of up to 64 bytes to ANGIE */ - while (bytes_remaining > 0) { - if (bytes_remaining > 64) - chunk_size = 64; - else - chunk_size = bytes_remaining; - - ret = jtag_libusb_control_transfer(device->usb_device_handle, - (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), - REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (char *)data_ptr, - chunk_size, LIBUSB_TIMEOUT_MS, &transferred); - - if (ret != ERROR_OK) - return ret; - - if (transferred != chunk_size) { - /* Abort if libusb sent less data than requested */ + if (jtag_scan_type(cmd) != SCAN_OUT) { + // queue read back buffer for further processing + struct read_queue_entry *entry = malloc(sizeof(*entry)); + if (!entry) { + LOG_ERROR("Out of memory"); + free(buffer); return ERROR_FAIL; } - bytes_remaining -= chunk_size; - addr += chunk_size; - data_ptr += chunk_size; - } - - return ERROR_OK; -} - -/************************** Generic helper functions **************************/ - -/** - * Print state of interesting signals via LOG_INFO(). - * - * @param input_signals input signal states as returned by CMD_GET_SIGNALS - * @param output_signals output signal states as returned by CMD_GET_SIGNALS - */ -static void angie_dump_signal_states(uint8_t input_signals, uint8_t output_signals) -{ - LOG_INFO("ANGIE signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i " - "SRST: %i", - (output_signals & SIGNAL_TDI ? 1 : 0), - (input_signals & SIGNAL_TDO ? 1 : 0), - (output_signals & SIGNAL_TMS ? 1 : 0), - (output_signals & SIGNAL_TCK ? 1 : 0), - (output_signals & SIGNAL_TRST ? 1 : 0), - (output_signals & SIGNAL_SRST ? 1 : 0)); -} - -/**************** ANGIE command generation helper functions ***************/ - -/** - * Allocate and initialize space in memory for ANGIE command payload. - * - * @param angie_cmd pointer to command whose payload should be allocated. - * @param size the amount of memory to allocate (bytes). - * @param direction which payload to allocate. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, - enum angie_payload_direction direction) -{ - uint8_t *payload; - - payload = calloc(size, sizeof(uint8_t)); - - if (!payload) { - LOG_ERROR("Could not allocate ANGIE command payload: out of memory"); - return ERROR_FAIL; - } - - switch (direction) { - case PAYLOAD_DIRECTION_OUT: - if (angie_cmd->payload_out) { - LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); - free(payload); - return ERROR_FAIL; - } - angie_cmd->payload_out = payload; - angie_cmd->payload_out_size = size; - break; - case PAYLOAD_DIRECTION_IN: - if (angie_cmd->payload_in_start) { - LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); - free(payload); - return ERROR_FAIL; - } - - angie_cmd->payload_in_start = payload; - angie_cmd->payload_in = payload; - angie_cmd->payload_in_size = size; - - /* By default, free payload_in_start in angie_clear_queue(). Commands - * that do not want this behavior (e. g. split scans) must turn it off - * separately! */ - angie_cmd->free_payload_in_start = true; - - break; - } - - return ERROR_OK; -} - -/****************** ANGIE command queue helper functions ******************/ - -/** - * Get the current number of bytes in the queue, including command IDs. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param direction the transfer direction for which to get byte count. - * @return the number of bytes currently stored in the queue for the specified - * direction. - */ -static int angie_get_queue_size(struct angie *device, - enum angie_payload_direction direction) -{ - struct angie_cmd *current = device->queue_start; - int sum = 0; - - while (current) { - switch (direction) { - case PAYLOAD_DIRECTION_OUT: - sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ - break; - case PAYLOAD_DIRECTION_IN: - sum += current->payload_in_size; - break; - } - - current = current->next; - } - - return sum; -} - -/** - * Clear the ANGIE command queue. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - */ -static void angie_clear_queue(struct angie *device) -{ - struct angie_cmd *current = device->queue_start; - struct angie_cmd *next = NULL; - - while (current) { - /* Save pointer to next element */ - next = current->next; - - /* Free payloads: OUT payload can be freed immediately */ - free(current->payload_out); - current->payload_out = NULL; - - /* IN payload MUST be freed ONLY if no other commands use the - * payload_in_start buffer */ - if (current->free_payload_in_start) { - free(current->payload_in_start); - current->payload_in_start = NULL; - current->payload_in = NULL; - } - - /* Free queue element */ - free(current); - - /* Proceed with next element */ - current = next; - } - - device->commands_in_queue = 0; - device->queue_start = NULL; - device->queue_end = NULL; -} - -/** - * Add a command to the ANGIE command queue. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param angie_cmd pointer to command that shall be appended to the ANGIE - * command queue. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd) -{ - int newsize_out, newsize_in; - int ret = ERROR_OK; - - newsize_out = angie_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 - + angie_cmd->payload_out_size; - - newsize_in = angie_get_queue_size(device, PAYLOAD_DIRECTION_IN) - + angie_cmd->payload_in_size; - - /* Check if the current command can be appended to the queue */ - if (newsize_out > 64 || newsize_in > 64) { - /* New command does not fit. Execute all commands in queue before starting - * new queue with the current command as first entry. */ - ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); - - if (ret == ERROR_OK) - ret = angie_post_process_queue(device); - - if (ret == ERROR_OK) - angie_clear_queue(device); - } - - if (!device->queue_start) { - /* Queue was empty */ - device->commands_in_queue = 1; - - device->queue_start = angie_cmd; - device->queue_end = angie_cmd; - } else { - /* There are already commands in the queue */ - device->commands_in_queue++; - - device->queue_end->next = angie_cmd; - device->queue_end = angie_cmd; - } - - if (ret != ERROR_OK) - angie_clear_queue(device); - - return ret; -} - -/** - * Sends all queued ANGIE commands to the ANGIE for execution. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param timeout_ms - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_execute_queued_commands(struct angie *device, int timeout_ms) -{ - struct angie_cmd *current; - int ret, i, index_out, index_in, count_out, count_in, transferred; - uint8_t buffer[64]; - - if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) - angie_dump_queue(device); - - index_out = 0; - count_out = 0; - count_in = 0; - - for (current = device->queue_start; current; current = current->next) { - /* Add command to packet */ - buffer[index_out] = current->id; - index_out++; - count_out++; - - for (i = 0; i < current->payload_out_size; i++) - buffer[index_out + i] = current->payload_out[i]; - index_out += current->payload_out_size; - count_in += current->payload_in_size; - count_out += current->payload_out_size; - } - - /* Send packet to ANGIE */ - ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_out, - (char *)buffer, count_out, timeout_ms, &transferred); - if (ret != ERROR_OK) { - LOG_ERROR("Libusb bulk write queued commands failed."); - return ret; - } - if (transferred != count_out) { - LOG_ERROR("Libusb bulk write queued commands failed: transferred byte count"); - return ERROR_FAIL; - } - - /* Wait for response if commands contain IN payload data */ - if (count_in > 0) { - ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_in, - (char *)buffer, count_in, timeout_ms, &transferred); - if (ret != ERROR_OK) { - LOG_ERROR("Libusb bulk write input payload data failed"); - return ret; - } - if (transferred != count_in) { - LOG_ERROR("Libusb bulk write input payload data failed: transferred byte count"); - return ERROR_FAIL; - } - - /* Write back IN payload data */ - index_in = 0; - for (current = device->queue_start; current; current = current->next) { - for (i = 0; i < current->payload_in_size; i++) { - current->payload_in[i] = buffer[index_in]; - index_in++; - } - } - } - return ERROR_OK; -} - -/** - * Convert an ANGIE command ID (\a id) to a human-readable string. - * - * @param id the ANGIE command ID. - * @return the corresponding human-readable string. - */ -static const char *angie_cmd_id_string(uint8_t id) -{ - switch (id) { - case CMD_SCAN_IN: - return "CMD_SCAN_IN"; - case CMD_SLOW_SCAN_IN: - return "CMD_SLOW_SCAN_IN"; - case CMD_SCAN_OUT: - return "CMD_SCAN_OUT"; - case CMD_SLOW_SCAN_OUT: - return "CMD_SLOW_SCAN_OUT"; - case CMD_SCAN_IO: - return "CMD_SCAN_IO"; - case CMD_SLOW_SCAN_IO: - return "CMD_SLOW_SCAN_IO"; - case CMD_CLOCK_TMS: - return "CMD_CLOCK_TMS"; - case CMD_SLOW_CLOCK_TMS: - return "CMD_SLOW_CLOCK_TMS"; - case CMD_CLOCK_TCK: - return "CMD_CLOCK_TCK"; - case CMD_SLOW_CLOCK_TCK: - return "CMD_SLOW_CLOCK_TCK"; - case CMD_SLEEP_US: - return "CMD_SLEEP_US"; - case CMD_SLEEP_MS: - return "CMD_SLEEP_MS"; - case CMD_GET_SIGNALS: - return "CMD_GET_SIGNALS"; - case CMD_SET_SIGNALS: - return "CMD_SET_SIGNALS"; - case CMD_CONFIGURE_TCK_FREQ: - return "CMD_CONFIGURE_TCK_FREQ"; - case CMD_SET_LEDS: - return "CMD_SET_LEDS"; - case CMD_TEST: - return "CMD_TEST"; - default: - return "CMD_UNKNOWN"; - } -} - -/** - * Print one ANGIE command to stdout. - * - * @param angie_cmd pointer to ANGIE command. - */ -static void angie_dump_command(struct angie_cmd *angie_cmd) -{ - char hex[64 * 3]; - for (int i = 0; i < angie_cmd->payload_out_size; i++) - sprintf(hex + 3 * i, "%02" PRIX8 " ", angie_cmd->payload_out[i]); - - hex[3 * angie_cmd->payload_out_size - 1] = 0; - LOG_DEBUG_IO(" %-22s | OUT size = %" PRIi8 ", bytes = %s", - angie_cmd_id_string(angie_cmd->id), angie_cmd->payload_out_size, hex); - - LOG_DEBUG_IO("\n | IN size = %" PRIi8 "\n", angie_cmd->payload_in_size); -} - -/** - * Print the ANGIE command queue to stdout. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - */ -static void angie_dump_queue(struct angie *device) -{ - struct angie_cmd *current; - - LOG_DEBUG_IO("ANGIE command queue:\n"); - - for (current = device->queue_start; current; current = current->next) - angie_dump_command(current); -} - -/** - * Perform JTAG scan - * - * Creates and appends a JTAG scan command to the ANGIE command queue. - * A JTAG scan consists of three steps: - * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). - * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. - * - Move to the desired end state. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). - * @param scan_size_bits number of bits to shift into the JTAG chain. - * @param tdi pointer to array containing TDI data. - * @param tdo_start pointer to first element of array where TDO data shall be - * stored. See #angie_cmd for details. - * @param tdo pointer to array where TDO data shall be stored - * @param tms_count_start number of TMS state transitions to perform BEFORE - * shifting data into the JTAG chain. - * @param tms_sequence_start sequence of TMS state transitions that will be - * performed BEFORE shifting data into the JTAG chain. - * @param tms_count_end number of TMS state transitions to perform AFTER - * shifting data into the JTAG chain. - * @param tms_sequence_end sequence of TMS state transitions that will be - * performed AFTER shifting data into the JTAG chain. - * @param origin pointer to OpenOCD command that generated this scan command. - * @param postprocess whether this command needs to be post-processed after - * execution. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_scan_cmd(struct angie *device, enum scan_type scan_type, - int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, - uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, - uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret, i, scan_size_bytes; - uint8_t bits_last_byte; - - if (!cmd) - return ERROR_FAIL; - - /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, - * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ - if (scan_size_bits > (58 * 8)) { - LOG_ERROR("BUG: Tried to create CMD_SCAN_IO ANGIE command with too" - " large payload"); - free(cmd); - return ERROR_FAIL; - } - - scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); - - bits_last_byte = scan_size_bits % 8; - if (bits_last_byte == 0) - bits_last_byte = 8; - - /* Allocate out_payload depending on scan type */ - switch (scan_type) { - case SCAN_IN: - if (device->delay_scan_in < 0) - cmd->id = CMD_SCAN_IN; - else - cmd->id = CMD_SLOW_SCAN_IN; - ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_IN); - break; - case SCAN_OUT: - if (device->delay_scan_out < 0) - cmd->id = CMD_SCAN_OUT; - else - cmd->id = CMD_SLOW_SCAN_OUT; - ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); - break; - case SCAN_IO: - if (device->delay_scan_io < 0) - cmd->id = CMD_SCAN_IO; - else - cmd->id = CMD_SLOW_SCAN_IO; - ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); - break; - default: - LOG_ERROR("BUG: 'append scan cmd' encountered an unknown scan type"); - ret = ERROR_FAIL; - break; - } - - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - /* Build payload_out that is common to all scan types */ - cmd->payload_out[0] = scan_size_bytes & 0xFF; - cmd->payload_out[1] = bits_last_byte & 0xFF; - cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); - cmd->payload_out[3] = tms_sequence_start; - cmd->payload_out[4] = tms_sequence_end; - - /* Setup payload_out for types with OUT transfer */ - if (scan_type == SCAN_OUT || scan_type == SCAN_IO) { - for (i = 0; i < scan_size_bytes; i++) - cmd->payload_out[i + 5] = tdi[i]; - } - - /* Setup payload_in pointers for types with IN transfer */ - if (scan_type == SCAN_IN || scan_type == SCAN_IO) { - cmd->payload_in_start = tdo_start; - cmd->payload_in = tdo; - cmd->payload_in_size = scan_size_bytes; - } - - cmd->needs_postprocessing = postprocess; - cmd->cmd_origin = origin; - - /* For scan commands, we free payload_in_start only when the command is - * the last in a series of split commands or a stand-alone command */ - cmd->free_payload_in_start = postprocess; - - return angie_append_queue(device, cmd); -} - -/** - * Perform TAP state transitions - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param count defines the number of TCK clock cycles generated (up to 8). - * @param sequence defines the TMS pin levels for each state transition. The - * Least-Significant Bit is read first. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, - uint8_t sequence) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - if (device->delay_clock_tms < 0) - cmd->id = CMD_CLOCK_TMS; - else - cmd->id = CMD_SLOW_CLOCK_TMS; - - /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ - ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - cmd->payload_out[0] = count; - cmd->payload_out[1] = sequence; - - return angie_append_queue(device, cmd); -} - -/** - * Generate a defined amount of TCK clock cycles - * - * All other JTAG signals are left unchanged. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param count the number of TCK clock cycles to generate. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - if (device->delay_clock_tck < 0) - cmd->id = CMD_CLOCK_TCK; - else - cmd->id = CMD_SLOW_CLOCK_TCK; - - /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ - ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - cmd->payload_out[0] = count & 0xff; - cmd->payload_out[1] = (count >> 8) & 0xff; - - return angie_append_queue(device, cmd); -} - -/** - * Read JTAG signals. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_get_signals_cmd(struct angie *device) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - cmd->id = CMD_GET_SIGNALS; - cmd->needs_postprocessing = true; - - /* CMD_GET_SIGNALS has two IN payload bytes */ - ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); - - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - return angie_append_queue(device, cmd); -} - -/** - * Arbitrarily set JTAG output signals. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param low defines which signals will be de-asserted. Each bit corresponds - * to a JTAG signal: - * - SIGNAL_TDI - * - SIGNAL_TMS - * - SIGNAL_TCK - * - SIGNAL_TRST - * - SIGNAL_BRKIN - * - SIGNAL_RESET - * - SIGNAL_OCDSE - * @param high defines which signals will be asserted. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, - uint8_t high) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - cmd->id = CMD_SET_SIGNALS; - - /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ - ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); - - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - cmd->payload_out[0] = low; - cmd->payload_out[1] = high; - - return angie_append_queue(device, cmd); -} - -/** - * Sleep for a pre-defined number of microseconds - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param us the number microseconds to sleep. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_sleep_cmd(struct angie *device, uint32_t us) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - cmd->id = CMD_SLEEP_US; - - /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ - ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); - - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - cmd->payload_out[0] = us & 0x00ff; - cmd->payload_out[1] = (us >> 8) & 0x00ff; - - return angie_append_queue(device, cmd); -} - -/** - * Set TCK delay counters - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. - * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. - * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. - * @param delay_tck delay count top value in jtag_clock_tck() function. - * @param delay_tms delay count top value in jtag_slow_clock_tms() function. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_configure_tck_cmd(struct angie *device, int delay_scan_in, - int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - cmd->id = CMD_CONFIGURE_TCK_FREQ; - - /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero - * IN payload bytes */ - ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - if (delay_scan_in < 0) - cmd->payload_out[0] = 0; - else - cmd->payload_out[0] = (uint8_t)delay_scan_in; - - if (delay_scan_out < 0) - cmd->payload_out[1] = 0; - else - cmd->payload_out[1] = (uint8_t)delay_scan_out; - - if (delay_scan_io < 0) - cmd->payload_out[2] = 0; - else - cmd->payload_out[2] = (uint8_t)delay_scan_io; - - if (delay_tck < 0) - cmd->payload_out[3] = 0; - else - cmd->payload_out[3] = (uint8_t)delay_tck; - - if (delay_tms < 0) - cmd->payload_out[4] = 0; - else - cmd->payload_out[4] = (uint8_t)delay_tms; - - return angie_append_queue(device, cmd); -} - -/** - * Test command. Used to check if the ANGIE device is ready to accept new - * commands. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_append_test_cmd(struct angie *device) -{ - struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); - int ret; - - if (!cmd) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - - cmd->id = CMD_TEST; - - /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ - ret = angie_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); - if (ret != ERROR_OK) { - free(cmd); - return ret; - } - - cmd->payload_out[0] = 0xAA; - - return angie_append_queue(device, cmd); -} - -/****************** ANGIE TCK frequency helper functions ******************/ - -/** - * Calculate delay values for a given TCK frequency. - * - * The ANGIE firmware uses five different speed values for different - * commands. These speed values are calculated in these functions. - * - * The five different commands which support variable TCK frequency are - * implemented twice in the firmware: - * 1. Maximum possible frequency without any artificial delay - * 2. Variable frequency with artificial linear delay loop - * - * To set the ANGIE to maximum frequency, it is only necessary to use the - * corresponding command IDs. To set the ANGIE to a lower frequency, the - * delay loop top values have to be calculated first. Then, a - * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ANGIE device. - * - * The delay values are described by linear equations: - * t = k * x + d - * (t = period, k = constant, x = delay value, d = constant) - * - * Thus, the delay can be calculated as in the following equation: - * x = (t - d) / k - * - * The constants in these equations have been determined and validated by - * measuring the frequency resulting from different delay values. - * - * @param type for which command to calculate the delay value. - * @param f TCK frequency for which to calculate the delay value in Hz. - * @param delay where to store resulting delay value. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay) -{ - float t_us, x, x_ceil; - - /* Calculate period of requested TCK frequency */ - t_us = 1000000.0 / f; - - switch (type) { - case DELAY_CLOCK_TCK: - x = (t_us - 6.0) / 4; - break; - case DELAY_CLOCK_TMS: - x = (t_us - 8.5) / 4; - break; - case DELAY_SCAN_IN: - x = (t_us - 8.8308) / 4; - break; - case DELAY_SCAN_OUT: - x = (t_us - 10.527) / 4; - break; - case DELAY_SCAN_IO: - x = (t_us - 13.132) / 4; - break; - default: - return ERROR_FAIL; - break; - } - - /* Check if the delay value is negative. This happens when a frequency is - * requested that is too high for the delay loop implementation. In this - * case, set delay value to zero. */ - if (x < 0) - x = 0; - - /* We need to convert the exact delay value to an integer. Therefore, we - * round the exact value UP to ensure that the resulting frequency is NOT - * higher than the requested frequency. */ - x_ceil = ceilf(x); - - /* Check if the value is within limits */ - if (x_ceil > 255) - return ERROR_FAIL; - - *delay = (int)x_ceil; - - return ERROR_OK; -} - -/** - * Calculate frequency for a given delay value. - * - * Similar to the #angie_calculate_delay function, this function calculates the - * TCK frequency for a given delay value by using linear equations of the form: - * t = k * x + d - * (t = period, k = constant, x = delay value, d = constant) - * - * @param type for which command to calculate the delay value. - * @param delay value for which to calculate the resulting TCK frequency. - * @return the resulting TCK frequency - */ -static long angie_calculate_frequency(enum angie_delay_type type, int delay) -{ - float t_us, f_float; - - if (delay > 255) - return 0; - - switch (type) { - case DELAY_CLOCK_TCK: - if (delay < 0) - t_us = 2.666; - else - t_us = (4.0 * delay) + 6.0; - break; - case DELAY_CLOCK_TMS: - if (delay < 0) - t_us = 5.666; - else - t_us = (4.0 * delay) + 8.5; - break; - case DELAY_SCAN_IN: - if (delay < 0) - t_us = 5.5; - else - t_us = (4.0 * delay) + 8.8308; - break; - case DELAY_SCAN_OUT: - if (delay < 0) - t_us = 7.0; - else - t_us = (4.0 * delay) + 10.527; - break; - case DELAY_SCAN_IO: - if (delay < 0) - t_us = 9.926; - else - t_us = (4.0 * delay) + 13.132; - break; - default: - return 0; - } - - f_float = 1000000.0 / t_us; - return roundf(f_float); -} - -/******************* Interface between ANGIE and OpenOCD ******************/ - -/** - * Sets the end state follower (see interface.h) if \a endstate is a stable - * state. - * - * @param endstate the state the end state follower should be set to. - */ -static void angie_set_end_state(enum tap_state endstate) -{ - if (tap_is_state_stable(endstate)) - tap_set_end_state(endstate); - else - LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); + entry->reply_buffer_offset = start_offset; + entry->cmd = cmd; + entry->buffer = buffer; + angie_read_queue_add(&device->read_queue, entry); + } else { + // built buffer won't be of later use + free(buffer); + } + + return ERROR_OK; } /** - * Move from the current TAP state to the current TAP end state. + * Return JTAG RUNTEST command size in bytes * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: RUNTEST command + * @return size of command in the transfer buffer in bytes */ -static int angie_queue_statemove(struct angie *device) +static int angie_jtag_runtest_size(struct angie *device, + const struct runtest_command *cmd) { - uint8_t tms_sequence, tms_count; - int ret; - - if (tap_get_state() == tap_get_end_state()) { - /* Do nothing if we are already there */ - return ERROR_OK; - } + int cmd_size = 0; - tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + if (tap_get_state() != TAP_IDLE) + cmd_size += tap_get_tms_path_len(tap_get_state(), TAP_IDLE) * 2 + 1; + cmd_size += cmd->num_cycles * 2 + 1; + if (tap_get_end_state() != TAP_IDLE) + cmd_size += tap_get_tms_path_len(TAP_IDLE, tap_get_end_state()) * 2 + 1; - ret = angie_append_clock_tms_cmd(device, tms_count, tms_sequence); - - if (ret == ERROR_OK) - tap_set_state(tap_get_end_state()); - - return ret; + return cmd_size; } /** - * Perform a scan operation on a JTAG register. + * Execute JTAG RUNTEST command * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: SCAN command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_scan(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_runtest(struct angie *device, + const struct runtest_command *cmd) { - uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; - uint32_t scans_max_payload, bytecount; - uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; - uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; - - uint8_t first_tms_count, first_tms_sequence; - uint8_t last_tms_count, last_tms_sequence; - - uint8_t tms_count_pause, tms_sequence_pause; - uint8_t tms_count_resume, tms_sequence_resume; - - uint8_t tms_count_start, tms_sequence_start; - uint8_t tms_count_end, tms_sequence_end; - - enum scan_type type; int ret; + enum tap_state saved_end_state = tap_get_end_state(); - /* Determine scan size */ - scan_size_bits = jtag_scan_size(cmd->cmd.scan); - scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); - - /* Determine scan type (IN/OUT/IO) */ - type = jtag_scan_type(cmd->cmd.scan); + LOG_DEBUG_IO("RUNTEST: %d cycles", cmd->num_cycles); - /* Determine number of scan commands with maximum payload */ - scans_max_payload = scan_size_bytes / 58; - - /* Determine size of last shift command */ - bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); - - /* Allocate TDO buffer if required */ - if (type == SCAN_IN || type == SCAN_IO) { - tdo_buffer_start = calloc(scan_size_bytes, sizeof(uint8_t)); - - if (!tdo_buffer_start) - return ERROR_FAIL; - - tdo_buffer = tdo_buffer_start; - } - - /* Fill TDI buffer if required */ - if (type == SCAN_OUT || type == SCAN_IO) { - jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); - tdi_buffer = tdi_buffer_start; + // only do a state_move when we're not already in IDLE + if (tap_get_state() != TAP_IDLE) { + angie_set_end_state(TAP_IDLE); + ret = angie_state_move(device, 0); + if (ret != ERROR_OK) + return ret; } - /* Get TAP state transitions */ - if (cmd->cmd.scan->ir_scan) { - angie_set_end_state(TAP_IRSHIFT); - first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - - tap_set_state(TAP_IRSHIFT); - tap_set_end_state(cmd->cmd.scan->end_state); - last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - - /* TAP state transitions for split scans */ - tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); - tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); - tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); - tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); - } else { - angie_set_end_state(TAP_DRSHIFT); - first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - - tap_set_state(TAP_DRSHIFT); - tap_set_end_state(cmd->cmd.scan->end_state); - last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); - last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); - - /* TAP state transitions for split scans */ - tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); - tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); - tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); - tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); + // execute num_cycles + for (unsigned int i = 0; i < cmd->num_cycles; i++) { + ret = angie_buffer_append(device, 0, 0, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, 0, 0); + if (ret != ERROR_OK) + return ret; } + ret = angie_buffer_append(device, 0, 0, 0); + if (ret != ERROR_OK) + return ret; - /* Generate scan commands */ - bytecount = scan_size_bytes; - while (bytecount > 0) { - if (bytecount == scan_size_bytes) { - /* This is the first scan */ - tms_count_start = first_tms_count; - tms_sequence_start = first_tms_sequence; - } else { - /* Resume from previous scan */ - tms_count_start = tms_count_resume; - tms_sequence_start = tms_sequence_resume; - } - - if (bytecount > 58) { /* Full scan, at least one scan will follow */ - tms_count_end = tms_count_pause; - tms_sequence_end = tms_sequence_pause; - - ret = angie_append_scan_cmd(device, - type, - 58 * 8, - tdi_buffer, - tdo_buffer_start, - tdo_buffer, - tms_count_start, - tms_sequence_start, - tms_count_end, - tms_sequence_end, - cmd, - false); - - bytecount -= 58; - - /* Update TDI and TDO buffer pointers */ - if (tdi_buffer_start) - tdi_buffer += 58; - if (tdo_buffer_start) - tdo_buffer += 58; - } else if (bytecount == 58) { /* Full scan, no further scans */ - tms_count_end = last_tms_count; - tms_sequence_end = last_tms_sequence; - - ret = angie_append_scan_cmd(device, - type, - 58 * 8, - tdi_buffer, - tdo_buffer_start, - tdo_buffer, - tms_count_start, - tms_sequence_start, - tms_count_end, - tms_sequence_end, - cmd, - true); - - bytecount = 0; - } else {/* Scan with less than maximum payload, no further scans */ - tms_count_end = last_tms_count; - tms_sequence_end = last_tms_sequence; - - ret = angie_append_scan_cmd(device, - type, - bits_last_scan, - tdi_buffer, - tdo_buffer_start, - tdo_buffer, - tms_count_start, - tms_sequence_start, - tms_count_end, - tms_sequence_end, - cmd, - true); - - bytecount = 0; - } - - if (ret != ERROR_OK) { - free(tdi_buffer_start); - free(tdo_buffer_start); + // finish in end_state + angie_set_end_state(saved_end_state); + if (tap_get_state() != tap_get_end_state()) { + ret = angie_state_move(device, 0); + if (ret != ERROR_OK) return ret; - } } - free(tdi_buffer_start); - - /* Set current state to the end state requested by the command */ - tap_set_state(cmd->cmd.scan->end_state); - return ERROR_OK; } /** - * Move the TAP into the Test Logic Reset state. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd) -{ - int ret = angie_append_clock_tms_cmd(device, 5, 0xff); - - if (ret == ERROR_OK) - tap_set_state(TAP_RESET); - - return ret; -} - -/** - * Run Test. + * Execute JTAG TMS command + * Clock a bunch of TMS transitions, to change the JTAG + * state machine. * - * Generate TCK clock cycles while remaining - * in the Run-Test/Idle state. - * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: TMS command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_tms(struct angie *device, + const struct tms_command *cmd) { - int ret; + unsigned int num_bits = cmd->num_bits; + const uint8_t *bits = cmd->bits; - /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ - if (tap_get_state() != TAP_IDLE) { - angie_set_end_state(TAP_IDLE); - angie_queue_statemove(device); - } - - /* Generate the clock cycles */ - ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); - if (ret != ERROR_OK) - return ret; + LOG_DEBUG_IO("TMS: %d bits", num_bits); - /* Move to end state specified in command */ - if (cmd->cmd.runtest->end_state != tap_get_state()) { - tap_set_end_state(cmd->cmd.runtest->end_state); - angie_queue_statemove(device); + int tms = 0; + for (unsigned int i = 0; i < num_bits; i++) { + tms = ((bits[i / 8] >> (i % 8)) & 1); + int ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; } - return ERROR_OK; + return angie_buffer_append(device, 0, tms, 0); } /** - * Execute a JTAG_RESET command + * Execute JTAG RESET command + * Control /TRST and /SYSRST pins. + * Perform immediate bitbang transaction. * - * @param device - * @param trst indicate if trst signal is activated. - * @param srst indicate if srst signal is activated. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: RESET command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_reset(int trst, int srst) +static int angie_jtag_execute_reset(struct angie *device, + const struct reset_command *cmd) { - struct angie *device = angie_handle; - uint8_t low = 0, high = 0; + LOG_DEBUG_IO("RESET: trst %i srst %i", cmd->trst, cmd->srst); - if (trst) { + uint8_t out_value = (1 << NTRST_GPIO) | (1 << NSYSRST_GPIO); + if (cmd->trst == 1 || + (cmd->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); - low |= SIGNAL_TRST; - } else { - high |= SIGNAL_TRST; - } - - if (srst) - low |= SIGNAL_SRST; - else - high |= SIGNAL_SRST; - int ret = angie_append_set_signals_cmd(device, low, high); - if (ret != ERROR_OK) - return ret; - - ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); - if (ret != ERROR_OK) - return ret; + if (cmd->trst == 1) + out_value &= ~(1 << NTRST_GPIO); // switch /TRST low + else if (cmd->trst == 0) + out_value |= (1 << NTRST_GPIO); // switch /TRST high - angie_clear_queue(device); + if (cmd->srst == 1) + out_value &= ~(1 << NSYSRST_GPIO); // switch /SYSRST low + else if (cmd->srst == 0) + out_value |= (1 << NSYSRST_GPIO); // switch /SYSRST high - return ERROR_OK; + return angie_buffer_append_simple(device, out_value); } /** - * Move to one TAP state or several states in succession. + * Execute JTAG STABLECLOCKS command + * Issues a number of clock cycles while staying in a stable state. + * Because the TMS value required to stay in the RESET state is a 1, whereas + * the TMS value required to stay in any of the other stable states is a 0, + * this function checks the current stable state to decide on the value of TMS + * to use. * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: STABLECLOCKS command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_stableclocks(struct angie *device, + const struct stableclocks_command *cmd) { - int ret, state_count; - enum tap_state *path; - uint8_t tms_sequence; - - unsigned int num_states = cmd->cmd.pathmove->num_states; - path = cmd->cmd.pathmove->path; - state_count = 0; - - while (num_states > 0) { - unsigned int batch_size; + int tms = (tap_get_state() == TAP_RESET ? 1 : 0); - tms_sequence = 0; - - /* Determine batch size */ - if (num_states >= 8) - batch_size = 8; - else - batch_size = num_states; - - for (unsigned int i = 0; i < batch_size; i++) { - if (tap_state_transition(tap_get_state(), false) == path[state_count]) { - /* Append '0' transition: clear bit 'i' in tms_sequence */ - buf_set_u32(&tms_sequence, i, 1, 0x0); - } else if (tap_state_transition(tap_get_state(), true) - == path[state_count]) { - /* Append '1' transition: set bit 'i' in tms_sequence */ - buf_set_u32(&tms_sequence, i, 1, 0x1); - } else { - /* Invalid state transition */ - LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", - tap_state_name(tap_get_state()), - tap_state_name(path[state_count])); - return ERROR_FAIL; - } - - tap_set_state(path[state_count]); - state_count++; - num_states--; - } - - /* Append CLOCK_TMS command to ANGIE command queue */ - LOG_INFO("pathmove batch: count = %i, sequence = 0x%" PRIx8 "", batch_size, tms_sequence); - ret = angie_append_clock_tms_cmd(angie_handle, batch_size, tms_sequence); + // send num_cycles clocks onto the cable + for (unsigned int i = 0; i < cmd->num_cycles; i++) { + int ret = angie_buffer_append(device, 1, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 0, tms, 0); if (ret != ERROR_OK) return ret; } + LOG_DEBUG_IO("clocks %i while in %s", cmd->num_cycles, + tap_state_name(tap_get_state())); + return ERROR_OK; } /** - * Sleep for a specific amount of time. + * Execute JTAG STATEMOVE command * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: STATEMOVE command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_statemove(struct angie *device, + const struct statemove_command *cmd) { - /* IMPORTANT! Due to the time offset in command execution introduced by - * command queueing, this needs to be implemented in the ANGIE device */ - return angie_append_sleep_cmd(device, cmd->cmd.sleep->us); + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->end_state)); + angie_set_end_state(cmd->end_state); + return angie_state_move(device, 0); } /** - * Generate TCK cycles while remaining in a stable state. + * Execute JTAG PATHMOVE command * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @param cmd pointer to the command that shall be executed. + * @param device: Angie device pointer + * @param cmd: PATHMOVE command + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) +static int angie_jtag_execute_pathmove(struct angie *device, + const struct pathmove_command *cmd) { int ret; - - if (!tap_is_state_stable(tap_get_state())) { - LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); - return ERROR_FAIL; - } - - unsigned int num_cycles = cmd->cmd.stableclocks->num_cycles; - - /* TMS stays either high (Test Logic Reset state) or low (all other states) */ - if (tap_get_state() == TAP_RESET) - ret = angie_append_set_signals_cmd(device, 0, SIGNAL_TMS); - else - ret = angie_append_set_signals_cmd(device, SIGNAL_TMS, 0); - - if (ret != ERROR_OK) - return ret; - - while (num_cycles > 0) { - if (num_cycles > 0xFFFF) { - /* ANGIE CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ - ret = angie_append_clock_tck_cmd(device, 0xFFFF); - num_cycles -= 0xFFFF; + int num_states = cmd->num_states; + int tms = 0; + + LOG_DEBUG_IO("pathmove: %i states, end in %s", cmd->num_states, + tap_state_name(cmd->path[cmd->num_states - 1])); + + int state_count = 0; + while (num_states) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { + tms = 0; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { + tms = 1; } else { - ret = angie_append_clock_tck_cmd(device, num_cycles); - num_cycles = 0; + LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", + tap_state_name(tap_get_state()), + tap_state_name(cmd->path[state_count])); + return ERROR_JTAG_DEVICE_ERROR; } + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; + ret = angie_buffer_append(device, 1, tms, 0); if (ret != ERROR_OK) return ret; - } - - return ERROR_OK; -} - -/** - * Post-process JTAG_SCAN command - * - * @param angie_cmd pointer to ANGIE command that shall be processed. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_post_process_scan(struct angie_cmd *angie_cmd) -{ - struct jtag_command *cmd = angie_cmd->cmd_origin; - int ret; - switch (jtag_scan_type(cmd->cmd.scan)) { - case SCAN_IN: - case SCAN_IO: - ret = jtag_read_buffer(angie_cmd->payload_in_start, cmd->cmd.scan); - break; - case SCAN_OUT: - /* Nothing to do for OUT scans */ - ret = ERROR_OK; - break; - default: - LOG_ERROR("BUG: angie post process scan encountered an unknown JTAG scan type"); - ret = ERROR_FAIL; - break; + tap_set_state(cmd->path[state_count]); + state_count++; + num_states--; } + ret = angie_buffer_append(device, 0, tms, 0); + if (ret != ERROR_OK) + return ret; - return ret; + tap_set_end_state(tap_get_state()); + + return ERROR_OK; } /** - * Perform post-processing of commands after ANGIE queue has been executed. + * Process command size in bytes * - * @param device pointer to struct angie identifying ANGIE driver instance. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param device: Angie device pointer + * @param cmd: JTAG command + * @return command size in the transfer buffer in bytes */ -static int angie_post_process_queue(struct angie *device) +static size_t angie_cmd_size(struct angie *device, const struct jtag_command *cmd) { - struct angie_cmd *current; - struct jtag_command *openocd_cmd; - int ret; - - current = device->queue_start; - - while (current) { - openocd_cmd = current->cmd_origin; - - /* Check if a corresponding OpenOCD command is stored for this - * ANGIE command */ - if (current->needs_postprocessing && openocd_cmd) { - switch (openocd_cmd->type) { - case JTAG_SCAN: - ret = angie_post_process_scan(current); - break; - case JTAG_TLR_RESET: - case JTAG_RUNTEST: - case JTAG_PATHMOVE: - case JTAG_SLEEP: - case JTAG_STABLECLOCKS: - /* Nothing to do for these commands */ - ret = ERROR_OK; - break; - default: - ret = ERROR_FAIL; - LOG_ERROR("BUG: angie post process queue encountered unknown JTAG " - "command type"); - break; - } - - if (ret != ERROR_OK) - return ret; - } - - current = current->next; + switch (cmd->type) { + case JTAG_SCAN: + return angie_jtag_scan_size(device, cmd->cmd.scan); + case JTAG_TMS: + return cmd->cmd.tms->num_bits + 2 + 1; + case JTAG_RESET: + return 1; + case JTAG_RUNTEST: + return angie_jtag_runtest_size(device, cmd->cmd.runtest); + case JTAG_STABLECLOCKS: + return cmd->cmd.stableclocks->num_cycles * 2; + case JTAG_TLR_RESET: // renamed from JTAG_STATEMOVE + return tap_get_tms_path_len(tap_get_state(), + cmd->cmd.statemove->end_state) * 2 + 1; + case JTAG_PATHMOVE: + return cmd->cmd.pathmove->num_states * 2 + 1; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + return 0; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + return 0; } - - return ERROR_OK; } -/**************************** JTAG driver functions ***************************/ - /** - * Executes the JTAG Command Queue. + * Execute JTAG commands queue * - * This is done in three stages: First, all OpenOCD commands are processed into - * queued ANGIE commands. Next, the ANGIE command queue is sent to the - * ANGIE device and data received from the ANGIE device is cached. Finally, - * the post-processing function writes back data to the corresponding OpenOCD - * commands. - * - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param cmd_queue to execute + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_execute_queue(struct jtag_command *cmd_queue) +static int angie_jtag_execute_queue(struct jtag_command *cmd_queue) { + int retval = ERROR_OK; struct jtag_command *cmd = cmd_queue; - int ret; + struct angie *device = angie_handle; while (cmd) { + retval = angie_buffer_flush_check(device, angie_cmd_size(device, cmd)); + if (retval != ERROR_OK) + return retval; + switch (cmd->type) { - case JTAG_SCAN: - ret = angie_queue_scan(angie_handle, cmd); - break; - case JTAG_TLR_RESET: - ret = angie_queue_tlr_reset(angie_handle, cmd); - break; - case JTAG_RUNTEST: - ret = angie_queue_runtest(angie_handle, cmd); - break; - case JTAG_PATHMOVE: - ret = angie_queue_pathmove(angie_handle, cmd); - break; - case JTAG_SLEEP: - ret = angie_queue_sleep(angie_handle, cmd); - break; - case JTAG_STABLECLOCKS: - ret = angie_queue_stableclocks(angie_handle, cmd); - break; - default: - ret = ERROR_FAIL; - LOG_ERROR("BUG: encountered unknown JTAG command type"); - break; + case JTAG_SCAN: + retval = angie_jtag_execute_scan(device, cmd->cmd.scan); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_TMS: + retval = angie_jtag_execute_tms(device, cmd->cmd.tms); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_RESET: + angie_jtag_execute_reset(device, cmd->cmd.reset); + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_RUNTEST: + retval = angie_jtag_execute_runtest(device, cmd->cmd.runtest); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + retval = angie_jtag_execute_stableclocks(device, cmd->cmd.stableclocks); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_TLR_RESET: // renamed from JTAG_STATEMOVE + retval = angie_jtag_execute_statemove(device, cmd->cmd.statemove); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_PATHMOVE: + retval = angie_jtag_execute_pathmove(device, cmd->cmd.pathmove); + if (retval != ERROR_OK) + return retval; + retval = angie_buffer_flush(device); + if (retval != ERROR_OK) + return retval; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + break; } - if (ret != ERROR_OK) - return ret; - cmd = cmd->next; } - if (angie_handle->commands_in_queue > 0) { - ret = angie_execute_queued_commands(angie_handle, LIBUSB_TIMEOUT_MS); - if (ret != ERROR_OK) - return ret; - - ret = angie_post_process_queue(angie_handle); - if (ret != ERROR_OK) - return ret; - - angie_clear_queue(angie_handle); - } - - return ERROR_OK; + return angie_buffer_flush(device); } /** - * Set the TCK frequency of the ANGIE adapter. + * Angie quit method * - * @param khz desired JTAG TCK frequency. - * @param jtag_speed where to store corresponding adapter-specific speed value. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_khz(int khz, int *jtag_speed) +static int angie_quit(void) { - int ret; - - if (khz == 0) { - LOG_ERROR("RCLK not supported"); - return ERROR_FAIL; - } - - /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency - * setting can be done independently from all other commands. */ - if (khz >= 375) { - angie_handle->delay_clock_tck = -1; - } else { - ret = angie_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, - &angie_handle->delay_clock_tck); - if (ret != ERROR_OK) - return ret; - } - - /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the - * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS - * commands, all SCAN commands MUST also use the variable frequency - * implementation! */ - if (khz >= 176) { - angie_handle->delay_clock_tms = -1; - angie_handle->delay_scan_in = -1; - angie_handle->delay_scan_out = -1; - angie_handle->delay_scan_io = -1; - } else { - ret = angie_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, - &angie_handle->delay_clock_tms); - if (ret != ERROR_OK) - return ret; - - ret = angie_calculate_delay(DELAY_SCAN_IN, khz * 1000, - &angie_handle->delay_scan_in); - if (ret != ERROR_OK) - return ret; - - ret = angie_calculate_delay(DELAY_SCAN_OUT, khz * 1000, - &angie_handle->delay_scan_out); - if (ret != ERROR_OK) - return ret; - - ret = angie_calculate_delay(DELAY_SCAN_IO, khz * 1000, - &angie_handle->delay_scan_io); - if (ret != ERROR_OK) - return ret; - } - - LOG_DEBUG_IO("ANGIE TCK setup: delay_tck = %i (%li Hz),", - angie_handle->delay_clock_tck, - angie_calculate_frequency(DELAY_CLOCK_TCK, angie_handle->delay_clock_tck)); - LOG_DEBUG_IO(" delay_tms = %i (%li Hz),", - angie_handle->delay_clock_tms, - angie_calculate_frequency(DELAY_CLOCK_TMS, angie_handle->delay_clock_tms)); - LOG_DEBUG_IO(" delay_scan_in = %i (%li Hz),", - angie_handle->delay_scan_in, - angie_calculate_frequency(DELAY_SCAN_IN, angie_handle->delay_scan_in)); - LOG_DEBUG_IO(" delay_scan_out = %i (%li Hz),", - angie_handle->delay_scan_out, - angie_calculate_frequency(DELAY_SCAN_OUT, angie_handle->delay_scan_out)); - LOG_DEBUG_IO(" delay_scan_io = %i (%li Hz),", - angie_handle->delay_scan_io, - angie_calculate_frequency(DELAY_SCAN_IO, angie_handle->delay_scan_io)); - - /* Configure the ANGIE device with the new delay values */ - ret = angie_append_configure_tck_cmd(angie_handle, - angie_handle->delay_scan_in, - angie_handle->delay_scan_out, - angie_handle->delay_scan_io, - angie_handle->delay_clock_tck, - angie_handle->delay_clock_tms); + if (!angie_handle) + return ERROR_OK; + int ret = angie_usb_close(angie_handle); if (ret != ERROR_OK) return ret; - *jtag_speed = khz; - - return ERROR_OK; -} - -/** - * Set the TCK frequency of the ANGIE adapter. - * - * Because of the way the TCK frequency is set up in the ANGIE firmware, - * there are five different speed settings. To simplify things, the - * adapter-specific speed setting value is identical to the TCK frequency in - * khz. - * - * @param speed desired adapter-specific speed value. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_speed(int speed) -{ - int dummy; - - return angie_khz(speed, &dummy); -} + angie_read_queue_clean(&angie_handle->read_queue); -/** - * Convert adapter-specific speed value to corresponding TCK frequency in kHz. - * - * Because of the way the TCK frequency is set up in the ANGIE firmware, - * there are five different speed settings. To simplify things, the - * adapter-specific speed setting value is identical to the TCK frequency in - * khz. - * - * @param speed adapter-specific speed value. - * @param khz where to store corresponding TCK frequency in kHz. - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL - */ -static int angie_speed_div(int speed, int *khz) -{ - *khz = speed; + free(angie_handle); + angie_handle = NULL; return ERROR_OK; } /** - * Initiates the firmware download to the ANGIE adapter and prepares - * the USB handle. + * Angie initialization method * - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @return ERROR_OK on success, negative error code otherwise */ static int angie_init(void) { - int ret, transferred; - char str_manufacturer[20]; - bool download_firmware = false; - char dummy[64]; - uint8_t input_signals, output_signals; - - angie_handle = calloc(1, sizeof(struct angie)); + int ret; + angie_handle = calloc(1, sizeof(*angie_handle)); if (!angie_handle) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto exit; } - ret = angie_usb_open(angie_handle); - if (ret != ERROR_OK) { - free(angie_handle); - angie_handle = NULL; - return ret; - } + angie_read_queue_init(&angie_handle->read_queue); - /* Get String Descriptor to determine if firmware needs to be loaded */ - ret = libusb_get_string_descriptor_ascii(angie_handle->usb_device_handle, 1, (unsigned char *)str_manufacturer, 20); - if (ret < 0) { - /* Could not get descriptor -> Unconfigured or original Keil firmware */ - download_firmware = true; - } else { - /* We got a String Descriptor, check if it is the correct one */ - if (strncmp(str_manufacturer, "NanoXplore, SAS.", 16) != 0) - download_firmware = true; - } + ret = angie_usb_open(angie_handle); + if (ret != ERROR_OK) + goto exit; - if (download_firmware) { + if (angie_is_firmware_needed(angie_handle)) { LOG_INFO("Loading ANGIE firmware. This is reversible by power-cycling ANGIE device."); - if (libusb_claim_interface(angie_handle->usb_device_handle, 0) != LIBUSB_SUCCESS) { - LOG_ERROR("Could not claim interface 0"); - return ERROR_FAIL; + + ret = libusb_claim_interface(angie_handle->usbdev, 0); + if (ret != LIBUSB_SUCCESS) { + LOG_ERROR("Failed to claim interface 0"); + ret = ERROR_FAIL; + goto exit; } + ret = angie_load_firmware_and_renumerate(angie_handle, - ANGIE_FIRMWARE_FILE, ANGIE_RENUMERATION_DELAY_US); + ANGIE_FIRMWARE_FILE, + ANGIE_RENUMERATION_DELAY_US); if (ret != ERROR_OK) { LOG_ERROR("Could not download firmware and re-numerate ANGIE"); angie_quit(); return ret; } + ret = angie_load_bitstream(angie_handle, ANGIE_BITSTREAM_FILE); if (ret != ERROR_OK) { LOG_ERROR("Could not download bitstream"); angie_quit(); return ret; } - if (libusb_release_interface(angie_handle->usb_device_handle, 0) != LIBUSB_SUCCESS) { - LOG_ERROR("Fail release interface 0"); - return ERROR_FAIL; - } - if (libusb_claim_interface(angie_handle->usb_device_handle, 1) != LIBUSB_SUCCESS) { - LOG_ERROR("Could not claim interface 1"); - return ERROR_FAIL; - } - /* Configure io extender 23: all input */ - ret = angie_io_extender_config(angie_handle, 0x23, 0xFF); - if (ret != ERROR_OK) { - LOG_ERROR("Could not configure io extender 23"); - return ret; - } - if (libusb_release_interface(angie_handle->usb_device_handle, 1) != LIBUSB_SUCCESS) { - LOG_ERROR("Fail release interface 1"); - return ERROR_FAIL; - } } else { LOG_INFO("ANGIE device is already running ANGIE firmware"); } - /* Get ANGIE USB IN/OUT endpoints and claim the interface 0 */ - ret = jtag_libusb_choose_interface(angie_handle->usb_device_handle, - &angie_handle->ep_in, &angie_handle->ep_out, 0xFF, 0, 0, -1); - if (ret != ERROR_OK) { - LOG_ERROR("Choose and claim interface failed"); - angie_quit(); - return ret; - } - - /* Initialize ANGIE command queue */ - angie_clear_queue(angie_handle); - - /* Issue one test command with short timeout */ - ret = angie_append_test_cmd(angie_handle); - if (ret != ERROR_OK) { - LOG_ERROR("Append test command failed."); - angie_quit(); - return ret; - } + return ERROR_OK; +exit: + angie_quit(); + return ret; +} - ret = angie_execute_queued_commands(angie_handle, 200); - if (ret != ERROR_OK) { - /* Sending test command failed. The ANGIE device may be forever waiting for - * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was - * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ +/** + * Angie set speed method + * + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_speed(int divisor) +{ + int baud = (divisor == 0) ? 3000000 : + (divisor == 1) ? 2000000 : + 3000000 / divisor; + LOG_DEBUG("angie speed(%d) rate %d bits/sec", divisor, baud); - ret = jtag_libusb_bulk_write(angie_handle->usb_device_handle, angie_handle->ep_in, - dummy, 64, 200, &transferred); + return ERROR_OK; +} - if (ret != ERROR_OK || transferred == 0) { - /* Bulk IN transfer failed -> unrecoverable error condition */ - LOG_ERROR("Cannot communicate with ANGIE device. Disconnect ANGIE from " - "the USB port and re-connect, then re-run OpenOCD"); - angie_quit(); - return ERROR_FAIL; - } - /* Successfully received Bulk IN packet -> continue */ - LOG_INFO("Recovered from lost Bulk IN packet"); +/** + * Angie set khz method + * + * @param khz + * @param divisor returned to caller + * @return ERROR_OK on success, negative error code otherwise + */ +static int angie_khz(int khz, int *divisor) +{ + if (khz == 0) { + LOG_DEBUG("RCLK not supported"); + return ERROR_FAIL; } - angie_clear_queue(angie_handle); - - /* Execute get signals command */ - ret = angie_append_get_signals_cmd(angie_handle); - if (ret != ERROR_OK) { - LOG_ERROR("Append get signals command failed"); - angie_quit(); - return ret; - } - ret = angie_execute_queued_commands(angie_handle, 200); - if (ret != ERROR_OK) { - LOG_ERROR("Execute get signals command failed"); - angie_quit(); - return ret; + // Calculate frequency divisor. + if (khz > 2500) { + *divisor = 0; // Special case: 3 MHz + } else if (khz > 1700) { + *divisor = 1; // Special case: 2 MHz + } else { + *divisor = (2 * 3000 / khz + 1) / 2; + if (*divisor > 0x3FFF) + *divisor = 0x3FFF; } - - /* Post-process the single CMD_GET_SIGNALS command */ - input_signals = angie_handle->queue_start->payload_in[0]; - output_signals = angie_handle->queue_start->payload_in[1]; - angie_dump_signal_states(input_signals, output_signals); - - angie_clear_queue(angie_handle); - return ERROR_OK; } /** - * Closes the USB handle for the ANGIE device. + * Angie set speed div * - * @return on success: ERROR_OK - * @return on failure: ERROR_FAIL + * @param divisor + * @param khz returned to caller + * @return ERROR_OK on success, negative error code otherwise */ -static int angie_quit(void) +static int angie_speed_div(int divisor, int *khz) { - int ret = angie_usb_close(angie_handle); - free(angie_handle); - angie_handle = NULL; - - return ret; + // Maximum 3 Mbaud for bit bang mode + if (divisor == 0) + *khz = 30000; + else if (divisor == 1) + *khz = 20000; + else + *khz = 30000 / divisor; + return ERROR_OK; } static struct jtag_interface angie_interface = { - .execute_queue = angie_execute_queue, + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = angie_jtag_execute_queue, }; struct adapter_driver angie_adapter_driver = { @@ -2393,7 +1368,6 @@ struct adapter_driver angie_adapter_driver = { .init = angie_init, .quit = angie_quit, - .reset = angie_reset, .speed = angie_speed, .khz = angie_khz, .speed_div = angie_speed_div, diff --git a/src/jtag/drivers/angie/README b/src/jtag/drivers/angie/README deleted file mode 100644 index c727154c48..0000000000 --- a/src/jtag/drivers/angie/README +++ /dev/null @@ -1,3 +0,0 @@ -This folder contain only the files needed by ANGIE's driver. -You will find the complete ANGIE's firmware and the bitstream's code source in -contrib/firmware. diff --git a/src/jtag/drivers/angie/angie_bitstream.bit b/src/jtag/drivers/angie/angie_bitstream.bit index 7b3a88f7c8..71fbb85e60 100644 Binary files a/src/jtag/drivers/angie/angie_bitstream.bit and b/src/jtag/drivers/angie/angie_bitstream.bit differ diff --git a/src/jtag/drivers/angie/angie_firmware.bin b/src/jtag/drivers/angie/angie_firmware.bin index 68486ef8f0..ecf2cfd513 100644 Binary files a/src/jtag/drivers/angie/angie_firmware.bin and b/src/jtag/drivers/angie/angie_firmware.bin differ diff --git a/src/jtag/drivers/angie/include/msgtypes.h b/src/jtag/drivers/angie/include/msgtypes.h deleted file mode 100644 index fb045e98c3..0000000000 --- a/src/jtag/drivers/angie/include/msgtypes.h +++ /dev/null @@ -1,172 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - -**************************************************************************** - File : msgtypes.h * - Contents : Definition of the commands supported by NanoXplore * - USB-JTAG ANGIE adapter hardware. * - Based on openULINK project code by: Martin Schmoelzer. * - Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * - * - * -*****************************************************************************/ - -/** - * @file - * Definition of the commands supported by the ANGIE firmware. - * - * Basically, two types of commands can be distinguished: - * - Commands with fixed payload size - * - Commands with variable payload size - * - * SCAN commands (in all variations) carry payloads of variable size, all - * other commands carry payloads of fixed size. - * - * In the case of SCAN commands, the payload size (n) is calculated by - * dividing the scan_size_bits variable by 8, rounding up the result. - * - * Offset zero always contains the command ID. - * - **************************************************************************** - * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * - * * - * OUT: * - * offset 1: scan_size_bytes * - * offset 2: bits_last_byte * - * offset 3: tms_count_start + tms_count_end * - * offset 4: tms_sequence_start * - * offset 5: tms_sequence_end * - * * - * IN: * - * offset 0..n: TDO data * - **************************************************************************** - * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * - * * - * OUT: * - * offset 1: scan_size_bytes * - * offset 2: bits_last_byte * - * offset 3: tms_count_start + tms_count_end * - * offset 4: tms_sequence_start * - * offset 5: tms_sequence_end * - * offset 6..x: TDI data * - **************************************************************************** - * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * - * * - * OUT: * - * offset 1: scan_size_bytes * - * offset 2: bits_last_byte * - * offset 3: tms_count_start + tms_count_end * - * offset 4: tms_sequence_start * - * offset 5: tms_sequence_end * - * offset 6..x: TDI data * - * * - * IN: * - * offset 0..n: TDO data * - **************************************************************************** - * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * - * * - * OUT: * - * offset 1: tms_count * - * offset 2: tms_sequence * - **************************************************************************** - * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * - * * - * OUT: * - * offset 1: low byte of tck_count * - * offset 2: high byte of tck_count * - **************************************************************************** - * CMD_CLOCK_SLEEP_US: * - * * - * OUT: * - * offset 1: low byte of sleep_us * - * offset 2: high byte of sleep_us * - **************************************************************************** - * CMD_CLOCK_SLEEP_MS: * - * * - * OUT: * - * offset 1: low byte of sleep_ms * - * offset 2: high byte of sleep_ms * - **************************************************************************** - * CMD_GET_SIGNALS: * - * * - * IN: * - * offset 0: current state of input signals * - * offset 1: current state of output signals * - **************************************************************************** - * CMD_SET_SIGNALS: * - * * - * OUT: * - * offset 1: signals that should be de-asserted * - * offset 2: signals that should be asserted * - **************************************************************************** - * CMD_CONFIGURE_TCK_FREQ: * - * * - * OUT: * - * offset 1: delay value for scan_in function * - * offset 2: delay value for scan_out function * - * offset 3: delay value for scan_io function * - * offset 4: delay value for clock_tck function * - * offset 5: delay value for clock_tms function * - **************************************************************************** - * CMD_SET_LEDS: * - * * - * OUT: * - * offset 1: LED states: * - * Bit 0: turn COM LED on * - * Bit 1: turn RUN LED on * - * Bit 2: turn COM LED off * - * Bit 3: turn RUN LED off * - * Bits 7..4: Reserved * - **************************************************************************** - * CMD_TEST: * - * * - * OUT: * - * offset 1: unused dummy value * - **************************************************************************** - */ - -#ifndef __MSGTYPES_H -#define __MSGTYPES_H - -/* - * Command IDs: - * - * Bits 7..6: Reserved, should always be zero - * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, - * the IDs 0x00..0x1F are commands with variable payload size, - * the IDs 0x20..0x3F are commands with fixed payload size. - */ - -#define CMD_ID_MASK 0x3F - -/* Commands with variable payload size */ -#define CMD_SCAN_IN 0x00 -#define CMD_SLOW_SCAN_IN 0x01 -#define CMD_SCAN_OUT 0x02 -#define CMD_SLOW_SCAN_OUT 0x03 -#define CMD_SCAN_IO 0x04 -#define CMD_SLOW_SCAN_IO 0x05 - -/* Commands with fixed payload size */ -#define CMD_CLOCK_TMS 0x20 -#define CMD_SLOW_CLOCK_TMS 0x21 -#define CMD_CLOCK_TCK 0x22 -#define CMD_SLOW_CLOCK_TCK 0x23 -#define CMD_SLEEP_US 0x24 -#define CMD_SLEEP_MS 0x25 -#define CMD_GET_SIGNALS 0x26 -#define CMD_SET_SIGNALS 0x27 -#define CMD_CONFIGURE_TCK_FREQ 0x28 -#define CMD_SET_LEDS 0x29 -#define CMD_TEST 0x2A - -/* JTAG signal definition for jtag_get_signals() -- Input signals! */ -#define SIGNAL_TDO 1 - -/* JTAG signal definition for jtag_get_signals() -- Output signals! */ -#define SIGNAL_TDI 8 -#define SIGNAL_TMS 2 -#define SIGNAL_TCK 4 -#define SIGNAL_TRST 1 -#define SIGNAL_SRST 32 - -#endif diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 9d8c592edb..5c0e2ea948 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -94,69 +94,69 @@ static int armjtagew_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); - armjtagew_end_state(cmd->cmd.runtest->end_state); - armjtagew_runtest(cmd->cmd.runtest->num_cycles); - break; + armjtagew_end_state(cmd->cmd.runtest->end_state); + armjtagew_runtest(cmd->cmd.runtest->num_cycles); + break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - armjtagew_end_state(cmd->cmd.statemove->end_state); - armjtagew_state_move(); - break; + armjtagew_end_state(cmd->cmd.statemove->end_state); + armjtagew_state_move(); + break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - armjtagew_path_move(cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path); - break; + armjtagew_path_move(cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path); + break; - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - armjtagew_end_state(cmd->cmd.scan->end_state); + armjtagew_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("scan input, length = %d", scan_size); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ - armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); + armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); #endif - type = jtag_scan_type(cmd->cmd.scan); - armjtagew_scan(cmd->cmd.scan->ir_scan, - type, buffer, - scan_size, cmd->cmd.scan); - break; - - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - - armjtagew_tap_execute(); - - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - armjtagew_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; - - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + type = jtag_scan_type(cmd->cmd.scan); + armjtagew_scan(cmd->cmd.scan->ir_scan, + type, buffer, + scan_size, cmd->cmd.scan); + break; + + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + + armjtagew_tap_execute(); + + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + armjtagew_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; + + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c index c2e763ddb3..ebf38c7fa6 100644 --- a/src/jtag/drivers/bitbang.c +++ b/src/jtag/drivers/bitbang.c @@ -236,14 +236,14 @@ static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, buffered++; } else { switch (bitbang_interface->read()) { - case BB_LOW: - buffer[bytec] &= ~bcval; - break; - case BB_HIGH: - buffer[bytec] |= bcval; - break; - default: - return ERROR_FAIL; + case BB_LOW: + buffer[bytec] &= ~bcval; + break; + case BB_HIGH: + buffer[bytec] |= bcval; + break; + default: + return ERROR_FAIL; } } } @@ -256,14 +256,14 @@ static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, bit_cnt == scan_size - 1)) { for (unsigned int i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) { switch (bitbang_interface->read_sample()) { - case BB_LOW: - buffer[i/8] &= ~(1 << (i % 8)); - break; - case BB_HIGH: - buffer[i/8] |= 1 << (i % 8); - break; - default: - return ERROR_FAIL; + case BB_LOW: + buffer[i / 8] &= ~(1 << (i % 8)); + break; + case BB_HIGH: + buffer[i / 8] |= 1 << (i % 8); + break; + default: + return ERROR_FAIL; } } buffered = 0; @@ -315,64 +315,64 @@ int bitbang_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %s", - cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - bitbang_end_state(cmd->cmd.runtest->end_state); - if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) - return ERROR_FAIL; - break; - - case JTAG_STABLECLOCKS: - /* this is only allowed while in a stable state. A check for a stable - * state was done in jtag_add_clocks() - */ - if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) - return ERROR_FAIL; - break; - - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %s", - tap_state_name(cmd->cmd.statemove->end_state)); - bitbang_end_state(cmd->cmd.statemove->end_state); - if (bitbang_state_move(0) != ERROR_OK) - return ERROR_FAIL; - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %s", - cmd->cmd.pathmove->num_states, - tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); - if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) - return ERROR_FAIL; - break; - case JTAG_SCAN: - bitbang_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("%s scan %d bits; end in %s", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - scan_size, - tap_state_name(cmd->cmd.scan->end_state)); - type = jtag_scan_type(cmd->cmd.scan); - if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, - scan_size) != ERROR_OK) - return ERROR_FAIL; - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - if (bitbang_interface->flush && (bitbang_interface->flush() != ERROR_OK)) - return ERROR_FAIL; - bitbang_sleep(cmd->cmd.sleep->us); - break; - case JTAG_TMS: - retval = bitbang_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %s", + cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + bitbang_end_state(cmd->cmd.runtest->end_state); + if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK) + return ERROR_FAIL; + break; + + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %s", + tap_state_name(cmd->cmd.statemove->end_state)); + bitbang_end_state(cmd->cmd.statemove->end_state); + if (bitbang_state_move(0) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %s", + cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK) + return ERROR_FAIL; + break; + case JTAG_SCAN: + bitbang_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("%s scan %d bits; end in %s", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + scan_size, + tap_state_name(cmd->cmd.scan->end_state)); + type = jtag_scan_type(cmd->cmd.scan); + if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, + scan_size) != ERROR_OK) + return ERROR_FAIL; + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + if (bitbang_interface->flush && (bitbang_interface->flush() != ERROR_OK)) + return ERROR_FAIL; + bitbang_sleep(cmd->cmd.sleep->us); + break; + case JTAG_TMS: + retval = bitbang_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/buspirate.c b/src/jtag/drivers/buspirate.c index 4283616adc..7eab94bd0a 100644 --- a/src/jtag/drivers/buspirate.c +++ b/src/jtag/drivers/buspirate.c @@ -941,24 +941,24 @@ static void buspirate_swd_set_feature(int fd, char feat, char action) uint8_t tmp[1]; switch (feat) { - case FEATURE_TRST: - LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); - return; - case FEATURE_LED: - LOG_ERROR("Buspirate LED feature not available in SWD mode"); - return; - case FEATURE_SRST: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; - break; - case FEATURE_PULLUP: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; - break; - case FEATURE_VREG: - swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; - break; - default: - LOG_DEBUG("Buspirate unknown feature %d", feat); - return; + case FEATURE_TRST: + LOG_DEBUG("Buspirate TRST feature not available in SWD mode"); + return; + case FEATURE_LED: + LOG_ERROR("Buspirate LED feature not available in SWD mode"); + return; + case FEATURE_SRST: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x02 : swd_features & 0x0D; + break; + case FEATURE_PULLUP: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x04 : swd_features & 0x0B; + break; + case FEATURE_VREG: + swd_features = (action == ACTION_ENABLE) ? swd_features | 0x08 : swd_features & 0x07; + break; + default: + LOG_DEBUG("Buspirate unknown feature %d", feat); + return; } tmp[0] = CMD_RAW_PERIPH | swd_features; diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c new file mode 100644 index 0000000000..c031ceece2 --- /dev/null +++ b/src/jtag/drivers/ch347.c @@ -0,0 +1,2442 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Driver for CH347-JTAG interface V1.1 * + * * + * Copyright (C) 2022 by oidcat. * + * Author: oidcatiot@163.com * + * * + * Enhancements by EasyDevKits - info@easydevkits.com * + * * + * CH347 is a high-speed USB bus converter chip that provides UART, I2C * + * and SPI synchronous serial ports and JTAG interface through USB bus. * + * * + * The JTAG interface by CH347 can supports transmission frequency * + * configuration up to 60MHz. * + * * + * The USB2.0 to JTAG scheme based on CH347 can be used to build * + * customized USB high-speed JTAG debugger and other products. * + * * + * _____________ * + * | |____JTAG/SWD (TDO,TDI,TMS,TCK,TRST) * + * USB__| CH347T/F | * + * |_____________|____UART(TXD1,RXD1,RTS1,CTS1,DTR1) * + * ______|______ * + * | | * + * | 8 MHz XTAL | * + * |_____________| * + * * + * This CH347 driver is only tested for the CH347T chip in mode 3. * + * The CH347 datasheet mention another chip the CH347F which was not * + * available for testing. * + * * + * The datasheet for the wch-ic.com's CH347 part is here: * + * https://www.wch-ic.com/downloads/CH347DS1_PDF.html * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if IS_CYGWIN == 1 +#include "windows.h" +#undef LOG_ERROR +#endif + +// project specific includes +#include +#include +#include +#include +#include +#include +#include +#include +#include "libusb_helper.h" + +// system includes +#include +#include +#include +#include +#include + +#define TDI_H BIT(4) +#define TDI_L 0 +#define TMS_H BIT(1) +#define TMS_L 0 +#define TCK_H BIT(0) +#define TCK_L 0 +#define TRST_H BIT(5) +#define TRST_L 0 +#define LED_ON 1 +#define LED_OFF 0 +#define GPIO_CNT 8 // the CH347 has 8 GPIO's +/* mask which GPIO's are available in mode 3 of CH347T only GPIO3 (Pin11 / SCL), GPIO4 (Pin15 / ACT), + GPIO5 (Pin9 / TRST) and GPIO6 (Pin2 / CTS1) are possible. Tested only with CH347T not CH347F chip. + pin numbers are for CH347T */ +#define USEABLE_GPIOS 0x78 +/* For GPIO command: always set bits 7 and 6 for GPIO enable + bits 5 and 4 for pin direction output bit 3 is the data bit */ +#define GPIO_SET_L (BIT(4) | BIT(5) | BIT(6) | BIT(7)) // value for setting a GPIO to low +#define GPIO_SET_H (BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7)) // value for setting a GPIO to high + +#define VENDOR_VERSION 0x5F // for getting the chip version + +// maybe the hardware of the CH347 chip can capture only this amount of TDO bits +#define HW_TDO_BUF_SIZE 4096 +// Don't send more than this amount of bytes via libusb in one packet. Also that is the limit for LARGER_PACK mode. +#define LARGER_PACK_MAX_SIZE 51200 +// The data length contained in each command packet during USB high-speed operation +#define UCMDPKT_DATA_MAX_BYTES_USBHS 507 +#define USBC_PACKET_USBHS 512 // Maximum data length per packet at USB high speed +#define CH347_CMD_HEADER 3 // Protocol header length (1 byte command type + 2 bytes data length) +#define CH347_CMD_INIT_READ_LEN 1 // for JTAG_INIT/SWD_INIT we have only one data byte +// if we send 9 in the init command we get the STANDARD mode or LARGER_PACK mode flag +#define CH347_CMD_INIT_GET_MODE_CLOCK_INDEX_VALUE 9 +// No more bits are allowed per CH347_CMD_JTAG_BIT_OP command; this should be dividable by 8 +#define MAX_BITS_PER_BIT_OP 248 + +/* Protocol transmission format: CMD (1 byte) + Length (2 bytes) + Data + Parameter acquisition, used to obtain firmware version, JTAG interface related parameters, etc */ +#define CH347_CMD_INFO_RD 0xCA +#define CH347_CMD_GPIO 0xCC // GPIO Command +#define CH347_CMD_JTAG_INIT 0xD0 // JTAG Interface initialization command +#define CH347_CMD_JTAG_BIT_OP 0xD1 // JTAG interface pin bit control command +#define CH347_CMD_JTAG_BIT_OP_RD 0xD2 // JTAG interface pin bit control and read commands +#define CH347_CMD_JTAG_DATA_SHIFT 0xD3 // JTAG interface data shift command +#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 // JTAG interface data shift and read command +// for a single command these amount of data can be read at max +#define CH347_SINGLE_CMD_MAX_READ MAX(GPIO_CNT, CH347_CMD_INIT_READ_LEN) + +// for SWD +#define CH347_CMD_SWD_INIT 0xE5 // SWD Interface Initialization Command +#define CH347_CMD_SWD 0xE8 // SWD Command group header +#define CH347_CMD_SWD_REG_W 0xA0 // SWD Interface write reg +#define CH347_CMD_SWD_SEQ_W 0xA1 // SWD Interface write spec seq +#define CH347_CMD_SWD_REG_R 0xA2 // SWD Interface read reg +#define CH347_MAX_PROCESSING_US 7000 // max time in us for packet processing + // USB hosts disconnect the adapter if SWD processing takes more! +#define CH347_MAX_SEND_BUF USBC_PACKET_USBHS +#define CH347_MAX_RECV_BUF USBC_PACKET_USBHS +#define CH347_MAX_CMD_BUF 128 +#define CH347_SWD_CLOCK_MAX 5000 +#define CH347_SWD_CLOCK_BASE 1000 +// limited by the longest sequence processing time +#define CH347_SWD_CLOCK_MAX_DIVISOR (CH347_MAX_PROCESSING_US / swd_seq_dormant_to_swd_len) + +#define CH347_EPOUT 0x06u // the usb endpoint number for writing +#define CH347_EPIN 0x86u // the usb endpoint number for reading +#define CH347T_MPHSI_INTERFACE 2 // the CH347T JTAG interface is number 2 +#define CH347F_MPHSI_INTERFACE 4 // the CH347F JTAG interface is number 4 +#define USB_WRITE_TIMEOUT 500 // write timeout in milliseconds +#define USB_READ_TIMEOUT 500 // read timeout in milliseconds +// BCD version for devices that can use bytewise mode below this version only bitwise mode can be used +#define BYTEWISE_MODE_VERSION 0x241 +/* if the configuration is not setting the vendor id / product id we search for vendor id 1a86 + and product id's 0x55dd (CH347T chip in mode 3), 0x55de (CH347F chip) and 0x55e7 (other chip) */ +#define DEFAULT_VENDOR_ID 0x1a86 +#define DEFAULT_CH347T_PRODUCT_ID 0x55dd +#define DEFAULT_CH347F_PRODUCT_ID 0x55de +#define DEFAULT_OTHER_PRODUCT_ID 0x55e7 + +/* There are 3 different CH347 variants. The datasheet mentions the CH347T chip which has the product id 0x55dd + as default when it's configured to mode 3. The CH347F chip is also mentioned in the datasheet and has the + default product id 0x55de. The 3rd variant is not mentioned in a datasheet but was found here + https://github.com/WCHSoftGroup/ch347 + The code from WCHSoftGroup is also searching for this product id */ +enum ch347_variant { + CH347T = 0, // The CH347T chip + CH347F = 1, // The CH347F chip + OTHER_PRODUCT_ID = 2, // other product id not mentioned in the datasheet +}; + +/* STANDARD_PACK means that we can send only one USBC_PACKET_USBHS-sized USB packet + and then read data back. LARGER_PACK means, we can send packets as large as + LARGER_PACK_MAX_SIZE. libusb splits there large packets into smaller USB packets and + transmit the data. Then we read back the data in a bigger packet. */ +enum pack_size { + UNSET = -1, + STANDARD_PACK = 0, + LARGER_PACK = 1, +}; + +// for STANDARD_PACK mode: these are the 6 possible speeds; values in kHz +static const int ch347_standard_pack_clock_speeds[] = { + 1875, // 1.875 MHz (60000 : 32) + 3750, // 3.75 MHz (60000 : 16) + 7500, // 7.5 MHz (60000 : 8) + 15000, // 15 MHz (60000 : 4) + 30000, // 30 MHz (60000 : 2) + 60000 // 60 MHz +}; + +// for LARGER_PACK mode: these are the 8 possible speeds; values in kHz +static const int ch347_larger_pack_clock_speeds[] = { + 469, // 468.75 kHz (60000 : 128) + 938, // 937.5 kHz (60000 : 64) + 1875, // 1.875 MHz (60000 : 32) + 3750, // 3.75 MHz (60000 : 16) + 7500, // 7.5 MHz (60000 : 8) + 15000, // 15 MHz (60000 : 4) + 30000, // 30 MHz (60000 : 2) + 60000 // 60 MHz +}; + +struct ch347_cmd { + uint8_t type; // the command type + uint8_t *write_data; // data bytes for write + uint16_t write_data_len; // count of data bytes in the write_data buffer + uint16_t read_len; // if >0 a read is needed after this command + uint16_t tdo_bit_count; // how many TDO bits are needed to shift in by this read + struct list_head queue; // for handling a queue (list) +}; + +struct ch347_scan { + struct scan_field *fields; // array of scan_field's for data from the device + int fields_len; // scan_fields array length + struct list_head queue; // for handling a queue (list) +}; + +struct ch347_info { + // Record the CH347 pin status + int tms_pin; + int tdi_pin; + int tck_pin; + int trst_pin; + + enum ch347_variant chip_variant; // ch347_variant for explanation + // if true then we can't us the bytewise commands due to a bug of the chip; depends on BYTEWISE_MODE_VERSION + bool use_bitwise_mode; + enum pack_size pack_size; // see: pack_size for explanation + int max_len; // in STANDARD_PACK or bitwise mode we can send only one USBC_PACKET_USBHS sized package + bool swclk_5mhz_supported; + + // a "scratchpad" where we record all bytes for one command + uint8_t scratchpad_cmd_type; // command type + uint8_t scratchpad[UCMDPKT_DATA_MAX_BYTES_USBHS]; // scratchpad buffer + int scratchpad_idx; // current index in scratchpad + + // after a command is complete it will be stored for later processing + struct list_head cmd_queue; + // all data input scan fields are queued here + struct list_head scan_queue; + // read buffer for the single commands like CH347_CMD_GPIO and CH347_CMD_JTAG_INIT + uint8_t single_read[CH347_SINGLE_CMD_MAX_READ]; + int singe_read_len; // data length in single_read +}; + +struct ch347_swd_io { + uint8_t usb_cmd; // 0xA0, 0xA1, 0xA2 + uint8_t cmd; + uint32_t *dst; + uint32_t value; + struct list_head list_entry; +}; + +struct ch347_swd_context { + uint8_t send_buf[CH347_MAX_SEND_BUF]; + uint8_t recv_buf[CH347_MAX_RECV_BUF]; + int send_len; + int recv_len; + int need_recv_len; + int queued_retval; + int sent_cmd_count; + unsigned int clk_divisor; + unsigned int total_swd_clk; + struct list_head send_cmd_head; + struct list_head free_cmd_head; + struct ch347_swd_io ch347_cmd_buf[CH347_MAX_CMD_BUF]; +}; + +static struct ch347_swd_context ch347_swd_context; +static bool swd_mode; +static uint16_t default_ch347_vids[] = {DEFAULT_VENDOR_ID, DEFAULT_VENDOR_ID, DEFAULT_VENDOR_ID, 0}; +static uint16_t default_ch347_pids[] = {DEFAULT_CH347T_PRODUCT_ID, + DEFAULT_CH347F_PRODUCT_ID, DEFAULT_OTHER_PRODUCT_ID, 0}; +static uint16_t custom_ch347_vids[] = {0, 0, 0, 0}; +static uint16_t custom_ch347_pids[] = {0, 0, 0, 0}; +static char *ch347_device_desc; +static uint8_t ch347_activity_led_gpio_pin = 0xFF; +static bool ch347_activity_led_active_high; +static struct ch347_info ch347; +static struct libusb_device_handle *ch347_handle; + +/* there are "single" commands. These commands can't be chained together and + need to be send as single command and need a read after write */ +static inline bool ch347_is_single_cmd_type(uint8_t type) +{ + return type == CH347_CMD_GPIO || type == CH347_CMD_JTAG_INIT || type == CH347_CMD_SWD_INIT; +} + +static void log_buf_dump(const uint8_t *data, unsigned int size, bool recv) +{ + unsigned int i = 0, j = 0; + unsigned int n = size * 3 + 1; + char *str = malloc(n); + if (!str) + return; + + while (i < size && j < n) { + uint8_t cmd = data[i++]; + hexify(str + j, &cmd, 1, n - j); + j += 2; + str[j++] = ' '; + + unsigned int cmd_payload_size = le_to_h_u16(data + i); + if (i + 2 <= size && j + 4 < n) { + hexify(str + j, data + i, 2, n - j); + i += 2; + j += 4; + str[j++] = ' '; + } + + if (cmd == CH347_CMD_SWD) { + // nested SWD commands + str[j] = '\0'; + if (i + cmd_payload_size > size) { + LOG_DEBUG_IO("%s - bad size", str); + cmd_payload_size = size - i; + } else { + LOG_DEBUG_IO("%s", str); + } + j = 0; + unsigned int swd_base_i = i; + + while (i < swd_base_i + cmd_payload_size) { + uint8_t swd_cmd = data[i++]; + hexify(str + j, &swd_cmd, 1, n - j); + j += 2; + str[j++] = ' '; + + unsigned int swd_bits = 0; + unsigned int swd_payload_size = 0; + if (!recv) { + if (i + 2 <= size) { + swd_bits = le_to_h_u16(data + i); + hexify(str + j, data + i, 2, n - j); + i += 2; + j += 4; + str[j++] = ' '; + } + } + + switch (swd_cmd) { + case CH347_CMD_SWD_REG_W: + if (recv) + swd_payload_size = 1; + else + swd_payload_size = DIV_ROUND_UP(swd_bits, 8); + break; + case CH347_CMD_SWD_SEQ_W: + if (!recv) + swd_payload_size = DIV_ROUND_UP(swd_bits, 8); + break; + case CH347_CMD_SWD_REG_R: + if (recv) + swd_payload_size = 1 + 4 + 1; + else + swd_payload_size = 1; + break; + } + + hexify(str + j, data + i, MIN(swd_payload_size, size - i), n - j); + i += swd_payload_size; + j += 2 * swd_payload_size; + str[j] = '\0'; + if (i > size) + LOG_DEBUG_IO(" %s - bad size", str); + else + LOG_DEBUG_IO(" %s", str); + j = 0; + } + } else { + hexify(str + j, data + i, MIN(cmd_payload_size, size - i), n - j); + i += cmd_payload_size; + j += 2 * cmd_payload_size; + str[j] = '\0'; + if (i > size) + LOG_DEBUG_IO("%s - bad size", str); + else + LOG_DEBUG_IO("%s", str); + j = 0; + } + } + free(str); +} + +/** + * @brief writes data to the CH347 via libusb driver + * + * @param data Point to the data buffer + * @param length Data length in and out + * @return ERROR_OK at success + */ +static int ch347_write_data(uint8_t *data, int *length) +{ + int write_len = *length; + int i = 0; + int transferred = 0; + + while (true) { + int retval = jtag_libusb_bulk_write(ch347_handle, CH347_EPOUT, (char *)&data[i], + write_len, USB_WRITE_TIMEOUT, &transferred); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 write fail"); + *length = 0; + return retval; + } + i += transferred; + if (i >= *length) + break; + write_len = *length - i; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + LOG_DEBUG_IO("size=%d, buf=", i); + log_buf_dump(data, i, false); + } + + *length = i; + return ERROR_OK; +} + +/** + * @brief reads data from the CH347 via libusb driver + * + * @param data Point to the data buffer + * @param length Data length in and out + * @return ERROR_OK at success + */ +static int ch347_read_data(uint8_t *data, int *length) +{ + int read_len = *length; + int i = 0; + int transferred = 0; + + while (true) { + int retval = jtag_libusb_bulk_read(ch347_handle, CH347_EPIN, (char *)&data[i], + read_len, USB_READ_TIMEOUT, &transferred); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 read fail"); + *length = 0; + return retval; + } + + i += transferred; + if (i >= *length) + break; + read_len = *length - i; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + LOG_DEBUG_IO("size=%d, buf=", i); + log_buf_dump(data, i, true); + } + + *length = i; + return ERROR_OK; +} + +/** + * @brief calculates the amount of bits and bytes that should be read + * for this command + * + * @param cmd command for the calculation + */ +static void ch347_cmd_calc_reads(struct ch347_cmd *cmd) +{ + cmd->read_len = 0; + cmd->tdo_bit_count = 0; + + switch (cmd->type) { + case CH347_CMD_GPIO: + // for GPIO we need to read back the same amount of data that we had send + cmd->read_len = cmd->write_data_len; + break; + case CH347_CMD_JTAG_INIT: + case CH347_CMD_SWD_INIT: + // for JTAG_INIT/SWD_INIT the amount is fixed + cmd->read_len = CH347_CMD_INIT_READ_LEN; + break; + case CH347_CMD_JTAG_BIT_OP_RD: + // for bit operations we need to count the TCK high edges + for (int i = 0; i < cmd->write_data_len; i++) { + if ((cmd->write_data[i] & TCK_H) == TCK_H) { + cmd->read_len++; + cmd->tdo_bit_count++; + } + } + break; + case CH347_CMD_JTAG_DATA_SHIFT_RD: + // for byte operations: need to read one byte back for each data byte + cmd->read_len = cmd->write_data_len; + // we occupy 8 bits per byte in the TDO hardware buffer + cmd->tdo_bit_count = cmd->read_len * 8; + break; + } +} + +/** + * @brief copy the scratchpad content into a new command in the command queue + * + * @param scan_fields array of scan_field's for data from the device + * @param scan_fields_len array length + * @return ERROR_OK at success + */ +static int ch347_cmd_from_scratchpad(void) +{ + // nothing to do if no bytes are recorded + if (!ch347.scratchpad_idx) + return ERROR_OK; + + // malloc for the command and data bytes + struct ch347_cmd *cmd = malloc(sizeof(struct ch347_cmd)); + if (cmd) + cmd->write_data = malloc(ch347.scratchpad_idx); + if (!cmd || !cmd->write_data) { + LOG_ERROR("malloc failed"); + free(cmd); + return ERROR_FAIL; + } + + // copy data, calculate the reads and add to the command queue + cmd->type = ch347.scratchpad_cmd_type; + cmd->write_data_len = ch347.scratchpad_idx; + memcpy(cmd->write_data, ch347.scratchpad, ch347.scratchpad_idx); + ch347_cmd_calc_reads(cmd); + list_add_tail(&cmd->queue, &ch347.cmd_queue); + + // cleanup the scratchpad for the next command + ch347.scratchpad_cmd_type = 0; + ch347.scratchpad_idx = 0; + return ERROR_OK; +} + +/** + * @brief Reads data back from CH347 and decode it byte- and bitwise into the buffer + * + * @param decoded_buf Point to a buffer to place the data to be decoded; need to be sized + * to the decoded size length; not the raw_read_len + * @param decoded_buf_len length of the decoded_buf + * @param raw_read_len Data length in bytes that should be read via libusb; the decoded length can be shorter + * @return ERROR_OK at success + */ +static int ch347_read_scan(uint8_t *decoded_buf, int decoded_buf_len, int raw_read_len) +{ + int read_len = raw_read_len; + uint8_t *read_buf = malloc(read_len); + if (!read_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + + int retval = ch347_read_data(read_buf, &read_len); + if (retval != ERROR_OK) { + free(read_buf); + return retval; + } + + int rd_idx = 0; + int decoded_buf_idx = 0; + + while (rd_idx < read_len) { + unsigned int type = read_buf[rd_idx++]; + uint16_t data_len = le_to_h_u16(&read_buf[rd_idx]); + rd_idx += 2; + if (decoded_buf_idx > decoded_buf_len) { + LOG_ERROR("CH347 decoded_buf too small"); + free(read_buf); + return ERROR_FAIL; + } + + // nothing to decode? Only read to make the CH347 happy! + if (!decoded_buf) { + rd_idx += data_len; + continue; + } + + switch (type) { + case CH347_CMD_GPIO: + case CH347_CMD_JTAG_INIT: + case CH347_CMD_SWD_INIT: + case CH347_CMD_JTAG_DATA_SHIFT_RD: + // for all bytewise commands: copy the data bytes + memcpy(&decoded_buf[decoded_buf_idx], &read_buf[rd_idx], data_len); + decoded_buf_idx += data_len; + rd_idx += data_len; + break; + case CH347_CMD_JTAG_BIT_OP_RD: + // for CH347_CMD_JTAG_BIT_OP_RD we need to copy bit by bit + for (int i = 0; i < data_len; i++) { + if (read_buf[rd_idx + i] & BIT(0)) + decoded_buf[decoded_buf_idx + i / 8] |= BIT(i % 8); + else + decoded_buf[decoded_buf_idx + i / 8] &= ~(BIT(i % 8)); + } + rd_idx += data_len; + decoded_buf_idx += DIV_ROUND_UP(data_len, 8); + break; + default: + LOG_ERROR("CH347 read command fail"); + free(read_buf); + return ERROR_FAIL; + } + } + + free(read_buf); + return ERROR_OK; +} + +/** + * @brief Used to put the data from the decoded buffer into the scan command fields + * + * @param decoded_buf Point to a buffer for the decoded data + * @param decoded_buf_len length of the decoded_buf + * @return ERROR_OK at success + */ +static int ch347_scan_data_to_fields(uint8_t *decoded_buf, int decoded_buf_len) +{ + int byte_offset = 0; + struct ch347_scan *scan; + struct ch347_scan *tmp; + int bit_offset = 0; + list_for_each_entry_safe(scan, tmp, &ch347.scan_queue, queue) { + for (int i = 0; i < scan->fields_len; i++) { + int num_bits = scan->fields[i].num_bits; + LOG_DEBUG("fields[%d].in_value[%d], read from bit offset: %d", i, num_bits, bit_offset); + // only if we need the value + if (scan->fields[i].in_value) { + uint8_t *capture_buf = malloc(DIV_ROUND_UP(num_bits, 8)); + if (!capture_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + uint8_t *captured = buf_set_buf(decoded_buf, bit_offset, capture_buf, 0, num_bits); + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *str = buf_to_hex_str(captured, num_bits); + LOG_DEBUG_IO("size=%d, buf=[%s]", num_bits, str); + free(str); + } + + buf_cpy(captured, scan->fields[i].in_value, num_bits); + free(capture_buf); + } else { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) + LOG_DEBUG_IO("field skipped"); + } + bit_offset += num_bits; + } + list_del(&scan->queue); + free(scan); + /* after one round of scan field processing the + next data bits are read from the next data byte + => round up and calculate the next start bit */ + byte_offset = DIV_ROUND_UP(bit_offset, 8); + bit_offset = byte_offset * 8; + } + + // if not all bytes are transferred: put the rest into single_read buffer + if (byte_offset < decoded_buf_len) { + ch347.singe_read_len = decoded_buf_len - byte_offset; + LOG_DEBUG("single read of %d bytes", ch347.singe_read_len); + if (ch347.singe_read_len > CH347_SINGLE_CMD_MAX_READ) { + LOG_ERROR("Can't read more than %d bytes for a single command!", CH347_SINGLE_CMD_MAX_READ); + ch347.singe_read_len = CH347_SINGLE_CMD_MAX_READ; + } + memcpy(ch347.single_read, &decoded_buf[byte_offset], ch347.singe_read_len); + } + + return ERROR_OK; +} + +/** + * @brief Sends the write buffer via libusb + * and if LARGER_PACK mode is active read also data back + * + * @return ERROR_OK at success + */ +static int ch347_cmd_transmit_queue(void) +{ + // queue last command + int retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + // nothing to do! => done here + if (list_empty(&ch347.cmd_queue)) + return ERROR_OK; + + // calculate the needed buffer length for all decoded bytes + struct ch347_cmd *cmd; + int decoded_buf_len = 0; + list_for_each_entry(cmd, &ch347.cmd_queue, queue) + if (cmd->read_len > 0) + decoded_buf_len += ch347_is_single_cmd_type(cmd->type) ? + cmd->read_len : DIV_ROUND_UP(cmd->tdo_bit_count, 8); + + // create the buffer for all decoded bytes + uint8_t *decoded_buf = NULL; + int decoded_buf_idx = 0; + if (decoded_buf_len > 0) { + decoded_buf = malloc(decoded_buf_len); + if (!decoded_buf) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + } + + while (!list_empty(&ch347.cmd_queue)) { + struct ch347_cmd *last_cmd = NULL; + int total_len = 0; + int total_tdo_count = 0; + int bytes_to_write = 0; + + list_for_each_entry(cmd, &ch347.cmd_queue, queue) { + total_len += CH347_CMD_HEADER + cmd->write_data_len; + total_tdo_count += cmd->tdo_bit_count; + // don't exceed max length or max TDO bit count + if (total_len >= ch347.max_len || total_tdo_count >= HW_TDO_BUF_SIZE) + break; + // remember the last cmd to send and bytes to send + last_cmd = cmd; + bytes_to_write = total_len; + } + + // sanity checks + if (!last_cmd || bytes_to_write == 0) { + LOG_ERROR("Nothing to send!"); + free(decoded_buf); + return ERROR_FAIL; + } + + // create the write buffer + uint8_t *write_buf = malloc(bytes_to_write); + if (!write_buf) { + LOG_ERROR("malloc failed"); + free(decoded_buf); + return ERROR_FAIL; + } + + int idx = 0; + int bytes_to_read = 0; + int current_decoded_buf_len = 0; + struct ch347_cmd *tmp; + + list_for_each_entry_safe(cmd, tmp, &ch347.cmd_queue, queue) { + // copy command to buffer + write_buf[idx++] = cmd->type; + h_u16_to_le(&write_buf[idx], cmd->write_data_len); + idx += 2; + memcpy(&write_buf[idx], cmd->write_data, cmd->write_data_len); + idx += cmd->write_data_len; + // need to read something back? + if (cmd->read_len > 0) { + bytes_to_read += CH347_CMD_HEADER + cmd->read_len; + current_decoded_buf_len += ch347_is_single_cmd_type(cmd->type) ? + cmd->read_len : DIV_ROUND_UP(cmd->tdo_bit_count, 8); + } + + // cmd data no longer needed + list_del(&cmd->queue); + free(cmd->write_data); + free(cmd); + + if (cmd == last_cmd) + break; + } + + // write data to device + retval = ch347_write_data(write_buf, &idx); + free(write_buf); + if (retval != ERROR_OK) { + free(decoded_buf); + return retval; + } + + if (!bytes_to_read) + continue; + + // Need only to execute a read without decoding the data to make the CH347 happy? + if (!current_decoded_buf_len) { + // read but don't decode anything + retval = ch347_read_scan(NULL, 0, bytes_to_read); + } else { + retval = ch347_read_scan(&decoded_buf[decoded_buf_idx], current_decoded_buf_len, bytes_to_read); + decoded_buf_idx += current_decoded_buf_len; + } + + if (retval != ERROR_OK) { + free(decoded_buf); + return retval; + } + } + + // something decoded from the data read back from CH347? + if (decoded_buf) { + // put the decoded data into the scan fields or single_read buffer + retval = ch347_scan_data_to_fields(decoded_buf, decoded_buf_len); + free(decoded_buf); + } + + return retval; +} + +/** + * @brief starts the next command in the scratchpad. If it's the same command type + * it can concat the data bytes. no need to make a new command for this case + * + * @param type command type + */ +static int ch347_cmd_start_next(uint8_t type) +{ + // different command type or non chainable command? (GPIO commands can't be concat) + uint8_t prev_type = ch347.scratchpad_cmd_type; + if (prev_type != type || ch347_is_single_cmd_type(type)) { + // something written in the scratchpad? => store it as command + if (prev_type != 0 && ch347.scratchpad_idx > 0) { + int retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + /* if the last queued command is not chainable we should send it immediately + because e.g. the GPIO command can't be combined with any other command */ + if (ch347_is_single_cmd_type(prev_type)) { + retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + } + } + + /* before we can send non chainable command ("single" like GPIO command) we should send all + other commands because we can't send it together with other commands */ + if (ch347_is_single_cmd_type(type)) { + int retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + } + + // store the next command type + ch347.scratchpad_cmd_type = type; + } + + return ERROR_OK; +} + +/** + * @brief queue the scan fields into the scan queue + * + * @param scan_fields array of scan field's for data from the device + * @param scan_fields_len array length + * @return ERROR_OK at success + */ +static int ch347_scan_queue_fields(struct scan_field *scan_fields, int scan_fields_len) +{ + // malloc for the scan struct + struct ch347_scan *scan = malloc(sizeof(struct ch347_scan)); + if (!scan) { + LOG_ERROR("malloc failed"); + return ERROR_FAIL; + } + + scan->fields = scan_fields; + scan->fields_len = scan_fields_len; + list_add_tail(&scan->queue, &ch347.scan_queue); + return ERROR_OK; +} + +/** + * @brief Function executes the single command and deliver one byte from the buffer + * that's read back from USB + * + * @param read_buf_idx index of the byte that should be returned + * @param byte returns byte at index or if index is out of range the first byte + * @return ERROR_OK at success + */ +static int ch347_single_read_get_byte(int read_buf_idx, uint8_t *byte) +{ + int retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + + if (read_buf_idx > CH347_SINGLE_CMD_MAX_READ || read_buf_idx < 0) { + LOG_ERROR("read_buf_idx out of range"); + return ERROR_FAIL; + } + + *byte = ch347.single_read[read_buf_idx]; + return ERROR_OK; +} + +/** + * @brief checks if the scratchpad is full. If it's full the function creates + * a command from it and puts it into the command queue + */ +static void ch347_scratchpad_check_full(void) +{ + // if full create a new command in the queue + if (ch347.scratchpad_idx == UCMDPKT_DATA_MAX_BYTES_USBHS) { + uint8_t type = ch347.scratchpad_cmd_type; + ch347_cmd_from_scratchpad(); + ch347.scratchpad_cmd_type = type; + } +} + +/** + * @brief adds one byte to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @param byte add this byte + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_byte(uint8_t byte) +{ + if (ch347.scratchpad_cmd_type == 0) { + LOG_ERROR("call ch347_next_cmd first!"); + return ERROR_FAIL; + } + + ch347.scratchpad[ch347.scratchpad_idx++] = byte; + ch347_scratchpad_check_full(); + return ERROR_OK; +} + +/** + * @brief adds the output pin byte to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_pin_byte(void) +{ + return ch347_scratchpad_add_byte(ch347.tms_pin | ch347.tdi_pin | ch347.tck_pin | ch347.trst_pin); +} + +/** + * @brief adds bytes from a buffer to the scratchpad + * if scratchpad is full after this byte the command will be created from the + * scratchpad and the scratchpad is cleared for the next command + * + * @param bytes add this bytes + * @param count byte count + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_bytes(uint8_t *bytes, int count) +{ + if (ch347.scratchpad_cmd_type == 0) { + LOG_ERROR("call ch347_next_cmd first!"); + return ERROR_FAIL; + } + + int remaining = count; + int bytes_idx = 0; + while (remaining > 0) { + int bytes_to_store = ch347.scratchpad_idx + remaining <= UCMDPKT_DATA_MAX_BYTES_USBHS ? + remaining : UCMDPKT_DATA_MAX_BYTES_USBHS - ch347.scratchpad_idx; + + if (bytes) + memcpy(&ch347.scratchpad[ch347.scratchpad_idx], &bytes[bytes_idx], bytes_to_store); + else + memset(&ch347.scratchpad[ch347.scratchpad_idx], 0, bytes_to_store); + + ch347.scratchpad_idx += bytes_to_store; + bytes_idx += bytes_to_store; + remaining -= bytes_to_store; + ch347_scratchpad_check_full(); + } + + return ERROR_OK; +} + +/** + * @brief Function used to change the TMS value at the + * rising edge of TCK to switch its TAP state + * + * @param tms TMS value to be changed; true = output TMS high; false = output TMS low + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_clock_tms(bool tms) +{ + ch347.tms_pin = tms ? TMS_H : TMS_L; + ch347.tck_pin = TCK_L; + int retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + ch347.tck_pin = TCK_H; + return ch347_scratchpad_add_pin_byte(); +} + +/** + * @brief Function adds a certain amount of TCK pulses without changing the TMS pin + * + * @param count Amount of L/H TCK pulses to add + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_stableclocks(int count) +{ + if (ch347.scratchpad_cmd_type == 0) { + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + } + + bool tms = ch347.tms_pin == TMS_H; + for (int i = 0; i < count; i++) { + int retval = ch347_scratchpad_add_clock_tms(tms); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +/** + * @brief Function to ensure that the clock is in a low state + * + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_idle_clock(void) +{ + ch347.tck_pin = TCK_L; + return ch347_scratchpad_add_pin_byte(); +} + +/** + * @brief Function that performs state switching by changing the value of TMS + * + * @param tms_value The TMS values that need to be switched form one byte of data in the switching order + * @param step The number of bit values that need to be read from the tms_value value + * @param skip Count from the skip bit of tms_value to step + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_tms_change(const uint8_t *tms_value, int step, int skip) +{ + LOG_DEBUG_IO("TMS Value: %02x..., step = %d, skip = %d", tms_value[0], step, skip); + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + for (int i = skip; i < step; i++) { + retval = ch347_scratchpad_add_clock_tms((tms_value[i / 8] >> (i % 8)) & BIT(0)); + if (retval != ERROR_OK) + return retval; + } + + return ch347_scratchpad_add_idle_clock(); +} + +/** + * @brief Obtain the current Tap status and switch to the status TMS value passed down by cmd + * + * @param cmd Upper layer transfer command parameters + * @return ERROR_OK at success; ERROR_JTAG_TRANSITION_INVALID if no transition is possible + */ +static int ch347_scratchpad_add_move_path(struct pathmove_command *cmd) +{ + LOG_DEBUG_IO("num_states=%d, last_state=%d", cmd->num_states, cmd->path[cmd->num_states - 1]); + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = 0; i < cmd->num_states; i++) { + if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) { + retval = ch347_scratchpad_add_clock_tms(0); + if (retval != ERROR_OK) + return retval; + } else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) { + retval = ch347_scratchpad_add_clock_tms(1); + if (retval != ERROR_OK) + return retval; + } else { + LOG_ERROR("No transition possible!"); + return ERROR_JTAG_TRANSITION_INVALID; + } + tap_set_state(cmd->path[i]); + } + + return ch347_scratchpad_add_idle_clock(); +} + +/** + * @brief Toggle the tap state to the target state + * + * @param state Pre switch target path + * @param skip Number of digits to skip + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_move_state(enum tap_state state, int skip) +{ + uint8_t tms_scan; + int tms_len; + + LOG_DEBUG_IO("from %s to %s", tap_state_name(tap_get_state()), tap_state_name(state)); + // don't do anything if we are already in the right state; but do execute always the TAP_RESET + if (tap_get_state() == state && state != TAP_RESET) + return ERROR_OK; + + tms_scan = tap_get_tms_path(tap_get_state(), state); + tms_len = tap_get_tms_path_len(tap_get_state(), state); + int retval = ch347_scratchpad_add_tms_change(&tms_scan, tms_len, skip); + tap_set_state(state); + return retval; +} + +/** + * @brief CH347 Batch read/write function + * + * @param cmd The scan command + * @param bits Read and write data this time + * @param bits_len Incoming data length in bits + * @param scan The transmission method of incoming data to determine whether to perform data reading + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_write_read(struct scan_command *cmd, uint8_t *bits, int bits_len, enum scan_type scan) +{ + // the bits and bytes to transfer + int byte_count = bits_len / 8; + int bit_count = bits_len % 8; + + // only bytes are not possible because we need to set TMS high for the last bit + if (byte_count > 0 && bit_count == 0) { + // make one byte to eight bits + byte_count--; + bit_count = 8; + } + + // in bitwise mode only bits are allowed + if (ch347.use_bitwise_mode) { + byte_count = 0; + bit_count = bits_len; + } + + bool is_read = (scan == SCAN_IN || scan == SCAN_IO); + + // if we need to send bytes + if (byte_count > 0) { + // start the next cmd and copy the data out bytes to it + int retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_DATA_SHIFT_RD : CH347_CMD_JTAG_DATA_SHIFT); + if (retval != ERROR_OK) + return retval; + + if (bits) + retval = ch347_scratchpad_add_bytes(bits, byte_count); + else + retval = ch347_scratchpad_add_bytes(NULL, byte_count); + + if (retval != ERROR_OK) + return retval; + } + + // bits are always need to send; no possibility to not send bits + int retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + ch347.tms_pin = TMS_L; + ch347.tdi_pin = TDI_L; + + for (int i = 0; i < bit_count; i++) { + if (bits) + ch347.tdi_pin = ((bits[byte_count + i / 8] >> i % 8) & BIT(0)) ? TDI_H : TDI_L; + + // for the last bit set TMS high to exit the shift state + if (i + 1 == bit_count) + ch347.tms_pin = TMS_H; + + ch347.tck_pin = TCK_L; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + ch347.tck_pin = TCK_H; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + /* cut the package after each MAX_BITS_PER_BIT_OP bits because it + needs a dividable by 8 bits package */ + if (i > 0 && (i + 1) % MAX_BITS_PER_BIT_OP == 0) { + retval = ch347_cmd_from_scratchpad(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_cmd_start_next(is_read ? CH347_CMD_JTAG_BIT_OP_RD : CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + } + } + + // one TCK_L after the last bit + retval = ch347_scratchpad_add_idle_clock(); + if (retval != ERROR_OK) + return retval; + + // if read is involved we need to queue the scan fields + if (is_read) + return ch347_scan_queue_fields(cmd->fields, cmd->num_fields); + + return ERROR_OK; +} + +/** + * @brief Toggle the Tap state to run test/idle + * + * @param cycles how many clock cycles for output + * @param state JTAG end state + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_run_test(int cycles, enum tap_state state) +{ + LOG_DEBUG_IO("cycles=%d, end_state=%d", cycles, state); + int retval; + if (tap_get_state() != TAP_IDLE) { + retval = ch347_scratchpad_add_move_state(TAP_IDLE, 0); + if (retval != ERROR_OK) + return retval; + } + + retval = ch347_scratchpad_add_stableclocks(cycles); + if (retval != ERROR_OK) + return retval; + + return ch347_scratchpad_add_move_state(state, 0); +} + +/** + * @brief Switch to SHIFT-DR or SHIFT-IR status for scanning + * + * @param cmd Upper layer transfer command parameters + * @return ERROR_OK at success + */ +static int ch347_scratchpad_add_scan(struct scan_command *cmd) +{ + static const char *const type2str[] = {"", "SCAN_IN", "SCAN_OUT", "SCAN_IO"}; + + enum scan_type type = jtag_scan_type(cmd); + uint8_t *buf = NULL; + int scan_bits = jtag_build_buffer(cmd, &buf); + + // add a move to IRSHIFT or DRSHIFT state + int retval; + if (cmd->ir_scan) + retval = ch347_scratchpad_add_move_state(TAP_IRSHIFT, 0); + else + retval = ch347_scratchpad_add_move_state(TAP_DRSHIFT, 0); + + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) { + char *log_buf = buf_to_hex_str(buf, scan_bits); + LOG_DEBUG_IO("scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d", + cmd->ir_scan ? "IRSCAN" : "DRSCAN", + type2str[type], + scan_bits, log_buf, cmd->end_state); + free(log_buf); + } + + retval = ch347_scratchpad_add_write_read(cmd, buf, scan_bits, type); + free(buf); + if (retval != ERROR_OK) + return retval; + + // add a move to the final state + return ch347_scratchpad_add_move_state(cmd->end_state, 1); +} + +/** + * @brief Sets a GPIO bit + * + * @param gpio GPIO bit number 0-7 + * @param data true for high; false for low + * @return ERROR_OK at success + */ +static int ch347_gpio_set(int gpio, bool data) +{ + int retval = ch347_cmd_start_next(CH347_CMD_GPIO); + if (retval != ERROR_OK) + return retval; + + uint8_t gpios[GPIO_CNT]; + memset(gpios, 0, GPIO_CNT); + /* always set bits 7 and 6 for GPIO enable + bits 5 and 4 for pin direction output + bit 3 is the data bit */ + gpios[gpio] = data == 0 ? GPIO_SET_L : GPIO_SET_H; + retval = ch347_scratchpad_add_bytes(gpios, GPIO_CNT); + if (retval != ERROR_OK) + return retval; + + // check in the read if the bit is set/cleared correctly + uint8_t byte; + retval = ch347_single_read_get_byte(gpio, &byte); + if (retval != ERROR_OK) + return retval; + + if ((byte & BIT(6)) >> 6 != data) { + LOG_ERROR("Output not set."); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** + * @brief Turn the activity LED on or off + * + * @param led_state LED_ON or LED_OFF + * @return ERROR_OK at success or if pin is not configured + */ +static int ch347_activity_led_set(int led_state) +{ + if (ch347_activity_led_gpio_pin != 0xFF) + return ch347_gpio_set(ch347_activity_led_gpio_pin, ch347_activity_led_active_high ? led_state : 1 - led_state); + + // not configured => also OK + return ERROR_OK; +} + +/** + * @brief Control (assert/deassert) the signals SRST and TRST on the interface. + * + * @param trst 1 to assert TRST, 0 to deassert TRST. + * @param srst 1 to assert SRST, 0 to deassert SRST. + * @return Always ERROR_FAIL for asserting via SRST and TRST in SWD mode. + * ERROR_OK for assert/deassert in JTAG mode for TRST + */ +static int ch347_reset(int trst, int srst) +{ + LOG_DEBUG_IO("reset trst: %i srst %i", trst, srst); + if (srst) { + LOG_ERROR("Asserting SRST not supported!"); + return ERROR_FAIL; + } + + if (swd_mode) { + if (trst) + LOG_WARNING("Asserting TRST not supported in SWD mode!"); + return ERROR_OK; + } + + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_BIT_OP); + if (retval != ERROR_OK) + return retval; + + ch347.trst_pin = trst ? TRST_L : TRST_H; + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_idle_clock(); + if (retval != ERROR_OK) + return retval; + + return ch347_cmd_transmit_queue(); +} + +/** + * @brief Flushes the command buffer and sleeps for a specific timespan + * + * @param us Sleep time in microseconds + * @return ERROR_OK at success + */ +static int ch347_sleep(int us) +{ + LOG_DEBUG_IO("us=%d", us); + int retval = ch347_cmd_transmit_queue(); + jtag_sleep(us); + return retval; +} + +/** + * @brief Executes the command queue + * + * @return Success returns ERROR_OK + */ +static int ch347_execute_queue(struct jtag_command *cmd_queue) +{ + struct jtag_command *cmd = cmd_queue; + + int retval = ch347_activity_led_set(LED_ON); + if (retval != ERROR_OK) + return retval; + + while (retval == ERROR_OK && cmd) { + switch (cmd->type) { + case JTAG_RUNTEST: + retval = ch347_scratchpad_add_run_test(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); + break; + case JTAG_STABLECLOCKS: + retval = ch347_scratchpad_add_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + case JTAG_TLR_RESET: + retval = ch347_scratchpad_add_move_state(cmd->cmd.statemove->end_state, 0); + break; + case JTAG_PATHMOVE: + retval = ch347_scratchpad_add_move_path(cmd->cmd.pathmove); + break; + case JTAG_TMS: + retval = ch347_scratchpad_add_tms_change(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, 0); + break; + case JTAG_SLEEP: + retval = ch347_sleep(cmd->cmd.sleep->us); + break; + case JTAG_SCAN: + retval = ch347_scratchpad_add_scan(cmd->cmd.scan); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", cmd->type); + retval = ERROR_FAIL; + break; + } + + cmd = cmd->next; + } + + if (retval != ERROR_OK) + return retval; + + retval = ch347_cmd_transmit_queue(); + if (retval != ERROR_OK) + return retval; + + return ch347_activity_led_set(LED_OFF); +} + +/** + * @brief opens the CH347 device via libusb driver + * + * @return ERROR_OK on success + */ +static int ch347_open_device(void) +{ + const uint16_t *ch347_vids = custom_ch347_vids[0] != 0 ? custom_ch347_vids : default_ch347_vids; + const uint16_t *ch347_pids = custom_ch347_pids[0] != 0 ? custom_ch347_pids : default_ch347_pids; + + int retval = jtag_libusb_open(ch347_vids, ch347_pids, ch347_device_desc, &ch347_handle, NULL); + if (retval != ERROR_OK) { + char error_message[256]; + snprintf(error_message, sizeof(error_message), "CH347 not found. Tried VID/PID pairs: "); + for (int i = 0; ch347_vids[i] != 0; i++) + snprintf(error_message + strlen(error_message), sizeof(error_message) - strlen(error_message), + "%04x:%04x ", ch347_vids[i], ch347_pids[i]); + + LOG_ERROR("%s", error_message); + return retval; + } + + struct libusb_device_descriptor ch347_device_descriptor; + libusb_device *device = libusb_get_device(ch347_handle); + if (!device) { + LOG_ERROR("CH347 error calling libusb_get_device"); + jtag_libusb_close(ch347_handle); + return ERROR_FAIL; + } + + retval = libusb_get_device_descriptor(device, &ch347_device_descriptor); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 error getting device descriptor: %s", libusb_error_name(retval)); + jtag_libusb_close(ch347_handle); + return retval; + } + + // CH347T / CH347F detection + // if we can claim interface 4 we found a CH347F chip; if we can claim interface 2 we found CH347T chip + retval = libusb_claim_interface(ch347_handle, CH347F_MPHSI_INTERFACE); + if (retval != ERROR_OK) { + retval = libusb_claim_interface(ch347_handle, CH347T_MPHSI_INTERFACE); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 unable to claim interface: %s", libusb_error_name(retval)); + jtag_libusb_close(ch347_handle); + return retval; + } + ch347.chip_variant = CH347T; + } else { + ch347.chip_variant = CH347F; + } + + char firmware_version; + retval = jtag_libusb_control_transfer(ch347_handle, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + VENDOR_VERSION, 0, 0, &firmware_version, sizeof(firmware_version), + USB_WRITE_TIMEOUT, NULL); + if (retval != ERROR_OK) { + LOG_ERROR("CH347 unable to get firmware version"); + jtag_libusb_close(ch347_handle); + return retval; + } + + char manufacturer[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iManufacturer, + (unsigned char *)manufacturer, sizeof(manufacturer) - 1) < 0) { + strcpy(manufacturer, "(unknown)"); + } + char product[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iProduct, + (unsigned char *)product, sizeof(product) - 1) < 0) { + strcpy(product, "(unknown)"); + } + char serial_number[256 + 1]; + if (libusb_get_string_descriptor_ascii(ch347_handle, ch347_device_descriptor.iSerialNumber, + (unsigned char *)serial_number, sizeof(serial_number) - 1) < 0) { + strcpy(serial_number, "(unknown)"); + } + + LOG_INFO("CH347 %s from vendor %s with serial number %s found. (Chip version=%X.%2X, Firmware=0x%02X)", + product, + manufacturer, + serial_number, + (ch347_device_descriptor.bcdDevice >> 8) & 0xFF, + ch347_device_descriptor.bcdDevice & 0xFF, + firmware_version); + + if (ch347.chip_variant == CH347T && ch347_device_descriptor.bcdDevice < BYTEWISE_MODE_VERSION) { + LOG_INFO("CH347T old version of the chip, JTAG only working in bitwise mode. For bytewise mode at least version %X.%X is needed.", + (BYTEWISE_MODE_VERSION >> 8) & 0xFF, + BYTEWISE_MODE_VERSION & 0xFF); + ch347.use_bitwise_mode = true; + } else { + ch347.use_bitwise_mode = false; + } + + if (ch347.chip_variant == CH347T) { + if (swd_mode) { + ch347.swclk_5mhz_supported = ch347_device_descriptor.bcdDevice >= 0x544; + + if (ch347_device_descriptor.bcdDevice < 0x441) + LOG_WARNING("CH347T version older than 4.41 probably does not support SWD transport"); + + if (ch347_device_descriptor.bcdDevice == 0x441) + LOG_WARNING("If CH347T version 4.41 cannot connect or SWD fails often, insert a resistor to SWDIO circuit"); + + } else if (ch347_device_descriptor.bcdDevice == 0x241) { + LOG_WARNING("CH347T version 2.41 has very weird clock timing, may not work with a slower JTAG device"); + } + + if (ch347_device_descriptor.bcdDevice < 0x544) + LOG_INFO("Please upgrade CH347T firmware to a production version >= 5.44"); + + } else if (ch347.chip_variant == CH347F) { + ch347.swclk_5mhz_supported = ch347_device_descriptor.bcdDevice >= 0x101; + + if (ch347_device_descriptor.bcdDevice < 0x101) + LOG_INFO("Please upgrade CH347F firmware to a production version >= 1.1"); + } + + return ERROR_OK; +} + +/** + * @brief CH347 Device Release Function + * + * @return ERROR_OK on success + */ +static int ch347_quit(void) +{ + // on close set the LED on, because the state without JTAG is on + ch347_activity_led_set(LED_ON); + int retval = ch347_cmd_transmit_queue(); + jtag_libusb_close(ch347_handle); + LOG_DEBUG_IO("CH347 close"); + return retval; +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to get the JTAG + * interface initialized with the speed index or asking with special clock index 9 + * for the LARGER_PACK mode support + * + * @param clock_index Clock index; special clock index 9 is used for checking + * if the device supports the LARGER_PACK mode + * @param supports_larger_pack_mode returns true if the device supports the LARGER_PACK mode + * for newer CH347 devices; false if the device supports only the older STANDARD_PACK mode + * @return ERROR_OK on success + */ +static int ch347_adapter_init(uint8_t clock_index, bool *supports_larger_pack_mode) +{ + int retval = ch347_cmd_start_next(CH347_CMD_JTAG_INIT); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_byte(0); + if (retval != ERROR_OK) + return retval; + + retval = ch347_scratchpad_add_byte(clock_index); + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < 4; i++) { + retval = ch347_scratchpad_add_pin_byte(); + if (retval != ERROR_OK) + return retval; + } + + uint8_t mode; + retval = ch347_single_read_get_byte(0, &mode); + if (retval != ERROR_OK) + return retval; + + *supports_larger_pack_mode = mode != 0; + return ERROR_OK; +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to ask the JTAG + * interface with special clock index 9 for the LARGER_PACK mode support + * + * @param supports_larger_pack_mode returns true if the device supports the LARGER_PACK mode + * for newer CH347 devices; false if the device supports only the older STANDARD_PACK mode + * @return ERROR_OK on success + */ +static int ch347_adapter_supports_larger_pack_mode(bool *supports_larger_pack_mode) +{ + return ch347_adapter_init(CH347_CMD_INIT_GET_MODE_CLOCK_INDEX_VALUE, supports_larger_pack_mode); +} + +/** + * @brief Sends the CH347_CMD_JTAG_INIT (D0) command to get the JTAG + * interface initialized with the speed index + * + * @param clock_index Clock index + * @return ERROR_OK on success + */ +static int ch347_adapter_set_speed(uint8_t clock_index) +{ + bool unused; + return ch347_adapter_init(clock_index, &unused); +} + +/** + * @brief swd init function + * @param clock_divisor Divisor of base SWD frequency 1 MHz or 0 for fast 5 MHz clock + * + * @return ERROR_OK on success + */ +static int ch347_swd_init_cmd(uint8_t clock_divisor) +{ + int retval = ch347_cmd_start_next(CH347_CMD_SWD_INIT); + if (retval != ERROR_OK) + return retval; + + uint8_t cmd_data[] = {0x40, 0x42, 0x0f, 0x00, clock_divisor, 0x00, 0x00, 0x00 }; + retval = ch347_scratchpad_add_bytes(cmd_data, ARRAY_SIZE(cmd_data)); + if (retval != ERROR_OK) + return retval; + + /* TODO: CH347_CMD_SWD_INIT reads one data byte. + But how can we decide if SWD init was successfully executed? + Return an error code if init was failed */ + uint8_t init_result = 0; + retval = ch347_single_read_get_byte(0, &init_result); + LOG_DEBUG("SWD init clk div %" PRIu8 ", result %02" PRIx8, + clock_divisor, init_result); + ch347_swd_context.clk_divisor = clock_divisor; + return retval; +} + +/** + * @brief Initializes the JTAG interface and set CH347 TCK frequency + * + * @param speed_index speed index for JTAG_INIT command + * @return Success returns ERROR_OK, failed returns ERROR_FAIL + */ +static int ch347_speed_set(int speed_index) +{ + if (swd_mode) + return ch347_swd_init_cmd(speed_index); + + int retval = ch347_adapter_set_speed(speed_index); + if (retval != ERROR_OK) { + LOG_ERROR("Couldn't set CH347 speed"); + return retval; + } + + return ERROR_OK; +} + +/** + * @brief inits ch347.pack_size and ch347.max_len + * + * @return ERROR_OK on success + */ +static int ch347_init_pack_size(void) +{ + // already set? + if (ch347.pack_size != UNSET) + return ERROR_OK; + + // set the lower limit for starting + ch347.max_len = MIN(USBC_PACKET_USBHS, LARGER_PACK_MAX_SIZE); + bool supports_larger_pack_mode; + int retval = ch347_adapter_supports_larger_pack_mode(&supports_larger_pack_mode); + if (retval != ERROR_OK) + return retval; + + ch347.pack_size = supports_larger_pack_mode ? LARGER_PACK : STANDARD_PACK; + ch347.max_len = ch347.pack_size == STANDARD_PACK || ch347.use_bitwise_mode ? + USBC_PACKET_USBHS : LARGER_PACK_MAX_SIZE; + return ERROR_OK; +} + +/** + * @brief returns the speed in kHz by the give speed index + * + * @param speed_idx CH347 speed index + * @param khz Output of the speed in kHz + * @return ERROR_OK on success + */ +static int ch347_speed_get(int speed_idx, int *khz) +{ + if (swd_mode) { + if (speed_idx) + *khz = DIV_ROUND_UP(CH347_SWD_CLOCK_BASE, speed_idx); + else + *khz = CH347_SWD_CLOCK_MAX; + return ERROR_OK; + } + + int retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + const int *speeds = ch347.pack_size == STANDARD_PACK ? + ch347_standard_pack_clock_speeds : ch347_larger_pack_clock_speeds; + *khz = speeds[speed_idx]; + return ERROR_OK; +} + +/** + * @brief multiplies the input speed by 1000 + * + * @param khz Speed in kHz + * @param speed_idx CH347 speed index + * @return ERROR_OK at success; ERROR_FAIL if khz is zero + */ +static int ch347_speed_get_index(int khz, int *speed_idx) +{ + if (khz == 0) { + LOG_ERROR("Adaptive clocking not supported"); + return ERROR_FAIL; + } + + if (swd_mode) { + if (khz >= CH347_SWD_CLOCK_MAX && ch347.swclk_5mhz_supported) { + *speed_idx = 0; + } else { + // Don't allow too low clk speeds: packet processing is limited to ~8 msec + // or triggers host USB disconnect + *speed_idx = MIN(DIV_ROUND_UP(CH347_SWD_CLOCK_BASE, khz), + (int)CH347_SWD_CLOCK_MAX_DIVISOR); + } + return ERROR_OK; + } + + // when checking with speed index 9 we can see if the device supports STANDARD_PACK or LARGER_PACK mode + int retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + // depending on pack size there are different fixed clock speeds possible + const int *speeds = ch347.pack_size == STANDARD_PACK ? + ch347_standard_pack_clock_speeds : ch347_larger_pack_clock_speeds; + int length = ch347.pack_size == STANDARD_PACK ? + ARRAY_SIZE(ch347_standard_pack_clock_speeds) : ARRAY_SIZE(ch347_larger_pack_clock_speeds); + int idx = -1; + int lower_bound = 0; + // find the suitable speed index + for (int i = 0; i < length; i++) { + if (khz >= lower_bound && khz <= speeds[i]) { + idx = i; + break; + } + lower_bound = speeds[i]; + } + // too high! => use max possible speed + if (idx == -1) { + LOG_INFO("Speed %d kHz is higher than highest speed of %d kHz. Using %d khz!", + khz, speeds[length - 1], speeds[length - 1]); + idx = length - 1; + } else if (speeds[idx] != khz) { + LOG_INFO("Requested speed of %d kHz is not possible. Using the next higher speed of %d kHz!", + khz, speeds[idx]); + } + *speed_idx = idx; + return ERROR_OK; +} + +/** + * @brief The command handler for setting the device usb vid/pid + * + * @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise + */ +COMMAND_HANDLER(ch347_handle_vid_pid_command) +{ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (int i = 0; i < (int)(MIN(CMD_ARGC, ARRAY_SIZE(custom_ch347_pids))); i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], custom_ch347_vids[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], custom_ch347_pids[i / 2]); + } + + return ERROR_OK; +} + +/** + * @brief The command handler for setting the device description that should be found + * + * @return ERROR_OK at success; ERROR_COMMAND_SYNTAX_ERROR otherwise + */ +COMMAND_HANDLER(ch347_handle_device_desc_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(ch347_device_desc); + ch347_device_desc = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +static const struct command_registration ch347_subcommand_handlers[] = { + { + .name = "vid_pid", + .handler = &ch347_handle_vid_pid_command, + .mode = COMMAND_CONFIG, + .help = "the vendor ID and product ID of the CH347 device", + .usage = "(vid pid)*", + }, + { + .name = "device_desc", + .handler = &ch347_handle_device_desc_command, + .mode = COMMAND_CONFIG, + .help = "set the USB device description of the CH347 device", + .usage = "description_string", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration ch347_command_handlers[] = { + { + .name = "ch347", + .mode = COMMAND_ANY, + .help = "perform ch347 management", + .chain = ch347_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +/** + * @brief Configure which GPIO pin is used as the activity LED. + * + * Updates the global activity LED GPIO pin and polarity settings + * based on the provided configuration. If the given GPIO is not + * usable, the function returns without making changes. + * + * @param led_config Pointer to the GPIO configuration structure for the LED pin + */ +static void ch347_configure_activity_led(const struct adapter_gpio_config *led_config) +{ + uint8_t gpio = led_config->gpio_num; + if (gpio >= GPIO_CNT || (BIT(gpio) & USEABLE_GPIOS) == 0) + return; + + ch347_activity_led_gpio_pin = gpio; + ch347_activity_led_active_high = !led_config->active_low; +} + +/** + * @brief CH347 Initialization function + * + * @return ERROR_OK on success + */ +static int ch347_init(void) +{ + int retval = ch347_open_device(); + + if (retval != ERROR_OK) { + LOG_ERROR("CH347 open error"); + return retval; + } + + LOG_DEBUG_IO("CH347 open success"); + + // CH347 JTAG init + ch347.tck_pin = TCK_L; + ch347.tms_pin = TMS_H; + ch347.tdi_pin = TDI_L; + ch347.trst_pin = TRST_H; + INIT_LIST_HEAD(&ch347.cmd_queue); + INIT_LIST_HEAD(&ch347.scan_queue); + + ch347.pack_size = UNSET; + + ch347_configure_activity_led(&adapter_gpio_get_config()[ADAPTER_GPIO_IDX_LED]); + + if (!swd_mode) { + tap_set_state(TAP_RESET); + } else { + retval = ch347_init_pack_size(); + if (retval != ERROR_OK) + return retval; + + retval = ch347_swd_init_cmd(1); + } + return retval; +} + +/** + * @brief Initialization for the swd mode + * + * @return Always ERROR_OK + */ +static int ch347_swd_init(void) +{ + LOG_INFO("CH347 SWD mode enabled"); + swd_mode = true; + memset(&ch347_swd_context, 0, sizeof(ch347_swd_context)); + + INIT_LIST_HEAD(&ch347_swd_context.send_cmd_head); + INIT_LIST_HEAD(&ch347_swd_context.free_cmd_head); + + ch347_swd_context.queued_retval = ERROR_OK; + // 0XE8 + 2byte len + N byte cmds + ch347_swd_context.send_len = CH347_CMD_HEADER; + // 0XE8 + 2byte len + N byte ack + data + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + struct ch347_swd_io *pswd_io = ch347_swd_context.ch347_cmd_buf; + for (int i = 0; i < CH347_MAX_CMD_BUF; i++, pswd_io++) { + INIT_LIST_HEAD(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.free_cmd_head); + } + return ERROR_OK; +} + +static struct ch347_swd_io *ch347_get_one_swd_io(void) +{ + struct ch347_swd_io *pswd_io; + if (list_empty(&ch347_swd_context.free_cmd_head)) + return NULL; + + pswd_io = list_first_entry(&ch347_swd_context.free_cmd_head, + struct ch347_swd_io, list_entry); + list_del_init(&pswd_io->list_entry); + pswd_io->cmd = 0; + pswd_io->usb_cmd = CH347_CMD_SWD_SEQ_W; + pswd_io->dst = NULL; + return pswd_io; +} + +static int ch347_swd_queue_flush(void) +{ + int length = ch347_swd_context.send_len; + ch347_swd_context.send_buf[0] = CH347_CMD_SWD; + h_u16_to_le(&ch347_swd_context.send_buf[1], length - CH347_CMD_HEADER); + int retval = ch347_write_data(ch347_swd_context.send_buf, &length); + if (retval != ERROR_OK) { + ch347_swd_context.queued_retval = retval; + LOG_DEBUG("CH347WriteData error"); + return retval; + } + + ch347_swd_context.recv_len = 0; + length = ch347_swd_context.need_recv_len; + retval = ch347_read_data(&ch347_swd_context.recv_buf[ch347_swd_context.recv_len], &length); + if (retval != ERROR_OK) { + ch347_swd_context.queued_retval = retval; + LOG_DEBUG("CH347ReadData error"); + return retval; + } + + ch347_swd_context.recv_len += length; + if (ch347_swd_context.need_recv_len > ch347_swd_context.recv_len) { + LOG_ERROR("write/read failed %d %d", + ch347_swd_context.recv_len, + ch347_swd_context.need_recv_len); + retval = ERROR_FAIL; + } + + return retval; +} + +static void ch347_write_swd_reg(uint8_t cmd, const uint32_t out) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_W; + // 8bit + 32bit +1bit + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x29; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + h_u32_to_le(&ch347_swd_context.send_buf[ch347_swd_context.send_len], out); + ch347_swd_context.send_len += 4; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity_u32(out); + // 0xA0 + 1 byte(3bit ACK) + ch347_swd_context.need_recv_len += (1 + 1); + ch347_swd_context.total_swd_clk += 46; +} + +static void ch347_write_spec_seq(const uint8_t *out, uint8_t out_len) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = + CH347_CMD_SWD_SEQ_W; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out_len; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + for (uint8_t i = 0; i < DIV_ROUND_UP(out_len, 8); i++) + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out ? out[i] : 0x00; + ch347_swd_context.need_recv_len += 1; // 0xA1 + ch347_swd_context.total_swd_clk += out_len; +} + +static void ch347_read_swd_reg(uint8_t cmd) +{ + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = CH347_CMD_SWD_REG_R; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x22; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = 0x00; + ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd; + // 0xA2 + 1 byte(3bit ACK) + 4 byte(data) + 1 byte(1bit parity+1bit trn) + ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1; + ch347_swd_context.total_swd_clk += 46; +} + +static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, unsigned int out_len) +{ + if ((ch347_swd_context.send_len + (1 + 2 + DIV_ROUND_UP(out_len, 8))) > CH347_MAX_SEND_BUF) + return ERROR_FAIL; + if ((ch347_swd_context.need_recv_len + 2) > CH347_MAX_RECV_BUF) + return ERROR_FAIL; + + struct ch347_swd_io *pswd_io = ch347_get_one_swd_io(); + if (pswd_io) { + ch347_write_spec_seq(out, out_len); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + return ERROR_OK; + } else { + return ERROR_FAIL; + } +} + +// check read/write REG can fill in remaining buff +static bool ch347_chk_buf_size(uint8_t cmd, uint32_t ap_delay_clk) +{ + bool flush = false; + int send_len = ch347_swd_context.send_len; + int recv_len = ch347_swd_context.need_recv_len; + int len; + do { + if (cmd & SWD_CMD_RNW) { + len = 1 + 1 + 1 + 1; // 0xA2 + len + rev + cmd + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1 + 4 + 1; + /* 0xA2 + 1byte(3bit ack) + 4byte(data) + + 1byte(1bit parity+1bit trn) */ + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } else { // write reg + len = 1 + 1 + 1 + 1 + 4 + 1; + // 0xA0 + len + rev + cmd +data + parity + if (send_len + len > CH347_MAX_SEND_BUF) + break; + send_len += len; + len = 1 + 1; // 0xA0 + 1byte(3bit ack) + if (recv_len + len > CH347_MAX_RECV_BUF) + break; + recv_len += len; + } + if (cmd & SWD_CMD_APNDP) { + len = 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); + // 0xA1 + Len + rev + n byte(delay) + if (send_len + len > CH347_MAX_SEND_BUF) + break; + len = 1; // 0xA1 + if ((recv_len + len) > CH347_MAX_RECV_BUF) + break; + } + // swd packet requests + flush = true; + } while (false); + + return flush; +} + +static int ch347_swd_run_queue_inner(void); + +static int ch347_swd_send_idle(uint32_t ap_delay_clk) +{ + bool run_q = false; + struct ch347_swd_io *pswd_io = NULL; + unsigned int max_processing_clk = ch347_swd_context.clk_divisor + ? CH347_MAX_PROCESSING_US / ch347_swd_context.clk_divisor + : CH347_MAX_PROCESSING_US * 5; + bool more_q_runs = + 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8) > CH347_MAX_SEND_BUF + && ap_delay_clk > max_processing_clk; + + if (ch347_swd_context.sent_cmd_count) { + unsigned int expected_total_clk = ch347_swd_context.total_swd_clk + ap_delay_clk; + unsigned int expected_send_len = ch347_swd_context.send_len + + 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8); + // 0xA1 + Len + rev + n byte(delay) + unsigned int expected_recv_len = ch347_swd_context.need_recv_len + 1; + // 0xA1 + unsigned int expected_time = ch347_swd_context.clk_divisor + ? expected_total_clk * ch347_swd_context.clk_divisor + : expected_total_clk / 5; + if (expected_time > CH347_MAX_PROCESSING_US + || expected_send_len > CH347_MAX_SEND_BUF + || expected_recv_len > CH347_MAX_RECV_BUF) { + int send_room = CH347_MAX_SEND_BUF - ch347_swd_context.send_len - 1 - 1 - 1; + if (more_q_runs + && send_room > 0 + && expected_recv_len <= CH347_MAX_RECV_BUF + && ch347_swd_context.total_swd_clk < max_processing_clk) { + pswd_io = ch347_get_one_swd_io(); + if (pswd_io) { + // fill the rest of queue/time by part of delay + unsigned int this_delay_clk = MIN(ap_delay_clk, 255); + if ((unsigned int)send_room * 8 < this_delay_clk) + this_delay_clk = send_room * 8; + if (max_processing_clk - ch347_swd_context.total_swd_clk < this_delay_clk) + this_delay_clk = max_processing_clk - ch347_swd_context.total_swd_clk; + LOG_DEBUG_IO("partial delay %u clk", this_delay_clk); + ch347_write_spec_seq(NULL, this_delay_clk); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + ap_delay_clk -= this_delay_clk; + } + } + run_q = true; + } + } + + do { + if (!run_q) + pswd_io = ch347_get_one_swd_io(); + + if (!pswd_io) { + int retval = ch347_swd_run_queue_inner(); + if (retval != ERROR_OK) + return retval; + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue"); + ch347_swd_context.queued_retval = ERROR_FAIL; + return ERROR_FAIL; + } + } + + unsigned int send_room = CH347_MAX_SEND_BUF - 1 - 1 - 1; + unsigned int this_delay_clk = MIN(ap_delay_clk, 255); + if (send_room * 8 < this_delay_clk) + this_delay_clk = send_room * 8; + if (max_processing_clk < this_delay_clk) + this_delay_clk = max_processing_clk; + LOG_DEBUG_IO("delay %u clk", this_delay_clk); + ch347_write_spec_seq(NULL, this_delay_clk); + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + ap_delay_clk -= this_delay_clk; + run_q = true; + pswd_io = NULL; + } while (ap_delay_clk); + return ERROR_OK; +} + +static int ch347_swd_run_queue_inner(void) +{ + LOG_DEBUG_IO("Executing %u queued transactions", ch347_swd_context.sent_cmd_count); + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_DEBUG_IO("Skipping due to previous errors: %d", ch347_swd_context.queued_retval); + goto skip; + } + + int retval = ch347_swd_queue_flush(); + if (retval != ERROR_OK) + return retval; + + if (ch347_swd_context.queued_retval != ERROR_OK) { + LOG_ERROR("CH347 usb write/read failed - queued_retval"); + goto skip; + } + uint8_t *recv_buf = ch347_swd_context.recv_buf; + int recv_len = 0; + if (recv_buf[recv_len++] != CH347_CMD_SWD) { // 0XE8 + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not CH347_CMD_SWD"); + goto skip; + } + + int cmds_len = le_to_h_u16(&recv_buf[recv_len]); + recv_len += 2; // cmds_len + if ((cmds_len + CH347_CMD_HEADER) > ch347_swd_context.recv_len) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - too long"); + goto skip; + } + + struct list_head *tmp; + struct list_head *pos; + struct ch347_swd_io *pswd_io; + + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { + pswd_io = list_entry(pos, struct ch347_swd_io, list_entry); + if (pswd_io->usb_cmd == CH347_CMD_SWD_SEQ_W) { + if (recv_buf[recv_len++] != CH347_CMD_SWD_SEQ_W) { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not CH347_CMD_SWD_SEQ_W"); + goto skip; + } + } else { // read/write Reg + uint32_t ack; + bool check_ack; + // read Reg + if (recv_buf[recv_len] == CH347_CMD_SWD_REG_R) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + if (pswd_io->cmd & SWD_CMD_RNW) { + uint32_t data = buf_get_u32(&recv_buf[recv_len], 0, 32); + + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) + ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s read reg %X = %08" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : + ack == SWD_ACK_WAIT ? "WAIT" : + ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + data); + + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); + goto skip; + } + + uint32_t parity = buf_get_u32(&recv_buf[recv_len], 32, 1); + if (parity != (uint32_t)parity_u32(data)) { + LOG_ERROR("SWD Read data parity mismatch"); + ch347_swd_context.queued_retval = ERROR_FAIL; + goto skip; + } + + if (pswd_io->dst) + *pswd_io->dst = data; + } else { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed - not SWD_CMD_RNW"); + goto skip; + } + recv_len += 5; + } else if (recv_buf[recv_len] == CH347_CMD_SWD_REG_W) { + recv_len++; + ack = buf_get_u32(&recv_buf[recv_len++], 0, 3); + /* Devices do not reply to DP_TARGETSEL write + cmd, ignore received ack */ + check_ack = swd_cmd_returns_ack(pswd_io->cmd); + + LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK) + ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO, + "%s%s %s write reg %X = %08" PRIx32, + check_ack ? "" : "ack ignored ", + ack == SWD_ACK_OK ? "OK" : + ack == SWD_ACK_WAIT ? "WAIT" : + ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", + pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP", + (pswd_io->cmd & SWD_CMD_A32) >> 1, + pswd_io->value); + + if (ack != SWD_ACK_OK && check_ack) { + ch347_swd_context.queued_retval = swd_ack_to_error_code(ack); + goto skip; + } + } else { + ch347_swd_context.queued_retval = ERROR_FAIL; + LOG_ERROR("CH347 usb write/read failed recv_len = %d", recv_len); + goto skip; + } + } + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + +skip: + if (!list_empty(&ch347_swd_context.send_cmd_head)) { + list_for_each_safe(pos, tmp, &ch347_swd_context.send_cmd_head) { + pswd_io = list_entry(pos, struct ch347_swd_io, list_entry); + list_del_init(&pswd_io->list_entry); + list_add_tail(&pswd_io->list_entry, + &ch347_swd_context.free_cmd_head); + } + } + + // 0xE8 + 2byte len + ch347_swd_context.send_len = CH347_CMD_HEADER; + // 0xE8 + 2byte len + ch347_swd_context.need_recv_len = CH347_CMD_HEADER; + ch347_swd_context.recv_len = 0; + ch347_swd_context.sent_cmd_count = 0; + ch347_swd_context.total_swd_clk = 0; + retval = ch347_swd_context.queued_retval; + ch347_swd_context.queued_retval = ERROR_OK; + return retval; +} + +static int ch347_swd_run_queue(void) +{ + /* A transaction must be followed by another transaction or at least 8 + idle cycles to ensure that data is clocked through the AP. */ + int retval = ch347_swd_send_idle(8); + if (retval != ERROR_OK) + return retval; + + return ch347_swd_run_queue_inner(); +} + +static int ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk) +{ + int retval = ERROR_OK; + bool run_q = false; + if (ch347_swd_context.sent_cmd_count) { + unsigned int expected_total_clk = ch347_swd_context.total_swd_clk + + 46 // SWD transaction + + ap_delay_clk + + 8; // 8 idle cycles at the end of queue + unsigned int expected_time = ch347_swd_context.clk_divisor + ? expected_total_clk * ch347_swd_context.clk_divisor + : expected_total_clk / 5; + if (expected_time > CH347_MAX_PROCESSING_US) { + LOG_DEBUG_IO("Expected queue run %u cycles, with this cmd %u", + ch347_swd_context.total_swd_clk, expected_total_clk); + run_q = true; + } else if (!ch347_chk_buf_size(cmd, ap_delay_clk)) { + run_q = true; + } + } + + struct ch347_swd_io *pswd_io = NULL; + if (!run_q) + pswd_io = ch347_get_one_swd_io(); + + if (!pswd_io) { + retval = ch347_swd_run_queue_inner(); + if (retval != ERROR_OK) + return retval; + + pswd_io = ch347_get_one_swd_io(); + if (!pswd_io) { + LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue"); + ch347_swd_context.queued_retval = ERROR_FAIL; + return ERROR_FAIL; + } + } + + pswd_io->cmd = cmd | SWD_CMD_START | SWD_CMD_PARK; + + if (pswd_io->cmd & SWD_CMD_RNW) { + pswd_io->usb_cmd = CH347_CMD_SWD_REG_R; + pswd_io->dst = dst; + ch347_read_swd_reg(pswd_io->cmd); + } else { + pswd_io->usb_cmd = CH347_CMD_SWD_REG_W; + pswd_io->value = data; + ch347_write_swd_reg(pswd_io->cmd, data); + } + + ch347_swd_context.sent_cmd_count++; + list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head); + + // Insert idle cycles after AP accesses to avoid WAIT + if (ap_delay_clk) + retval = ch347_swd_send_idle(ap_delay_clk); + + return retval; +} + +static int ch347_swd_switch_seq(enum swd_special_seq seq) +{ + switch (seq) { + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + return ch347_swd_switch_out(seq, swd_seq_line_reset, swd_seq_line_reset_len); + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_swd, swd_seq_jtag_to_swd_len); + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_jtag_to_dormant, swd_seq_jtag_to_dormant_len); + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_jtag, swd_seq_swd_to_jtag_len); + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + return ch347_swd_switch_out(seq, swd_seq_swd_to_dormant, swd_seq_swd_to_dormant_len); + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_swd, swd_seq_dormant_to_swd_len); + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + return ch347_swd_switch_out(seq, swd_seq_dormant_to_jtag, swd_seq_dormant_to_jtag_len); + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; + } +} + +static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + assert(cmd & SWD_CMD_RNW); + int retval = ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk); + if (retval != ERROR_OK) + ch347_swd_context.queued_retval = retval; +} + +static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk) +{ + assert(!(cmd & SWD_CMD_RNW)); + int retval = ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk); + if (retval != ERROR_OK) + ch347_swd_context.queued_retval = retval; +} + +static const struct swd_driver ch347_swd = { + .init = ch347_swd_init, + .switch_seq = ch347_swd_switch_seq, + .read_reg = ch347_swd_read_reg, + .write_reg = ch347_swd_write_reg, + .run = ch347_swd_run_queue, +}; + +static struct jtag_interface ch347_interface = { + .supported = DEBUG_CAP_TMS_SEQ, + .execute_queue = ch347_execute_queue, +}; + +struct adapter_driver ch347_adapter_driver = { + .name = "ch347", + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, + .commands = ch347_command_handlers, + + .init = ch347_init, + .quit = ch347_quit, + .reset = ch347_reset, + .speed = ch347_speed_set, + .khz = ch347_speed_get_index, + .speed_div = ch347_speed_get, + + .jtag_ops = &ch347_interface, + .swd_ops = &ch347_swd, +}; diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 2bfcfcc2b0..9f60a5ede4 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -37,7 +37,8 @@ #include #include "cmsis_dap.h" -#include "libusb_helper.h" + +#define TIMEOUT_MS 6000 /* Create a dummy backend for 'backend' command if real one does not build */ #if BUILD_CMSIS_DAP_USB == 0 @@ -52,9 +53,16 @@ const struct cmsis_dap_backend cmsis_dap_hid_backend = { }; #endif +#if BUILD_CMSIS_DAP_TCP == 0 +const struct cmsis_dap_backend cmsis_dap_tcp_backend = { + .name = "tcp" +}; +#endif + static const struct cmsis_dap_backend *const cmsis_dap_backends[] = { &cmsis_dap_usb_backend, &cmsis_dap_hid_backend, + &cmsis_dap_tcp_backend, }; /* USB Config */ @@ -76,6 +84,7 @@ static uint16_t cmsis_dap_vid[MAX_USB_IDS + 1] = { 0 }; static uint16_t cmsis_dap_pid[MAX_USB_IDS + 1] = { 0 }; static int cmsis_dap_backend = -1; static bool swd_mode; +static bool cmsis_dap_quirk_mode; /* enable expensive workarounds */ /* CMSIS-DAP General Commands */ #define CMD_DAP_INFO 0x00 @@ -355,12 +364,12 @@ static int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen) } uint8_t current_cmd = dap->command[0]; - int retval = dap->backend->write(dap, txlen, LIBUSB_TIMEOUT_MS); + int retval = dap->backend->write(dap, txlen, TIMEOUT_MS); if (retval < 0) return retval; /* get reply */ - retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, CMSIS_DAP_BLOCKING); + retval = dap->backend->read(dap, TIMEOUT_MS, CMSIS_DAP_BLOCKING); if (retval < 0) return retval; @@ -864,13 +873,13 @@ static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap) } } - int retval = dap->backend->write(dap, idx, LIBUSB_TIMEOUT_MS); + int retval = dap->backend->write(dap, idx, TIMEOUT_MS); if (retval < 0) { queued_retval = retval; goto skip; } - unsigned int packet_count = dap->quirk_mode ? 1 : dap->packet_count; + unsigned int packet_count = cmsis_dap_quirk_mode ? 1 : dap->packet_count; dap->pending_fifo_put_idx = (dap->pending_fifo_put_idx + 1) % packet_count; dap->pending_fifo_block_count++; if (dap->pending_fifo_block_count > packet_count) @@ -905,7 +914,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo } /* get reply */ - retval = dap->backend->read(dap, LIBUSB_TIMEOUT_MS, blocking); + retval = dap->backend->read(dap, TIMEOUT_MS, blocking); bool timeout = (retval == ERROR_TIMEOUT_REACHED || retval == 0); if (timeout && blocking == CMSIS_DAP_NON_BLOCKING) return; @@ -990,7 +999,7 @@ static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, enum cmsis_dap_blo skip: block->transfer_count = 0; - if (!dap->quirk_mode && dap->packet_count > 1) + if (!cmsis_dap_quirk_mode && dap->packet_count > 1) dap->pending_fifo_get_idx = (dap->pending_fifo_get_idx + 1) % dap->packet_count; dap->pending_fifo_block_count--; } @@ -1086,7 +1095,7 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data) /* Not enough room in the queue. Run the queue. */ cmsis_dap_swd_write_from_queue(cmsis_dap_handle); - unsigned int packet_count = cmsis_dap_handle->quirk_mode ? 1 : cmsis_dap_handle->packet_count; + unsigned int packet_count = cmsis_dap_quirk_mode ? 1 : cmsis_dap_handle->packet_count; if (cmsis_dap_handle->pending_fifo_block_count >= packet_count) cmsis_dap_swd_read_process(cmsis_dap_handle, CMSIS_DAP_BLOCKING); } @@ -1230,7 +1239,7 @@ static int cmsis_dap_swd_switch_seq(enum swd_special_seq seq) if (swd_mode) queued_retval = cmsis_dap_swd_run_queue(); - if (cmsis_dap_handle->quirk_mode && seq != LINE_RESET && + if (cmsis_dap_quirk_mode && seq != LINE_RESET && (output_pins & (SWJ_PIN_SRST | SWJ_PIN_TRST)) == (SWJ_PIN_SRST | SWJ_PIN_TRST)) { /* Following workaround deasserts reset on most adapters. @@ -1558,38 +1567,38 @@ static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) printf(" %02x", cmd[i]); printf("\n"); switch (cmd[0]) { - case CMD_DAP_JTAG_SEQ: { - printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); - /* - * #1 = number of sequences - * #2 = sequence info 1 - * #3...4+n_bytes-1 = sequence 1 - * #4+n_bytes = sequence info 2 - * #5+n_bytes = sequence 2 (single bit) - */ - int pos = 2; - for (int seq = 0; seq < cmd[1]; ++seq) { - uint8_t info = cmd[pos++]; - int len = info & DAP_JTAG_SEQ_TCK; - if (len == 0) - len = 64; - printf(" sequence %d starting %d: info %02x (len=%d tms=%d read_tdo=%d): ", - seq, pos, info, len, info & DAP_JTAG_SEQ_TMS, info & DAP_JTAG_SEQ_TDO); - for (int i = 0; i < DIV_ROUND_UP(len, 8); ++i) - printf(" %02x", cmd[pos+i]); - pos += DIV_ROUND_UP(len, 8); - printf("\n"); - } - if (pos != cmdlen) { - printf("BUFFER LENGTH MISMATCH looks like %d but %d specified", pos, cmdlen); - exit(-1); - } - - break; + case CMD_DAP_JTAG_SEQ: { + printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); + /* + * #1 = number of sequences + * #2 = sequence info 1 + * #3...4+n_bytes-1 = sequence 1 + * #4+n_bytes = sequence info 2 + * #5+n_bytes = sequence 2 (single bit) + */ + int pos = 2; + for (int seq = 0; seq < cmd[1]; ++seq) { + uint8_t info = cmd[pos++]; + int len = info & DAP_JTAG_SEQ_TCK; + if (len == 0) + len = 64; + printf(" sequence %d starting %d: info %02x (len=%d tms=%d read_tdo=%d): ", + seq, pos, info, len, info & DAP_JTAG_SEQ_TMS, info & DAP_JTAG_SEQ_TDO); + for (int i = 0; i < DIV_ROUND_UP(len, 8); ++i) + printf(" %02x", cmd[pos + i]); + pos += DIV_ROUND_UP(len, 8); + printf("\n"); } - default: - LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); - break; + if (pos != cmdlen) { + printf("BUFFER LENGTH MISMATCH looks like %d but %d specified", pos, cmdlen); + exit(-1); + } + + break; + } + default: + LOG_DEBUG("unknown cmsis-dap command %02x", cmd[1]); + break; } } #endif @@ -1930,32 +1939,32 @@ static void cmsis_dap_execute_tms(struct jtag_command *cmd) static void cmsis_dap_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_SLEEP: - cmsis_dap_flush(); - cmsis_dap_execute_sleep(cmd); - break; - case JTAG_TLR_RESET: - cmsis_dap_flush(); - cmsis_dap_execute_tlr_reset(cmd); - break; - case JTAG_SCAN: - cmsis_dap_execute_scan(cmd); - break; - case JTAG_PATHMOVE: - cmsis_dap_execute_pathmove(cmd); - break; - case JTAG_RUNTEST: - cmsis_dap_execute_runtest(cmd); - break; - case JTAG_STABLECLOCKS: - cmsis_dap_execute_stableclocks(cmd); - break; - case JTAG_TMS: - cmsis_dap_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); - exit(-1); + case JTAG_SLEEP: + cmsis_dap_flush(); + cmsis_dap_execute_sleep(cmd); + break; + case JTAG_TLR_RESET: + cmsis_dap_flush(); + cmsis_dap_execute_tlr_reset(cmd); + break; + case JTAG_SCAN: + cmsis_dap_execute_scan(cmd); + break; + case JTAG_PATHMOVE: + cmsis_dap_execute_pathmove(cmd); + break; + case JTAG_RUNTEST: + cmsis_dap_execute_runtest(cmd); + break; + case JTAG_STABLECLOCKS: + cmsis_dap_execute_stableclocks(cmd); + break; + case JTAG_TMS: + cmsis_dap_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X encountered", cmd->type); + exit(-1); } } @@ -2238,11 +2247,13 @@ COMMAND_HANDLER(cmsis_dap_handle_quirk_command) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC == 1) - COMMAND_PARSE_ENABLE(CMD_ARGV[0], cmsis_dap_handle->quirk_mode); + if (CMD_ARGC == 1) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], cmsis_dap_quirk_mode); + return ERROR_OK; + } + + command_print(CMD, "%s", cmsis_dap_quirk_mode ? "enabled" : "disabled"); - command_print(CMD, "CMSIS-DAP quirk workarounds %s", - cmsis_dap_handle->quirk_mode ? "enabled" : "disabled"); return ERROR_OK; } @@ -2272,8 +2283,8 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .name = "backend", .handler = &cmsis_dap_handle_backend_command, .mode = COMMAND_CONFIG, - .help = "set the communication backend to use (USB bulk or HID).", - .usage = "(auto | usb_bulk | hid)", + .help = "set the communication backend to use (USB bulk or HID, or TCP).", + .usage = "(auto | usb_bulk | hid | tcp)", }, { .name = "quirk", @@ -2290,6 +2301,15 @@ static const struct command_registration cmsis_dap_subcommand_handlers[] = { .help = "USB bulk backend-specific commands", .usage = "", }, +#endif +#if BUILD_CMSIS_DAP_TCP + { + .name = "tcp", + .chain = cmsis_dap_tcp_subcommand_handlers, + .mode = COMMAND_ANY, + .help = "TCP backend-specific commands", + .usage = "", + }, #endif COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/cmsis_dap.h b/src/jtag/drivers/cmsis_dap.h index aded0e54a3..880fc33502 100644 --- a/src/jtag/drivers/cmsis_dap.h +++ b/src/jtag/drivers/cmsis_dap.h @@ -52,7 +52,6 @@ struct cmsis_dap { unsigned int pending_fifo_block_count; uint16_t caps; - bool quirk_mode; /* enable expensive workarounds */ uint32_t swo_buf_sz; bool trace_enabled; @@ -78,7 +77,9 @@ struct cmsis_dap_backend { extern const struct cmsis_dap_backend cmsis_dap_hid_backend; extern const struct cmsis_dap_backend cmsis_dap_usb_backend; +extern const struct cmsis_dap_backend cmsis_dap_tcp_backend; extern const struct command_registration cmsis_dap_usb_subcommand_handlers[]; +extern const struct command_registration cmsis_dap_tcp_subcommand_handlers[]; #define REPORT_ID_SIZE 1 diff --git a/src/jtag/drivers/cmsis_dap_tcp.c b/src/jtag/drivers/cmsis_dap_tcp.c new file mode 100644 index 0000000000..7894550fe2 --- /dev/null +++ b/src/jtag/drivers/cmsis_dap_tcp.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Provides CMSIS-DAP protocol over a TCP/IP socket. * + * UART and SWO are currently unsupported. * + * * + * Copyright (C) 2025 by Brian Kuschak * + * * + * Adapted from cmsis_dap_usb_hid.c. Copyright (C) 2013-2018 by: * + * Mickaël Thomas * + * Maksym Hilliaka * + * Phillip Pearson * + * Paul Fertser * + * mike brown * + * Spencer Oliver * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif +#include +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#include "helper/command.h" +#include "helper/log.h" +#include "helper/replacements.h" +#include "helper/system.h" +#include "cmsis_dap.h" + +#define STRINGIFY(x) #x + +// If the protocol changes in the future, the SIGNATURE should also be changed. +#define DAP_PKT_HDR_SIGNATURE 0x00504144 // "DAP" +#define DAP_PKT_TYPE_REQUEST 0x01 +#define DAP_PKT_TYPE_RESPONSE 0x02 + +#define CMSIS_DAP_TCP_PORT 4441 // Default. Can be overridden. +#define CMSIS_DAP_PACKET_SIZE 1024 // Max payload size not including + // header. + +/* When flushing after an error, the CMSIS-DAP driver assumes the pipeline is + * empty if it doesn't get a response after a short 10 msec timeout. While this + * works for USB, it may not work for TCP/IP due to higher network latency. TCP + * response packets may take longer to arrive. We set a lower bound on timeout + * for blocking reads, to give enough time for packets to arrive. + * + * The user may override this default value by setting the parameter + * 'cmsis-dap tcp min_timeout' + */ +#define DEFAULT_MIN_TIMEOUT_MS 150 + +/* CMSIS-DAP requests are variable length. With CMSIS-DAP over USB, the + * transfer sizes are preserved by the USB stack. However, TCP/IP is stream + * oriented so we perform our own packetization to preserve the boundaries + * between each request. This short header is prepended to each CMSIS-DAP + * request and response before being sent over the socket. Little endian format + * is used for multibyte values. + */ +struct __attribute__((packed)) cmsis_dap_tcp_packet_hdr { + uint32_t signature; // "DAP" + uint16_t length; // Not including header length. + uint8_t packet_type; + uint8_t reserved; // Reserved for future use. +}; + +/* Defines for struct cmsis_dap_tcp_packet_hdr requested by reviewer. */ +#define HEADER_SIGNATURE_OFFSET 0 +#define HEADER_LENGTH_OFFSET sizeof(uint32_t) +#define HEADER_PACKET_TYPE_OFFSET (sizeof(uint32_t) + sizeof(uint16_t)) +#define HEADER_RESERVED_OFFSET (sizeof(uint32_t) + sizeof(uint16_t) + \ + sizeof(uint8_t)) +#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint16_t) + \ + 2 * sizeof(uint8_t)) + +struct cmsis_dap_backend_data { + int sockfd; +}; + +static char *cmsis_dap_tcp_host; +static char cmsis_dap_tcp_port_default[] = STRINGIFY(CMSIS_DAP_TCP_PORT); +static char *cmsis_dap_tcp_port = cmsis_dap_tcp_port_default; +static int cmsis_dap_tcp_min_timeout_ms = DEFAULT_MIN_TIMEOUT_MS; + +static void cmsis_dap_tcp_close(struct cmsis_dap *dap); +static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz); +static void cmsis_dap_tcp_free(struct cmsis_dap *dap); + +static int cmsis_dap_tcp_open(struct cmsis_dap *dap, + uint16_t vids[] __attribute__((unused)), + uint16_t pids[] __attribute__((unused)), + const char *serial __attribute__((unused))) +{ + // Skip the open if the user has not provided a hostname. + if (!cmsis_dap_tcp_host) { + LOG_DEBUG("No TCP hostname, skipping open."); + return ERROR_FAIL; + } + + // Ignore vids, pids, serial. We use host and port subcommands instead. + + dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data)); + if (!dap->bdata) { + LOG_ERROR("CMSIS-DAP: unable to allocate memory"); + return ERROR_FAIL; + } + + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM + }; + struct addrinfo *result, *rp; + int fd = 0; + + LOG_INFO("CMSIS-DAP: Connecting to %s:%s using TCP backend", + cmsis_dap_tcp_host ? cmsis_dap_tcp_host : "localhost", + cmsis_dap_tcp_port); + + /* Some of the following code was taken from remote_bitbang.c */ + /* Obtain address(es) matching host/port */ + int s = getaddrinfo(cmsis_dap_tcp_host, cmsis_dap_tcp_port, &hints, + &result); + if (s != 0) { + LOG_ERROR("CMSIS-DAP: getaddrinfo: %s\n", gai_strerror(s)); + free(dap->bdata); + return ERROR_FAIL; + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully connect(2). + If socket(2) (or connect(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp ; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) + continue; + + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) { + LOG_DEBUG("Connected."); + break; /* Success */ + } + + close(fd); + } + + freeaddrinfo(result); + + if (!rp) { /* No address succeeded */ + LOG_ERROR("CMSIS-DAP: unable to connect to device %s:%s", + cmsis_dap_tcp_host ? cmsis_dap_tcp_host : "localhost", + cmsis_dap_tcp_port); + log_socket_error("Failed to connect"); + free(dap->bdata); + dap->bdata = NULL; + return ERROR_FAIL; + } + + /* Set NODELAY to minimize latency. */ + int one = 1; + /* On Windows optval has to be a const char *. */ + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one)); + + dap->bdata->sockfd = fd; + + int retval = cmsis_dap_tcp_alloc(dap, CMSIS_DAP_PACKET_SIZE); + if (retval != ERROR_OK) { + cmsis_dap_tcp_close(dap); + return retval; + } + return ERROR_OK; +} + +static void cmsis_dap_tcp_close(struct cmsis_dap *dap) +{ + if (close_socket(dap->bdata->sockfd) != 0) + log_socket_error("close_socket"); + + if (dap->bdata) + free(dap->bdata); + dap->bdata = NULL; + cmsis_dap_tcp_free(dap); +} + +static int socket_bytes_available(int sock, unsigned int *out_avail) +{ +#ifdef _WIN32 + u_long avail = 0; + if (ioctlsocket((SOCKET)sock, FIONREAD, &avail) == SOCKET_ERROR) + return -1; +#else + int avail = 0; + if (ioctl(sock, FIONREAD, &avail) < 0) + return -1; +#endif + *out_avail = avail; + return 0; +} + +static inline int readall_socket(int handle, void *buffer, unsigned int count) +{ + // Return after all count bytes available, or timeout, or error. + return recv(handle, buffer, count, MSG_WAITALL); +} + +static int peekall_socket(int handle, void *buffer, unsigned int count, + enum cmsis_dap_blocking blocking, unsigned int timeout_ms) +{ + /* Windows doesn't support MSG_PEEK in combination with MSG_WAITALL: + * return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL); + * + * So, use this method instead which should work for Windows and others. + * + * Data remains unread on the socket until recv() is called later without + * the MSG_PEEK flag. Return after all count bytes available, or timeout, + * or error. + */ + + if (count == 0) + return 0; + + while (true) { + int ret; + unsigned int avail; + if (socket_bytes_available(handle, &avail) < 0) + return -1; + + if (avail >= count) { + ret = recv(handle, (char *)buffer, (int)count, MSG_PEEK); + if (ret < 0) { +#ifdef _WIN32 + int err = WSAGetLastError(); + if (err == WSAEINTR) + continue; + if (err == WSAEWOULDBLOCK) + return -1; +#else + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return -1; // Timeout or nonblocking. +#endif + } + return ret; // 0: Closed, <0: Other error, >0 Success. + } + + // Not enough data available. + if (blocking == CMSIS_DAP_NON_BLOCKING) { +#ifdef _WIN32 + WSASetLastError(WSAEWOULDBLOCK); +#else + errno = EAGAIN; +#endif + return -1; + } + + // Blocking wait. + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(handle, &rfds); + + struct timeval tv; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + + ret = select(handle + 1, &rfds, NULL, NULL, &tv); + if (ret > 0) + continue; // Readable + + if (ret == 0) { // Timeout +#ifdef _WIN32 + WSASetLastError(WSAEWOULDBLOCK); +#else + errno = EAGAIN; +#endif + return -1; + } + + // Error +#ifndef _WIN32 + if (errno == EINTR) + continue; +#endif + return ret; + } +} + +static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms, + enum cmsis_dap_blocking blocking) +{ + int wait_ms = (blocking == CMSIS_DAP_NON_BLOCKING) ? 0 : + transfer_timeout_ms; + if (wait_ms) { + LOG_DEBUG_IO("CMSIS-DAP: using tcp timeout %d msec", wait_ms); + + // Don't use very short timeouts with TCP/IP as it may not be as fast + // to respond as USB. User configurable minimum value. + if (wait_ms < cmsis_dap_tcp_min_timeout_ms) { + wait_ms = cmsis_dap_tcp_min_timeout_ms; + LOG_DEBUG_IO("CMSIS-DAP: extending timeout to %d msec", wait_ms); + } + } + socket_recv_timeout(dap->bdata->sockfd, wait_ms); + + if (blocking == CMSIS_DAP_NON_BLOCKING) + socket_nonblock(dap->bdata->sockfd); + else + socket_block(dap->bdata->sockfd); + + // Peek at the header first to find the length. + int retval = peekall_socket(dap->bdata->sockfd, dap->packet_buffer, + HEADER_SIZE, blocking, wait_ms); + LOG_DEBUG_IO("Reading header returned %d", retval); + if (retval == 0) { + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 1"); + return ERROR_TIMEOUT_REACHED; + } else if (retval == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + if (blocking == CMSIS_DAP_NON_BLOCKING) + return ERROR_TIMEOUT_REACHED; + + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 2. timeout = %d msec", + wait_ms); + return ERROR_TIMEOUT_REACHED; + } + + LOG_ERROR("CMSIS-DAP: error reading header"); + log_socket_error("peek_socket"); + return ERROR_FAIL; + } else if (retval != HEADER_SIZE) { + LOG_ERROR("CMSIS-DAP: short header read"); + log_socket_error("peek_socket header short read"); + return ERROR_FAIL; + } + + struct cmsis_dap_tcp_packet_hdr header; + header.signature = le_to_h_u32(dap->packet_buffer + + HEADER_SIGNATURE_OFFSET); + header.length = le_to_h_u16(dap->packet_buffer + HEADER_LENGTH_OFFSET); + header.packet_type = dap->packet_buffer[HEADER_PACKET_TYPE_OFFSET]; + header.reserved = dap->packet_buffer[HEADER_RESERVED_OFFSET]; + + if (header.signature != DAP_PKT_HDR_SIGNATURE) { + LOG_ERROR("CMSIS-DAP: Unrecognized packet signature 0x%08x", + header.signature); + return ERROR_FAIL; + } else if (header.packet_type != DAP_PKT_TYPE_RESPONSE) { + LOG_ERROR("CMSIS-DAP: Unrecognized packet type 0x%02x", + header.packet_type); + return ERROR_FAIL; + } else if (header.length + HEADER_SIZE > dap->packet_buffer_size) { + LOG_ERROR("CMSIS-DAP: Packet length %d too large to fit.", + header.length); + return ERROR_FAIL; + } + + // Read the complete packet. + int read_len = HEADER_SIZE + header.length; + LOG_DEBUG_IO("Reading %d bytes (%d payload)...", read_len, header.length); + retval = readall_socket(dap->bdata->sockfd, dap->packet_buffer, read_len); + + if (retval == 0) { + LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 3"); + return ERROR_TIMEOUT_REACHED; + } else if (retval == -1) { + LOG_ERROR("CMSIS-DAP: error reading data"); + log_socket_error("read_socket"); + return ERROR_FAIL; + } else if (retval != read_len) { + LOG_ERROR("CMSIS-DAP: short read. retval = %d. read_len = %d. " + "blocking = %s. wait_ms = %d", retval, read_len, + (blocking == CMSIS_DAP_NON_BLOCKING) ? "yes" : "no", wait_ms); + log_socket_error("read_socket short read"); + return ERROR_FAIL; + } + return retval; +} + +static int cmsis_dap_tcp_write(struct cmsis_dap *dap, int txlen, + int timeout_ms __attribute__((unused))) +{ + const unsigned int len = txlen + HEADER_SIZE; + if (len > dap->packet_buffer_size) { + LOG_ERROR("CMSIS-DAP: Packet length %d exceeds TCP buffer size!", len); + return ERROR_FAIL; + } + + /* Set the header values. */ + h_u32_to_le(dap->packet_buffer + HEADER_SIGNATURE_OFFSET, + DAP_PKT_HDR_SIGNATURE); + h_u16_to_le(dap->packet_buffer + HEADER_LENGTH_OFFSET, txlen); + dap->packet_buffer[HEADER_PACKET_TYPE_OFFSET] = DAP_PKT_TYPE_REQUEST; + dap->packet_buffer[HEADER_RESERVED_OFFSET] = 0; + + /* write data to device */ + LOG_DEBUG_IO("Writing %d bytes (%d payload)", len, txlen); + int retval = write_socket(dap->bdata->sockfd, dap->packet_buffer, len); + if (retval < 0) { + log_socket_error("write_socket"); + return ERROR_FAIL; + } else if (retval != (int)len) { + LOG_ERROR("CMSIS-DAP: error writing data"); + log_socket_error("write_socket short write"); + return ERROR_FAIL; + } + return retval; +} + +static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz) +{ + // Reserve space for the packet header. + unsigned int packet_buffer_size = pkt_sz + HEADER_SIZE; + uint8_t *buf = malloc(packet_buffer_size); + if (!buf) { + LOG_ERROR("CMSIS-DAP: unable to allocate CMSIS-DAP packet buffer"); + return ERROR_FAIL; + } + + dap->packet_buffer = buf; + dap->packet_size = pkt_sz; + dap->packet_usable_size = pkt_sz; + dap->packet_buffer_size = packet_buffer_size; + + dap->command = dap->packet_buffer + HEADER_SIZE; + dap->response = dap->packet_buffer + HEADER_SIZE; + return ERROR_OK; +} + +static void cmsis_dap_tcp_free(struct cmsis_dap *dap) +{ + free(dap->packet_buffer); + dap->packet_buffer = NULL; +} + +static void cmsis_dap_tcp_cancel_all(struct cmsis_dap *dap) +{ +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_port) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (cmsis_dap_tcp_port != cmsis_dap_tcp_port_default) + free(cmsis_dap_tcp_port); + + cmsis_dap_tcp_port = strdup(CMD_ARGV[0]); + if (!cmsis_dap_tcp_port) { + LOG_ERROR("CMSIS-DAP: out of memory"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_host) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(cmsis_dap_tcp_host); + cmsis_dap_tcp_host = strdup(CMD_ARGV[0]); + if (!cmsis_dap_tcp_host) { + LOG_ERROR("CMSIS-DAP: out of memory"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(cmsis_dap_handle_tcp_min_timeout) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_tcp_min_timeout_ms); + LOG_INFO("CMSIS-DAP: using minimum timeout of %d ms for TCP packets.", + cmsis_dap_tcp_min_timeout_ms); + return ERROR_OK; +} + +const struct command_registration cmsis_dap_tcp_subcommand_handlers[] = { + { + .name = "host", + .handler = &cmsis_dap_handle_tcp_host, + .mode = COMMAND_CONFIG, + .help = "set the host name to use (for TCP backend only)", + .usage = "", + }, + { + .name = "port", + .handler = &cmsis_dap_handle_tcp_port, + .mode = COMMAND_CONFIG, + .help = "set the port number to use for DAP (for TCP backend only)", + .usage = "", + }, + { + .name = "min_timeout", + .handler = &cmsis_dap_handle_tcp_min_timeout, + .mode = COMMAND_CONFIG, + .help = "set the minimum timeout in milliseconds to wait for response " + "packets (for TCP backend only)", + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct cmsis_dap_backend cmsis_dap_tcp_backend = { + .name = "tcp", + .open = cmsis_dap_tcp_open, + .close = cmsis_dap_tcp_close, + .read = cmsis_dap_tcp_read, + .write = cmsis_dap_tcp_write, + .packet_buffer_alloc = cmsis_dap_tcp_alloc, + .packet_buffer_free = cmsis_dap_tcp_free, + .cancel_all = cmsis_dap_tcp_cancel_all, +}; diff --git a/src/jtag/drivers/cmsis_dap_usb_bulk.c b/src/jtag/drivers/cmsis_dap_usb_bulk.c index 8fbcb029dd..d34d4e31c1 100644 --- a/src/jtag/drivers/cmsis_dap_usb_bulk.c +++ b/src/jtag/drivers/cmsis_dap_usb_bulk.c @@ -414,7 +414,19 @@ static int cmsis_dap_usb_open(struct cmsis_dap *dap, uint16_t vids[], uint16_t p static void cmsis_dap_usb_close(struct cmsis_dap *dap) { for (unsigned int i = 0; i < MAX_PENDING_REQUESTS; i++) { - libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + if (dap->bdata->command_transfers[i].status == CMSIS_DAP_TRANSFER_PENDING) { + LOG_DEBUG("busy command USB transfer at %u", dap->pending_fifo_put_idx); + struct timeval tv = { + .tv_sec = 1, + .tv_usec = 1000 + }; + /* Complete pending commands */ + int res = libusb_handle_events_timeout_completed(dap->bdata->usb_ctx, &tv, NULL); + if (res == 0) + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } else { + libusb_free_transfer(dap->bdata->command_transfers[i].transfer); + } libusb_free_transfer(dap->bdata->response_transfers[i].transfer); } cmsis_dap_usb_free(dap); @@ -647,10 +659,10 @@ static void cmsis_dap_usb_cancel_all(struct cmsis_dap *dap) COMMAND_HANDLER(cmsis_dap_handle_usb_interface_command) { - if (CMD_ARGC == 1) - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_usb_interface); - else - LOG_ERROR("expected exactly one argument to cmsis_dap_usb_interface "); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cmsis_dap_usb_interface); return ERROR_OK; } @@ -661,7 +673,7 @@ const struct command_registration cmsis_dap_usb_subcommand_handlers[] = { .handler = &cmsis_dap_handle_usb_interface_command, .mode = COMMAND_CONFIG, .help = "set the USB interface number to use (for USB bulk backend only)", - .usage = "", + .usage = "", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/dmem.c b/src/jtag/drivers/dmem.c index e50e84aeeb..0f1b582990 100644 --- a/src/jtag/drivers/dmem.c +++ b/src/jtag/drivers/dmem.c @@ -93,14 +93,14 @@ static bool dmem_is_emulated_ap(struct adiv5_ap *ap, unsigned int *idx) return false; } -static void dmem_emu_set_ap_reg(uint64_t addr, uint32_t val) +static void dmem_emu_set_ap_reg(uint32_t addr, uint32_t val) { addr &= ~ARM_APB_PADDR31; *(volatile uint32_t *)((uintptr_t)dmem_emu_virt_base_addr + addr) = val; } -static uint32_t dmem_emu_get_ap_reg(uint64_t addr) +static uint32_t dmem_emu_get_ap_reg(uint32_t addr) { uint32_t val; @@ -113,46 +113,46 @@ static uint32_t dmem_emu_get_ap_reg(uint64_t addr) static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *data) { - uint64_t addr; + uint32_t addr; int ret = ERROR_OK; struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx]; switch (reg) { - case ADIV5_MEM_AP_REG_CSW: - *data = ap_info->apbap_csw; - break; - case ADIV5_MEM_AP_REG_TAR: - *data = ap_info->apbap_tar; - break; - case ADIV5_MEM_AP_REG_CFG: - *data = 0; - break; - case ADIV5_MEM_AP_REG_BASE: - *data = 0; - break; - case ADIV5_AP_REG_IDR: - *data = 0; - break; - case ADIV5_MEM_AP_REG_BD0: - case ADIV5_MEM_AP_REG_BD1: - case ADIV5_MEM_AP_REG_BD2: - case ADIV5_MEM_AP_REG_BD3: - addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); - - *data = dmem_emu_get_ap_reg(addr); - - break; - case ADIV5_MEM_AP_REG_DRW: - addr = ap_info->apbap_tar; - - *data = dmem_emu_get_ap_reg(addr); - - ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); - break; - default: - LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); - ret = ERROR_FAIL; - break; + case ADIV5_MEM_AP_REG_CSW: + *data = ap_info->apbap_csw; + break; + case ADIV5_MEM_AP_REG_TAR: + *data = ap_info->apbap_tar; + break; + case ADIV5_MEM_AP_REG_CFG: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BASE: + *data = 0; + break; + case ADIV5_AP_REG_IDR: + *data = 0; + break; + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); + + *data = dmem_emu_get_ap_reg(addr); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = ap_info->apbap_tar; + + *data = dmem_emu_get_ap_reg(addr); + + ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); + ret = ERROR_FAIL; + break; } /* Track the last error code. */ @@ -164,51 +164,51 @@ static int dmem_emu_ap_q_read(unsigned int ap_idx, unsigned int reg, uint32_t *d static int dmem_emu_ap_q_write(unsigned int ap_idx, unsigned int reg, uint32_t data) { - uint64_t addr; + uint32_t addr; int ret = ERROR_OK; struct dmem_emu_ap_info *ap_info = &dmem_emu_ap_list[ap_idx]; switch (reg) { - case ADIV5_MEM_AP_REG_CSW: - /* - * This implementation only supports 32-bit accesses. - * Force this by ensuring CSW_SIZE field indicates 32-BIT. - */ - ap_info->apbap_csw = ((data & ~CSW_SIZE_MASK) | CSW_32BIT); - break; - case ADIV5_MEM_AP_REG_TAR: - /* - * This implementation only supports 32-bit accesses. - * Force LS 2-bits of TAR to 00b - */ - ap_info->apbap_tar = (data & ~0x3); - break; - - case ADIV5_MEM_AP_REG_CFG: - case ADIV5_MEM_AP_REG_BASE: - case ADIV5_AP_REG_IDR: - /* We don't use this, so we don't need to store */ - break; - - case ADIV5_MEM_AP_REG_BD0: - case ADIV5_MEM_AP_REG_BD1: - case ADIV5_MEM_AP_REG_BD2: - case ADIV5_MEM_AP_REG_BD3: - addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); - - dmem_emu_set_ap_reg(addr, data); - - break; - case ADIV5_MEM_AP_REG_DRW: - addr = ap_info->apbap_tar; - dmem_emu_set_ap_reg(addr, data); - - ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); - break; - default: - LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); - ret = EINVAL; - break; + case ADIV5_MEM_AP_REG_CSW: + /* + * This implementation only supports 32-bit accesses. + * Force this by ensuring CSW_SIZE field indicates 32-BIT. + */ + ap_info->apbap_csw = ((data & ~CSW_SIZE_MASK) | CSW_32BIT); + break; + case ADIV5_MEM_AP_REG_TAR: + /* + * This implementation only supports 32-bit accesses. + * Force LS 2-bits of TAR to 00b + */ + ap_info->apbap_tar = (data & ~0x3); + break; + + case ADIV5_MEM_AP_REG_CFG: + case ADIV5_MEM_AP_REG_BASE: + case ADIV5_AP_REG_IDR: + /* We don't use this, so we don't need to store */ + break; + + case ADIV5_MEM_AP_REG_BD0: + case ADIV5_MEM_AP_REG_BD1: + case ADIV5_MEM_AP_REG_BD2: + case ADIV5_MEM_AP_REG_BD3: + addr = (ap_info->apbap_tar & ~0xf) + (reg & 0x0C); + + dmem_emu_set_ap_reg(addr, data); + + break; + case ADIV5_MEM_AP_REG_DRW: + addr = ap_info->apbap_tar; + dmem_emu_set_ap_reg(addr, data); + + ap_info->apbap_tar += dmem_memap_tar_inc(ap_info->apbap_csw); + break; + default: + LOG_INFO("%s: Unknown reg: 0x%02x", __func__, reg); + ret = EINVAL; + break; } /* Track the last error code. */ @@ -242,13 +242,13 @@ static int dmem_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *dat return ERROR_OK; switch (reg) { - case DP_CTRL_STAT: - *data = CDBGPWRUPACK | CSYSPWRUPACK; - break; + case DP_CTRL_STAT: + *data = CDBGPWRUPACK | CSYSPWRUPACK; + break; - default: - *data = 0; - break; + default: + *data = 0; + break; } return ERROR_OK; @@ -519,7 +519,7 @@ static int dmem_dap_init(void) MAP_SHARED, dmem_fd, dmem_mapped_start); if (dmem_map_base == MAP_FAILED) { - LOG_ERROR("Mapping address 0x%lx for 0x%lx bytes failed!", + LOG_ERROR("Mapping address 0x%zx for 0x%zx bytes failed!", dmem_mapped_start, dmem_mapped_size); goto error_fail; } @@ -543,7 +543,7 @@ static int dmem_dap_init(void) MAP_SHARED, dmem_fd, dmem_mapped_start); if (dmem_emu_map_base == MAP_FAILED) { - LOG_ERROR("Mapping EMU address 0x%lx for 0x%lx bytes failed!", + LOG_ERROR("Mapping EMU address 0x%" PRIx64 " for 0x%" PRIx64 " bytes failed!", dmem_emu_base_address, dmem_emu_size); goto error_fail; } diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index f88e4b9408..5bd934c386 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -818,71 +818,71 @@ static int syncbb_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - if ((cmd->cmd.reset->trst == 1) || + if (cmd->cmd.reset->trst == 1 || (cmd->cmd.reset->srst && - (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { - tap_set_state(TAP_RESET); - } - ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, - tap_state_name(cmd->cmd.runtest->end_state)); - - syncbb_end_state(cmd->cmd.runtest->end_state); - syncbb_runtest(cmd->cmd.runtest->num_cycles); - break; - - case JTAG_STABLECLOCKS: - /* this is only allowed while in a stable state. A check for a stable - * state was done in jtag_add_clocks() - */ - syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); - break; - - case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ - LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); - - syncbb_end_state(cmd->cmd.statemove->end_state); - syncbb_state_move(0); - break; - - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, - tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); - - syncbb_path_move(cmd->cmd.pathmove); - break; - - case JTAG_SCAN: - LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - tap_state_name(cmd->cmd.scan->end_state)); - - syncbb_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - - jtag_sleep(cmd->cmd.sleep->us); - break; - - case JTAG_TMS: - retval = syncbb_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + tap_set_state(TAP_RESET); + + ft232r_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %s", cmd->cmd.runtest->num_cycles, + tap_state_name(cmd->cmd.runtest->end_state)); + + syncbb_end_state(cmd->cmd.runtest->end_state); + syncbb_runtest(cmd->cmd.runtest->num_cycles); + break; + + case JTAG_STABLECLOCKS: + /* this is only allowed while in a stable state. A check for a stable + * state was done in jtag_add_clocks() + */ + syncbb_stableclocks(cmd->cmd.stableclocks->num_cycles); + break; + + case JTAG_TLR_RESET: /* renamed from JTAG_STATEMOVE */ + LOG_DEBUG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); + + syncbb_end_state(cmd->cmd.statemove->end_state); + syncbb_state_move(0); + break; + + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %s", cmd->cmd.pathmove->num_states, + tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); + + syncbb_path_move(cmd->cmd.pathmove); + break; + + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + tap_state_name(cmd->cmd.scan->end_state)); + + syncbb_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + syncbb_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + + jtag_sleep(cmd->cmd.sleep->us); + break; + + case JTAG_TMS: + retval = syncbb_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } if (ft232r_output_len > 0) ft232r_send_recv(); diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 2c3339e658..ab76458810 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -666,38 +666,38 @@ static void ftdi_execute_command(struct jtag_command *cmd) { switch (cmd->type) { #if BUILD_FTDI_CJTAG == 1 - case JTAG_RESET: - if (cmd->cmd.reset->trst) - cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ - break; + case JTAG_RESET: + if (cmd->cmd.reset->trst) + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ + break; #endif - case JTAG_RUNTEST: - ftdi_execute_runtest(cmd); - break; - case JTAG_TLR_RESET: + case JTAG_RUNTEST: + ftdi_execute_runtest(cmd); + break; + case JTAG_TLR_RESET: #if BUILD_FTDI_CJTAG == 1 - cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ + cjtag_reset_online_activate(); /* put the target (back) into selected cJTAG mode */ #endif - ftdi_execute_statemove(cmd); - break; - case JTAG_PATHMOVE: - ftdi_execute_pathmove(cmd); - break; - case JTAG_SCAN: - ftdi_execute_scan(cmd); - break; - case JTAG_SLEEP: - ftdi_execute_sleep(cmd); - break; - case JTAG_STABLECLOCKS: - ftdi_execute_stableclocks(cmd); - break; - case JTAG_TMS: - ftdi_execute_tms(cmd); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); - break; + ftdi_execute_statemove(cmd); + break; + case JTAG_PATHMOVE: + ftdi_execute_pathmove(cmd); + break; + case JTAG_SCAN: + ftdi_execute_scan(cmd); + break; + case JTAG_SLEEP: + ftdi_execute_sleep(cmd); + break; + case JTAG_STABLECLOCKS: + ftdi_execute_stableclocks(cmd); + break; + case JTAG_TMS: + ftdi_execute_tms(cmd); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); + break; } } diff --git a/src/jtag/drivers/gw16012.c b/src/jtag/drivers/gw16012.c index 805065f1f4..f6ae684f77 100644 --- a/src/jtag/drivers/gw16012.c +++ b/src/jtag/drivers/gw16012.c @@ -284,46 +284,46 @@ static int gw16012_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - gw16012_end_state(cmd->cmd.runtest->end_state); - gw16012_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - gw16012_end_state(cmd->cmd.statemove->end_state); - gw16012_state_move(); - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - gw16012_path_move(cmd->cmd.pathmove); - break; - case JTAG_SCAN: - gw16012_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - LOG_DEBUG_IO("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", - type, scan_size, cmd->cmd.scan->end_state); - gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); - if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) - retval = ERROR_JTAG_QUEUE_FAILED; - free(buffer); - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + gw16012_end_state(cmd->cmd.runtest->end_state); + gw16012_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + gw16012_end_state(cmd->cmd.statemove->end_state); + gw16012_state_move(); + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + gw16012_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: + gw16012_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + LOG_DEBUG_IO("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", + type, scan_size, cmd->cmd.scan->end_state); + gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); + if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) + retval = ERROR_JTAG_QUEUE_FAILED; + free(buffer); + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } @@ -461,6 +461,8 @@ static int gw16012_init(void) { uint8_t status_port; + LOG_WARNING("This adapter is deprecated and support will be removed in the next release!"); + if (gw16012_init_device() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 9caf37f6f0..46afa862db 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -40,8 +41,6 @@ static struct jaylink_connection connlist[JAYLINK_MAX_CONNECTIONS]; static enum jaylink_jtag_version jtag_command_version; static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; -static uint32_t serial_number; -static bool use_serial_number; static bool use_usb_location; static enum jaylink_usb_address usb_address; static bool use_usb_address; @@ -242,7 +241,7 @@ static void jlink_execute_scan(struct jtag_command *cmd) static void jlink_execute_sleep(struct jtag_command *cmd) { - LOG_DEBUG_IO("sleep %" PRIu32 "", cmd->cmd.sleep->us); + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); jlink_flush(); jtag_sleep(cmd->cmd.sleep->us); } @@ -250,27 +249,27 @@ static void jlink_execute_sleep(struct jtag_command *cmd) static int jlink_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_STABLECLOCKS: - jlink_execute_stableclocks(cmd); - break; - case JTAG_RUNTEST: - jlink_execute_runtest(cmd); - break; - case JTAG_TLR_RESET: - jlink_execute_statemove(cmd); - break; - case JTAG_PATHMOVE: - jlink_execute_pathmove(cmd); - break; - case JTAG_SCAN: - jlink_execute_scan(cmd); - break; - case JTAG_SLEEP: - jlink_execute_sleep(cmd); - break; - default: - LOG_ERROR("BUG: Unknown JTAG command type encountered"); - return ERROR_JTAG_QUEUE_FAILED; + case JTAG_STABLECLOCKS: + jlink_execute_stableclocks(cmd); + break; + case JTAG_RUNTEST: + jlink_execute_runtest(cmd); + break; + case JTAG_TLR_RESET: + jlink_execute_statemove(cmd); + break; + case JTAG_PATHMOVE: + jlink_execute_pathmove(cmd); + break; + case JTAG_SCAN: + jlink_execute_scan(cmd); + break; + case JTAG_SLEEP: + jlink_execute_sleep(cmd); + break; + default: + LOG_ERROR("BUG: Unknown JTAG command type encountered"); + return ERROR_JTAG_QUEUE_FAILED; } return ERROR_OK; @@ -561,8 +560,9 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) } use_usb_location = !!adapter_usb_get_location(); + const char *adapter_serial = adapter_get_required_serial(); - if (!use_serial_number && !use_usb_address && !use_usb_location && num_devices > 1) { + if (!adapter_serial && !use_usb_address && !use_usb_location && num_devices > 1) { LOG_ERROR("Multiple devices found, specify the desired device"); LOG_INFO("Found devices:"); for (size_t i = 0; devs[i]; i++) { @@ -575,7 +575,12 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) jaylink_strerror(ret)); continue; } - LOG_INFO("Device %zu serial: %" PRIu32, i, serial); + char name[JAYLINK_NICKNAME_MAX_LENGTH]; + int name_ret = jaylink_device_get_nickname(devs[i], name); + if (name_ret == JAYLINK_OK) + LOG_INFO("Device %zu serial: %" PRIu32 ", nickname %s", i, serial, name); + else + LOG_INFO("Device %zu serial: %" PRIu32, i, serial); } jaylink_free_devices(devs, true); @@ -585,23 +590,39 @@ static int jlink_open_device(uint32_t ifaces, bool *found_device) *found_device = false; + uint32_t serial_number; + ret = jaylink_parse_serial_number(adapter_serial, &serial_number); + if (ret != JAYLINK_OK) + serial_number = 0; + for (size_t i = 0; devs[i]; i++) { struct jaylink_device *dev = devs[i]; - if (use_serial_number) { - uint32_t tmp; - ret = jaylink_device_get_serial_number(dev, &tmp); - - if (ret == JAYLINK_ERR_NOT_AVAILABLE) { - continue; - } else if (ret != JAYLINK_OK) { - LOG_WARNING("jaylink_device_get_serial_number() failed: %s", - jaylink_strerror(ret)); - continue; + if (adapter_serial) { + /* + * Treat adapter serial as a nickname first as it can also be numeric. + * If it fails to match (optional) device nickname try to compare + * adapter serial with the actual device serial number. + */ + char nickname[JAYLINK_NICKNAME_MAX_LENGTH]; + ret = jaylink_device_get_nickname(dev, nickname); + if (ret != JAYLINK_OK || strcmp(nickname, adapter_serial) != 0) { + if (!serial_number) + continue; + + uint32_t tmp; + ret = jaylink_device_get_serial_number(dev, &tmp); + if (ret == JAYLINK_ERR_NOT_AVAILABLE) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_serial_number() failed: %s", + jaylink_strerror(ret)); + continue; + } + + if (serial_number != tmp) + continue; } - - if (serial_number != tmp) - continue; } if (use_usb_address) { @@ -670,29 +691,15 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - const char *serial = adapter_get_required_serial(); - if (serial) { - ret = jaylink_parse_serial_number(serial, &serial_number); - if (ret == JAYLINK_ERR) { - LOG_ERROR("Invalid serial number: %s", serial); - jaylink_exit(jayctx); - return ERROR_JTAG_INIT_FAILED; - } - if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_parse_serial_number() failed: %s", jaylink_strerror(ret)); - jaylink_exit(jayctx); - return ERROR_JTAG_INIT_FAILED; - } - use_serial_number = true; + if (adapter_get_required_serial()) use_usb_address = false; - } bool found_device; ret = jlink_open_device(JAYLINK_HIF_USB, &found_device); if (ret != ERROR_OK) return ret; - if (!found_device && use_serial_number) { + if (!found_device && adapter_get_required_serial()) { ret = jlink_open_device(JAYLINK_HIF_TCP, &found_device); if (ret != ERROR_OK) return ret; @@ -2111,44 +2118,44 @@ static int jlink_swd_switch_seq(enum swd_special_seq seq) unsigned int s_len; switch (seq) { - case LINE_RESET: - LOG_DEBUG_IO("SWD line reset"); - s = swd_seq_line_reset; - s_len = swd_seq_line_reset_len; - break; - case JTAG_TO_SWD: - LOG_DEBUG("JTAG-to-SWD"); - s = swd_seq_jtag_to_swd; - s_len = swd_seq_jtag_to_swd_len; - break; - case JTAG_TO_DORMANT: - LOG_DEBUG("JTAG-to-DORMANT"); - s = swd_seq_jtag_to_dormant; - s_len = swd_seq_jtag_to_dormant_len; - break; - case SWD_TO_JTAG: - LOG_DEBUG("SWD-to-JTAG"); - s = swd_seq_swd_to_jtag; - s_len = swd_seq_swd_to_jtag_len; - break; - case SWD_TO_DORMANT: - LOG_DEBUG("SWD-to-DORMANT"); - s = swd_seq_swd_to_dormant; - s_len = swd_seq_swd_to_dormant_len; - break; - case DORMANT_TO_SWD: - LOG_DEBUG("DORMANT-to-SWD"); - s = swd_seq_dormant_to_swd; - s_len = swd_seq_dormant_to_swd_len; - break; - case DORMANT_TO_JTAG: - LOG_DEBUG("DORMANT-to-JTAG"); - s = swd_seq_dormant_to_jtag; - s_len = swd_seq_dormant_to_jtag_len; - break; - default: - LOG_ERROR("Sequence %d not supported", seq); - return ERROR_FAIL; + case LINE_RESET: + LOG_DEBUG_IO("SWD line reset"); + s = swd_seq_line_reset; + s_len = swd_seq_line_reset_len; + break; + case JTAG_TO_SWD: + LOG_DEBUG("JTAG-to-SWD"); + s = swd_seq_jtag_to_swd; + s_len = swd_seq_jtag_to_swd_len; + break; + case JTAG_TO_DORMANT: + LOG_DEBUG("JTAG-to-DORMANT"); + s = swd_seq_jtag_to_dormant; + s_len = swd_seq_jtag_to_dormant_len; + break; + case SWD_TO_JTAG: + LOG_DEBUG("SWD-to-JTAG"); + s = swd_seq_swd_to_jtag; + s_len = swd_seq_swd_to_jtag_len; + break; + case SWD_TO_DORMANT: + LOG_DEBUG("SWD-to-DORMANT"); + s = swd_seq_swd_to_dormant; + s_len = swd_seq_swd_to_dormant_len; + break; + case DORMANT_TO_SWD: + LOG_DEBUG("DORMANT-to-SWD"); + s = swd_seq_dormant_to_swd; + s_len = swd_seq_dormant_to_swd_len; + break; + case DORMANT_TO_JTAG: + LOG_DEBUG("DORMANT-to-JTAG"); + s = swd_seq_dormant_to_jtag; + s_len = swd_seq_dormant_to_jtag_len; + break; + default: + LOG_ERROR("Sequence %d not supported", seq); + return ERROR_FAIL; } jlink_queue_data_out(s, s_len); diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index 88e301cebc..f79e2dca70 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -646,25 +646,24 @@ static void kitprog_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay static int kitprog_swd_switch_seq(enum swd_special_seq seq) { switch (seq) { - case JTAG_TO_SWD: - if (kitprog_handle->supports_jtag_to_swd) { - LOG_DEBUG("JTAG to SWD"); - if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) - return ERROR_FAIL; - break; - } else { - LOG_DEBUG("JTAG to SWD not supported"); - /* Fall through to fix target reset issue */ - } - /* fallthrough */ - case LINE_RESET: - LOG_DEBUG("SWD line reset"); - if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) + case JTAG_TO_SWD: + if (kitprog_handle->supports_jtag_to_swd) { + LOG_DEBUG("JTAG to SWD"); + if (kitprog_swd_seq(SEQUENCE_JTAG_TO_SWD) != ERROR_OK) return ERROR_FAIL; break; - default: - LOG_ERROR("Sequence %d not supported.", seq); + } + LOG_DEBUG("JTAG to SWD not supported"); + /* Fall through to fix target reset issue */ + /* fallthrough */ + case LINE_RESET: + LOG_DEBUG("SWD line reset"); + if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) return ERROR_FAIL; + break; + default: + LOG_ERROR("Sequence %d not supported.", seq); + return ERROR_FAIL; } return ERROR_OK; diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 36c7e04934..cc738e9a30 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -19,8 +19,278 @@ #include #include "bitbang.h" +/* + * In case of libgpiod v1, use as much as possible API from v2 plus + * the dummy wrappers below. + */ +#ifdef HAVE_LIBGPIOD_V1 + +#define GPIOD_LINE_DIRECTION_INPUT GPIOD_LINE_REQUEST_DIRECTION_INPUT +#define GPIOD_LINE_DIRECTION_OUTPUT GPIOD_LINE_REQUEST_DIRECTION_OUTPUT + +#define GPIOD_LINE_VALUE_INACTIVE 0 +#define GPIOD_LINE_VALUE_ACTIVE 1 + +#define GPIOD_LINE_DRIVE_PUSH_PULL 0 +#define GPIOD_LINE_DRIVE_OPEN_DRAIN GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN +#define GPIOD_LINE_DRIVE_OPEN_SOURCE GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE + +#define GPIOD_LINE_BIAS_DISABLED GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE +#define GPIOD_LINE_BIAS_PULL_UP GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP +#define GPIOD_LINE_BIAS_PULL_DOWN GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN + +struct gpiod_line_settings { + int direction; + int value; + int drive; + int bias; + int active_low; +}; + +static struct gpiod_line_settings *gpiod_line_settings_new(void) +{ + struct gpiod_line_settings *rv; + + rv = calloc(sizeof(struct gpiod_line_settings), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod line settings"); + return NULL; + } + + return rv; +} + +static void gpiod_line_settings_free(struct gpiod_line_settings *settings) +{ + free(settings); +} + +static int gpiod_line_settings_set_direction(struct gpiod_line_settings *settings, + int direction) +{ + settings->direction = direction; + + return 0; +} + +static int gpiod_line_settings_set_output_value(struct gpiod_line_settings *settings, + int value) +{ + settings->value = value; + + return 0; +} + +static int gpiod_line_settings_set_drive(struct gpiod_line_settings *settings, int drive) +{ + settings->drive = drive; + + return 0; +} + +static void gpiod_line_settings_set_active_low(struct gpiod_line_settings *settings, + bool active_low) +{ + if (active_low) + settings->active_low = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; +} + +#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS + +static int gpiod_line_settings_set_bias(struct gpiod_line_settings *settings, int bias) +{ + settings->bias = bias; + + return 0; +} + +#else /* HAVE_LIBGPIOD1_FLAGS_BIAS */ + +static int gpiod_line_settings_set_bias(struct gpiod_line_settings *settings, int bias) +{ + if (bias == GPIOD_LINE_BIAS_DISABLED) + return 0; + + LOG_WARNING("linuxgpiod: ignoring request for pull-%s: not supported by libgpiod v%s", + (bias == GPIOD_LINE_BIAS_PULL_UP) ? "up" : "down", + gpiod_version_string()); + + return 0; +} + +#endif /* HAVE_LIBGPIOD1_FLAGS_BIAS */ + +struct gpiod_line_config { + unsigned int gpio_num; + struct gpiod_line_settings *line_settings; +}; + +static struct gpiod_line_config *gpiod_line_config_new(void) +{ + struct gpiod_line_config *rv; + + rv = calloc(sizeof(struct gpiod_line_config), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod line config"); + return NULL; + } + + return rv; +} + +static void gpiod_line_config_free(struct gpiod_line_config *config) +{ + free(config); +} + +static int gpiod_line_config_add_line_settings(struct gpiod_line_config *config, + const unsigned int *offsets, size_t num_offsets, struct gpiod_line_settings *settings) +{ + assert(num_offsets == 1); + + config->gpio_num = *offsets; + config->line_settings = settings; + + return 0; +} + +struct gpiod_request_config { + const char *consumer; +}; + +static struct gpiod_request_config *gpiod_request_config_new(void) +{ + struct gpiod_request_config *rv; + + rv = calloc(sizeof(struct gpiod_request_config), 1); + if (!rv) { + LOG_ERROR("No memory for gpiod request config"); + return NULL; + } + + return rv; +} + +static void gpiod_request_config_free(struct gpiod_request_config *config) +{ + free(config); +} + +static void gpiod_request_config_set_consumer(struct gpiod_request_config *config, + const char *consumer) +{ + config->consumer = consumer; +} + +struct gpiod_line_request { + struct gpiod_line *gpio_line; + struct gpiod_chip *chip; + struct gpiod_request_config *req_cfg; + struct gpiod_line_config *line_cfg; +}; + +static void gpiod_line_request_release(struct gpiod_line_request *request); + +static struct gpiod_line_request *gpiod_chip_request_lines(struct gpiod_chip *chip, + struct gpiod_request_config *req_cfg, struct gpiod_line_config *line_cfg) +{ + struct gpiod_line_request *line_req; + int rv, flags = 0; + + assert(req_cfg); + + line_req = calloc(sizeof(struct gpiod_line_request), 1); + if (!line_req) { + LOG_ERROR("No memory for gpiod line request"); + return NULL; + } + + line_req->gpio_line = gpiod_chip_get_line(chip, line_cfg->gpio_num); + if (!line_req->gpio_line) { + free(line_req); + return NULL; + } + + /* remember stuff in case we need to reconfigure later */ + line_req->chip = chip; + line_req->req_cfg = gpiod_request_config_new(); + *line_req->req_cfg = *req_cfg; + line_req->line_cfg = line_cfg; + + flags |= line_cfg->line_settings->drive; + flags |= line_cfg->line_settings->bias; + flags |= line_cfg->line_settings->active_low; + + struct gpiod_line_request_config config = { + .consumer = line_req->req_cfg->consumer, + .request_type = line_cfg->line_settings->direction, + .flags = flags, + }; + + rv = gpiod_line_request(line_req->gpio_line, &config, line_cfg->line_settings->value); + if (rv < 0) { + gpiod_line_request_release(line_req); + return NULL; + } + + return line_req; +} + +static int gpiod_line_request_get_value(struct gpiod_line_request *request, + __attribute__((unused)) unsigned int offset) +{ + return gpiod_line_get_value(request->gpio_line); +} + +static int gpiod_line_request_set_value(struct gpiod_line_request *request, + __attribute__((unused)) unsigned int offset, int value) +{ + return gpiod_line_set_value(request->gpio_line, value); +} + +static void gpiod_line_request_release(struct gpiod_line_request *request) +{ + gpiod_request_config_free(request->req_cfg); + gpiod_line_release(request->gpio_line); + free(request); +} + +static int gpiod_line_request_reconfigure_lines(struct gpiod_line_request *request, + struct gpiod_line_config *line_cfg) +{ + int rv, flags = 0; + + /* in libgpiod v1 we have to release the line and re-aquire it */ + gpiod_line_release(request->gpio_line); + request->gpio_line = gpiod_chip_get_line(request->chip, request->line_cfg->gpio_num); + if (!request->gpio_line) + return -1; + + flags |= line_cfg->line_settings->drive; + flags |= line_cfg->line_settings->bias; + flags |= line_cfg->line_settings->active_low; + + struct gpiod_line_request_config config = { + .consumer = request->req_cfg->consumer, + .request_type = line_cfg->line_settings->direction, + .flags = flags, + }; + + rv = gpiod_line_request(request->gpio_line, &config, line_cfg->line_settings->value); + if (rv < 0) + return -1; + + /* remember updated line_cfg */ + request->line_cfg = line_cfg; + return 0; +} + +#endif /* HAVE_LIBGPIOD_V1 */ + static struct gpiod_chip *gpiod_chip[ADAPTER_GPIO_IDX_NUM] = {}; -static struct gpiod_line *gpiod_line[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_settings *gpiod_line_settings[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_config *gpiod_line_config[ADAPTER_GPIO_IDX_NUM] = {}; +static struct gpiod_line_request *gpiod_line_req[ADAPTER_GPIO_IDX_NUM] = {}; static int last_swclk; static int last_swdio; @@ -29,6 +299,20 @@ static bool swdio_input; static const struct adapter_gpio_config *adapter_gpio_config; +/* Helper to get/set a single line */ +static int linuxgpiod_line_get_value(enum adapter_gpio_config_index idx) +{ + return gpiod_line_request_get_value(gpiod_line_req[idx], + adapter_gpio_config[idx].gpio_num); +} + +static int linuxgpiod_line_set_value(enum adapter_gpio_config_index idx, int value) +{ + return gpiod_line_request_set_value(gpiod_line_req[idx], + adapter_gpio_config[idx].gpio_num, + value); +} + /* * Helper function to determine if gpio config is valid * @@ -46,7 +330,7 @@ static enum bb_value linuxgpiod_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_TDO]); + retval = linuxgpiod_line_get_value(ADAPTER_GPIO_IDX_TDO); if (retval < 0) { LOG_WARNING("reading tdo failed"); return 0; @@ -79,20 +363,20 @@ static int linuxgpiod_write(int tck, int tms, int tdi) } if (tdi != last_tdi) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TDI], tdi); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TDI, tdi); if (retval < 0) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TMS], tms); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TMS, tms); if (retval < 0) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TCK], tck); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TCK, tck); if (retval < 0) LOG_WARNING("writing tck failed"); } @@ -108,7 +392,7 @@ static int linuxgpiod_swdio_read(void) { int retval; - retval = gpiod_line_get_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); + retval = linuxgpiod_line_get_value(ADAPTER_GPIO_IDX_SWDIO); if (retval < 0) { LOG_WARNING("Fail read swdio"); return 0; @@ -121,30 +405,54 @@ static void linuxgpiod_swdio_drive(bool is_output) { int retval; - /* - * FIXME: change direction requires release and re-require the line - * https://stackoverflow.com/questions/58735140/ - * this would change in future libgpiod - */ - gpiod_line_release(gpiod_line[ADAPTER_GPIO_IDX_SWDIO]); - if (is_output) { - if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 1); + if (gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO_DIR, 1); if (retval < 0) - LOG_WARNING("Fail set swdio_dir"); + LOG_WARNING("Failed to set swdio_dir=1"); } - retval = gpiod_line_request_output(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD", 1); + + retval = gpiod_line_settings_set_direction(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_DIRECTION_OUTPUT); + if (retval < 0) + LOG_WARNING("Failed to set new direction of swdio"); + + retval = gpiod_line_settings_set_output_value(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_VALUE_ACTIVE); + if (retval < 0) + LOG_WARNING("Failed to set output value of swdio"); + + retval = gpiod_line_config_add_line_settings(gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO], + &adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, 1, + gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to apply output configuration to swdio"); + + retval = gpiod_line_request_reconfigure_lines(gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO], + gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO]); if (retval < 0) - LOG_WARNING("Fail request_output line swdio"); + LOG_WARNING("Failed to switch swdio to output"); } else { - retval = gpiod_line_request_input(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], "OpenOCD"); + retval = gpiod_line_settings_set_direction(gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO], + GPIOD_LINE_DIRECTION_INPUT); if (retval < 0) - LOG_WARNING("Fail request_input line swdio"); - if (gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR]) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO_DIR], 0); + LOG_WARNING("Failed to switch swdio to output"); + + retval = gpiod_line_config_add_line_settings(gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO], + &adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num, 1, + gpiod_line_settings[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to apply input configuration to swdio"); + + retval = gpiod_line_request_reconfigure_lines(gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO], + gpiod_line_config[ADAPTER_GPIO_IDX_SWDIO]); + if (retval < 0) + LOG_WARNING("Failed to switch swdio to input"); + + if (gpiod_line_req[ADAPTER_GPIO_IDX_SWDIO_DIR]) { + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO_DIR, 0); if (retval < 0) - LOG_WARNING("Fail set swdio_dir"); + LOG_WARNING("Failed to set swdio_dir=0"); } } @@ -158,7 +466,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) if (!swdio_input) { if (!last_stored || swdio != last_swdio) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWDIO], swdio); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWDIO, swdio); if (retval < 0) LOG_WARNING("Fail set swdio"); } @@ -166,7 +474,7 @@ static int linuxgpiod_swd_write(int swclk, int swdio) /* write swclk last */ if (!last_stored || swclk != last_swclk) { - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SWCLK], swclk); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SWCLK, swclk); if (retval < 0) LOG_WARNING("Fail set swclk"); } @@ -185,7 +493,7 @@ static int linuxgpiod_blink(bool on) if (!is_gpio_config_valid(ADAPTER_GPIO_IDX_LED)) return ERROR_OK; - retval = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_LED], on ? 1 : 0); + retval = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_LED, on); if (retval < 0) LOG_WARNING("Fail set led"); return retval; @@ -212,17 +520,17 @@ static int linuxgpiod_reset(int trst, int srst) LOG_DEBUG("linuxgpiod_reset"); /* - * active low behaviour handled by "adaptor gpio" command and + * active low behavior handled by "adaptor gpio" command and * GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW flag when requesting the line. */ - if (gpiod_line[ADAPTER_GPIO_IDX_SRST]) { - retval1 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_SRST], srst); + if (gpiod_line_req[ADAPTER_GPIO_IDX_SRST]) { + retval1 = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_SRST, srst); if (retval1 < 0) LOG_WARNING("set srst value failed"); } - if (gpiod_line[ADAPTER_GPIO_IDX_TRST]) { - retval2 = gpiod_line_set_value(gpiod_line[ADAPTER_GPIO_IDX_TRST], trst); + if (gpiod_line_req[ADAPTER_GPIO_IDX_TRST]) { + retval2 = linuxgpiod_line_set_value(ADAPTER_GPIO_IDX_TRST, trst); if (retval2 < 0) LOG_WARNING("set trst value failed"); } @@ -254,9 +562,17 @@ static bool linuxgpiod_swd_mode_possible(void) static inline void helper_release(enum adapter_gpio_config_index idx) { - if (gpiod_line[idx]) { - gpiod_line_release(gpiod_line[idx]); - gpiod_line[idx] = NULL; + if (gpiod_line_req[idx]) { + gpiod_line_request_release(gpiod_line_req[idx]); + gpiod_line_req[idx] = NULL; + } + if (gpiod_line_config[idx]) { + gpiod_line_config_free(gpiod_line_config[idx]); + gpiod_line_config[idx] = NULL; + } + if (gpiod_line_settings[idx]) { + gpiod_line_settings_free(gpiod_line_settings[idx]); + gpiod_line_settings[idx] = NULL; } if (gpiod_chip[idx]) { gpiod_chip_close(gpiod_chip[idx]); @@ -275,84 +591,103 @@ static int linuxgpiod_quit(void) static int helper_get_line(enum adapter_gpio_config_index idx) { + struct gpiod_request_config *req_cfg = NULL; + char chip_path[24]; + int rv = 0; + if (!is_gpio_config_valid(idx)) return ERROR_OK; - int dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT, flags = 0, val = 0, retval; + snprintf(chip_path, sizeof(chip_path), "/dev/gpiochip%u", adapter_gpio_config[idx].chip_num); + gpiod_chip[idx] = gpiod_chip_open(chip_path); - gpiod_chip[idx] = gpiod_chip_open_by_number(adapter_gpio_config[idx].chip_num); if (!gpiod_chip[idx]) { LOG_ERROR("Cannot open LinuxGPIOD chip %d for %s", adapter_gpio_config[idx].chip_num, adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } - gpiod_line[idx] = gpiod_chip_get_line(gpiod_chip[idx], adapter_gpio_config[idx].gpio_num); - if (!gpiod_line[idx]) { - LOG_ERROR("Error get line %s", adapter_gpio_get_name(idx)); + gpiod_line_settings[idx] = gpiod_line_settings_new(); + gpiod_line_config[idx] = gpiod_line_config_new(); + req_cfg = gpiod_request_config_new(); + + if (!gpiod_line_settings[idx] || !gpiod_line_config[idx] || !req_cfg) { + LOG_ERROR("Cannot configure LinuxGPIOD line for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); return ERROR_JTAG_INIT_FAILED; } + gpiod_request_config_set_consumer(req_cfg, "OpenOCD"); + switch (adapter_gpio_config[idx].init_state) { case ADAPTER_GPIO_INIT_STATE_INPUT: - dir = GPIOD_LINE_REQUEST_DIRECTION_INPUT; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_INPUT); break; case ADAPTER_GPIO_INIT_STATE_INACTIVE: - dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; - val = 0; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_OUTPUT); + rv |= gpiod_line_settings_set_output_value(gpiod_line_settings[idx], GPIOD_LINE_VALUE_INACTIVE); break; case ADAPTER_GPIO_INIT_STATE_ACTIVE: - dir = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; - val = 1; + rv = gpiod_line_settings_set_direction(gpiod_line_settings[idx], GPIOD_LINE_DIRECTION_OUTPUT); + rv |= gpiod_line_settings_set_output_value(gpiod_line_settings[idx], GPIOD_LINE_VALUE_ACTIVE); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line init state for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } switch (adapter_gpio_config[idx].drive) { case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL: + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_PUSH_PULL); break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN: - flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_OPEN_DRAIN); break; case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE: - flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; + rv = gpiod_line_settings_set_drive(gpiod_line_settings[idx], GPIOD_LINE_DRIVE_OPEN_SOURCE); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line driving for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } switch (adapter_gpio_config[idx].pull) { case ADAPTER_GPIO_PULL_NONE: -#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS - flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; -#endif + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_DISABLED); break; case ADAPTER_GPIO_PULL_UP: -#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS - flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; -#else - LOG_WARNING("linuxgpiod: ignoring request for pull-up on %s: not supported by gpiod v%s", - adapter_gpio_get_name(idx), gpiod_version_string()); -#endif + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_PULL_UP); break; case ADAPTER_GPIO_PULL_DOWN: -#ifdef HAVE_LIBGPIOD1_FLAGS_BIAS - flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; -#else - LOG_WARNING("linuxgpiod: ignoring request for pull-down on %s: not supported by gpiod v%s", - adapter_gpio_get_name(idx), gpiod_version_string()); -#endif + rv = gpiod_line_settings_set_bias(gpiod_line_settings[idx], GPIOD_LINE_BIAS_PULL_DOWN); break; } + if (rv < 0) { + LOG_ERROR("Error while configuring LinuxGPIOD line biasing for %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } - if (adapter_gpio_config[idx].active_low) - flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + gpiod_line_settings_set_active_low(gpiod_line_settings[idx], adapter_gpio_config[idx].active_low); - struct gpiod_line_request_config config = { - .consumer = "OpenOCD", - .request_type = dir, - .flags = flags, - }; + rv = gpiod_line_config_add_line_settings(gpiod_line_config[idx], + &adapter_gpio_config[idx].gpio_num, 1, + gpiod_line_settings[idx]); + if (rv < 0) { + LOG_ERROR("Error configuring gpio line %s", adapter_gpio_get_name(idx)); + gpiod_request_config_free(req_cfg); + return ERROR_JTAG_INIT_FAILED; + } - retval = gpiod_line_request(gpiod_line[idx], &config, val); - if (retval < 0) { + gpiod_line_req[idx] = gpiod_chip_request_lines(gpiod_chip[idx], req_cfg, gpiod_line_config[idx]); + + gpiod_request_config_free(req_cfg); + + if (!gpiod_line_req[idx]) { LOG_ERROR("Error requesting gpio line %s", adapter_gpio_get_name(idx)); return ERROR_JTAG_INIT_FAILED; } diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 04626cb1e5..4b5981ab5d 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -173,26 +173,26 @@ COMMAND_HANDLER(opendous_handle_opendous_info_command) COMMAND_HANDLER(opendous_handle_opendous_hw_jtag_command) { switch (CMD_ARGC) { - case 0: - command_print(CMD, "opendous hw jtag %i", opendous_hw_jtag_version); + case 0: + command_print(CMD, "opendous hw jtag %i", opendous_hw_jtag_version); + break; + + case 1: { + int request_version = atoi(CMD_ARGV[0]); + switch (request_version) { + case 2: + case 3: + opendous_hw_jtag_version = request_version; break; - case 1: { - int request_version = atoi(CMD_ARGV[0]); - switch (request_version) { - case 2: - case 3: - opendous_hw_jtag_version = request_version; - break; - - default: - return ERROR_COMMAND_SYNTAX_ERROR; - } - break; - } - default: return ERROR_COMMAND_SYNTAX_ERROR; + } + break; + } + + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; @@ -248,66 +248,66 @@ static int opendous_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %u cycles, end in %i", cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); - if (cmd->cmd.runtest->end_state != -1) - opendous_end_state(cmd->cmd.runtest->end_state); - opendous_runtest(cmd->cmd.runtest->num_cycles); - break; + if (cmd->cmd.runtest->end_state != -1) + opendous_end_state(cmd->cmd.runtest->end_state); + opendous_runtest(cmd->cmd.runtest->num_cycles); + break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - if (cmd->cmd.statemove->end_state != -1) - opendous_end_state(cmd->cmd.statemove->end_state); - opendous_state_move(); - break; + if (cmd->cmd.statemove->end_state != -1) + opendous_end_state(cmd->cmd.statemove->end_state); + opendous_state_move(); + break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); - break; + opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); + break; - case JTAG_SCAN: - LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); + case JTAG_SCAN: + LOG_DEBUG_IO("scan end in %i", cmd->cmd.scan->end_state); - if (cmd->cmd.scan->end_state != -1) - opendous_end_state(cmd->cmd.scan->end_state); + if (cmd->cmd.scan->end_state != -1) + opendous_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - LOG_DEBUG_IO("scan input, length = %d", scan_size); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + LOG_DEBUG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ - opendous_debug_buffer(buffer, (scan_size + 7) / 8); + opendous_debug_buffer(buffer, (scan_size + 7) / 8); #endif - type = jtag_scan_type(cmd->cmd.scan); - opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); - break; + type = jtag_scan_type(cmd->cmd.scan); + opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); + break; - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); - opendous_tap_execute(); + opendous_tap_execute(); - if (cmd->cmd.reset->trst == 1) - tap_set_state(TAP_RESET); - opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; + if (cmd->cmd.reset->trst == 1) + tap_set_state(TAP_RESET); + opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - opendous_tap_execute(); - jtag_sleep(cmd->cmd.sleep->us); - break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + opendous_tap_execute(); + jtag_sleep(cmd->cmd.sleep->us); + break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index 943ad854e8..d45a1c6a97 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -135,36 +135,36 @@ static void openjtag_debug_buffer(uint8_t *buffer, int length, uint8_t type) int j; switch (type) { + case DEBUG_TYPE_READ: + sprintf(line, "USB READ %d bytes", length); + break; + case DEBUG_TYPE_WRITE: + sprintf(line, "USB WRITE %d bytes", length); + break; + case DEBUG_TYPE_OCD_READ: + sprintf(line, "TO OpenOCD %d bytes", length); + break; + case DEBUG_TYPE_BUFFER: + sprintf(line, "Buffer %d bytes", length); + break; + } + + LOG_DEBUG("%s", line); + + for (i = 0; i < length; i += LINE_LEN) { + switch (type) { case DEBUG_TYPE_READ: - sprintf(line, "USB READ %d bytes", length); + sprintf(line, "USB READ: %04x", i); break; case DEBUG_TYPE_WRITE: - sprintf(line, "USB WRITE %d bytes", length); + sprintf(line, "USB WRITE: %04x", i); break; case DEBUG_TYPE_OCD_READ: - sprintf(line, "TO OpenOCD %d bytes", length); + sprintf(line, "TO OpenOCD: %04x", i); break; case DEBUG_TYPE_BUFFER: - sprintf(line, "Buffer %d bytes", length); + sprintf(line, "BUFFER: %04x", i); break; - } - - LOG_DEBUG("%s", line); - - for (i = 0; i < length; i += LINE_LEN) { - switch (type) { - case DEBUG_TYPE_READ: - sprintf(line, "USB READ: %04x", i); - break; - case DEBUG_TYPE_WRITE: - sprintf(line, "USB WRITE: %04x", i); - break; - case DEBUG_TYPE_OCD_READ: - sprintf(line, "TO OpenOCD: %04x", i); - break; - case DEBUG_TYPE_BUFFER: - sprintf(line, "BUFFER: %04x", i); - break; } for (j = i; j < i + LINE_LEN && j < length; j++) { @@ -182,24 +182,24 @@ static int8_t openjtag_get_tap_state(int8_t state) { switch (state) { - case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR; - case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR; - case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR; - case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR; - case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR; - case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR; - case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR; - case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR; - case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR; - case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR; - case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR; - case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR; - case TAP_IDLE: return OPENJTAG_TAP_IDLE; - case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR; - case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR; - case TAP_RESET: return OPENJTAG_TAP_RESET; - case TAP_INVALID: - default: return OPENJTAG_TAP_INVALID; + case TAP_DREXIT2: return OPENJTAG_TAP_EXIT2_DR; + case TAP_DREXIT1: return OPENJTAG_TAP_EXIT1_DR; + case TAP_DRSHIFT: return OPENJTAG_TAP_SHIFT_DR; + case TAP_DRPAUSE: return OPENJTAG_TAP_PAUSE_DR; + case TAP_IRSELECT: return OPENJTAG_TAP_SELECT_IR; + case TAP_DRUPDATE: return OPENJTAG_TAP_UPDATE_DR; + case TAP_DRCAPTURE: return OPENJTAG_TAP_CAPTURE_DR; + case TAP_DRSELECT: return OPENJTAG_TAP_SELECT_DR; + case TAP_IREXIT2: return OPENJTAG_TAP_EXIT2_IR; + case TAP_IREXIT1: return OPENJTAG_TAP_EXIT1_IR; + case TAP_IRSHIFT: return OPENJTAG_TAP_SHIFT_IR; + case TAP_IRPAUSE: return OPENJTAG_TAP_PAUSE_IR; + case TAP_IDLE: return OPENJTAG_TAP_IDLE; + case TAP_IRUPDATE: return OPENJTAG_TAP_UPDATE_IR; + case TAP_IRCAPTURE: return OPENJTAG_TAP_CAPURE_IR; + case TAP_RESET: return OPENJTAG_TAP_RESET; + case TAP_INVALID: + default: return OPENJTAG_TAP_INVALID; } } @@ -347,34 +347,34 @@ static int openjtag_speed(int speed) { int clockcmd; switch (speed) { - case 48000: - clockcmd = 0x00; - break; - case 24000: - clockcmd = 0x20; - break; - case 12000: - clockcmd = 0x40; - break; - case 6000: - clockcmd = 0x60; - break; - case 3000: - clockcmd = 0x80; - break; - case 1500: - clockcmd = 0xA0; - break; - case 750: - clockcmd = 0xC0; - break; - case 375: - clockcmd = 0xE0; - break; - default: - clockcmd = 0xE0; - LOG_WARNING("adapter speed not recognized, reverting to 375 kHz"); - break; + case 48000: + clockcmd = 0x00; + break; + case 24000: + clockcmd = 0x20; + break; + case 12000: + clockcmd = 0x40; + break; + case 6000: + clockcmd = 0x60; + break; + case 3000: + clockcmd = 0x80; + break; + case 1500: + clockcmd = 0xA0; + break; + case 750: + clockcmd = 0xC0; + break; + case 375: + clockcmd = 0xE0; + break; + default: + clockcmd = 0xE0; + LOG_WARNING("adapter speed not recognized, reverting to 375 kHz"); + break; } openjtag_sendcommand(clockcmd); diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 143f3bde1f..794f8296e5 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -20,7 +20,7 @@ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include -#define ioperm(startport, length, enable)\ +#define ioperm(startport, length, enable) \ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ @@ -45,67 +45,17 @@ #include #endif -// Parallel port cable description. -struct cable { - const char *name; - // Status port bit containing current TDO value. - uint8_t tdo_mask; - // Data port bit for TRST. - uint8_t trst_mask; - // Data port bit for TMD. - uint8_t tms_mask; - // Data port bit for TCK. - uint8_t tck_mask; - // Data port bit for TDI. - uint8_t tdi_mask; - // Data port bit for SRST. - uint8_t srst_mask; - // Data port bits that should be inverted. - uint8_t output_invert; - // Status port that should be inverted. - uint8_t input_invert; - // Initialize data port with this value. - uint8_t port_init; - // De-initialize data port with this value. - uint8_t port_exit; - // Data port bit for LED. - uint8_t led_mask; -}; - -static const struct cable cables[] = { - /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ - { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, - { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, - { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, - { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, - { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, - { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, - { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, -/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: - HARD TCK - Target TCK - HARD TMS - Target TMS - HARD TDI - Target TDI - HARD TDO - Target TDO - SOFT TCK - Target TRST - SOFT TDI - Target SRST -*/ - { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, - { "aspo", 0x10, 0x01, 0x04, 0x08, 0x02, 0x10, 0x17, 0x00, 0x17, 0x17, 0x00 }, - { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } -}; +static const struct adapter_gpio_config *adapter_gpio_config; -// Configuration variables. -static char *parport_cable; +#if PARPORT_USE_PPDEV == 0 static uint16_t parport_port; -static bool parport_exit; +#endif +static bool parport_write_exit_state; +static char *parport_device_file; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; // Interface variables. -static const struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 @@ -115,6 +65,20 @@ static unsigned long dataport; static unsigned long statusport; #endif +// Bitmask map for the input pins. +static struct { + uint8_t mask; +} input_pin_bitmask_map[] = { + [10] = {0x40}, + [11] = {0x80}, + [12] = {0x20}, + [13] = {0x10}, + [15] = {0x08}, +}; + +// Generate an output pin bitmask for an adapter signal. +#define OUTPUT_BITMASK(gpio_index) BIT((adapter_gpio_config[(gpio_index)].gpio_num - 2)) + static enum bb_value parport_read(void) { int data = 0; @@ -125,16 +89,15 @@ static enum bb_value parport_read(void) data = inb(statusport); #endif - if ((data ^ cable->input_invert) & cable->tdo_mask) - return BB_HIGH; - else - return BB_LOW; + const struct adapter_gpio_config *gpio_config = &adapter_gpio_config[ADAPTER_GPIO_IDX_TDO]; + const bool tdo_state = data & input_pin_bitmask_map[gpio_config->gpio_num].mask; + + return (tdo_state ^ gpio_config->active_low) ? BB_HIGH : BB_LOW; } -static inline void parport_write_data(void) +static void parport_write_data(void) { - uint8_t output; - output = dataport_value ^ cable->output_invert; + const uint8_t output = dataport_value; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); @@ -147,26 +110,27 @@ static inline void parport_write_data(void) #endif } -static int parport_write(int tck, int tms, int tdi) +static bool is_gpio_configured(enum adapter_gpio_config_index gpio_index) { - int i = wait_states + 1; - - if (tck) - dataport_value |= cable->tck_mask; - else - dataport_value &= ~cable->tck_mask; + return adapter_gpio_config[gpio_index].gpio_num != ADAPTER_GPIO_NOT_SET; +} - if (tms) - dataport_value |= cable->tms_mask; +static void set_pin_state(enum adapter_gpio_config_index gpio_index, + bool state) +{ + if (state ^ adapter_gpio_config[gpio_index].active_low) + dataport_value |= OUTPUT_BITMASK(gpio_index); else - dataport_value &= ~cable->tms_mask; + dataport_value &= ~OUTPUT_BITMASK(gpio_index); +} - if (tdi) - dataport_value |= cable->tdi_mask; - else - dataport_value &= ~cable->tdi_mask; +static int parport_write(int tck, int tms, int tdi) +{ + set_pin_state(ADAPTER_GPIO_IDX_TCK, tck == 1); + set_pin_state(ADAPTER_GPIO_IDX_TMS, tms == 1); + set_pin_state(ADAPTER_GPIO_IDX_TDI, tdi == 1); - while (i-- > 0) + for (int i = 0; i < wait_states + 1; i++) parport_write_data(); return ERROR_OK; @@ -177,15 +141,11 @@ static int parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); - if (trst == 0) - dataport_value |= cable->trst_mask; - else if (trst == 1) - dataport_value &= ~cable->trst_mask; + if (is_gpio_configured(ADAPTER_GPIO_IDX_TRST)) + set_pin_state(ADAPTER_GPIO_IDX_TRST, trst == 0); - if (srst == 0) - dataport_value |= cable->srst_mask; - else if (srst == 1) - dataport_value &= ~cable->srst_mask; + if (is_gpio_configured(ADAPTER_GPIO_IDX_SRST)) + set_pin_state(ADAPTER_GPIO_IDX_SRST, srst == 0); parport_write_data(); @@ -194,11 +154,10 @@ static int parport_reset(int trst, int srst) static int parport_led(bool on) { - if (on) - dataport_value |= cable->led_mask; - else - dataport_value &= ~cable->led_mask; + if (!is_gpio_configured(ADAPTER_GPIO_IDX_LED)) + return ERROR_OK; + set_pin_state(ADAPTER_GPIO_IDX_LED, on); parport_write_data(); return ERROR_OK; @@ -213,11 +172,12 @@ static int parport_speed(int speed) static int parport_khz(int khz, int *jtag_speed) { if (!khz) { - LOG_DEBUG("RCLK not supported"); + LOG_ERROR("RCLK is not supported by the adapter"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); + return ERROR_OK; } @@ -226,32 +186,35 @@ static int parport_speed_div(int speed, int *khz) uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; + return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 -static int parport_get_giveio_access(void) +static bool parport_get_giveio_access(void) { - HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof(version); if (!GetVersionEx(&version)) { errno = EINVAL; - return -1; + return false; } + if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) - return 0; + return true; + + HANDLE h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); - h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; - return -1; + return false; } CloseHandle(h); - return 0; + return true; } #endif @@ -261,105 +224,150 @@ static const struct bitbang_interface parport_bitbang = { .blink = &parport_led, }; +static const struct { + enum adapter_gpio_config_index gpio_index; + bool required; +} all_signals[] = { + { ADAPTER_GPIO_IDX_TDO, true }, + { ADAPTER_GPIO_IDX_TDI, true }, + { ADAPTER_GPIO_IDX_TMS, true }, + { ADAPTER_GPIO_IDX_TCK, true }, + { ADAPTER_GPIO_IDX_TRST, false }, + { ADAPTER_GPIO_IDX_SRST, false }, + { ADAPTER_GPIO_IDX_LED, false }, + { ADAPTER_GPIO_IDX_USER0, false }, +}; + static int parport_init(void) { - const struct cable *cur_cable; -#if PARPORT_USE_PPDEV == 1 - char buffer[256]; -#endif + adapter_gpio_config = adapter_gpio_get_config(); - cur_cable = cables; + // Check if all signals are configured properly. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; - if (!parport_cable) { - parport_cable = strdup("wiggler"); - LOG_WARNING("No parport cable specified, using default 'wiggler'"); - } + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) { + if (all_signals[i].required) { + LOG_ERROR("The signal '%s' is required and must be configured", + adapter_gpio_get_name(gpio_index)); + return ERROR_FAIL; + } - while (cur_cable->name) { - if (!strcmp(cur_cable->name, parport_cable)) { - cable = cur_cable; - break; + continue; } - cur_cable++; - } - if (!cable) { - LOG_ERROR("No matching cable found for %s", parport_cable); - return ERROR_JTAG_INIT_FAILED; + if (gpio_index == ADAPTER_GPIO_IDX_TDO) { + if (gpio.gpio_num < 10 || gpio.gpio_num > 15 || gpio.gpio_num == 14) { + LOG_ERROR("The '%s' signal pin must be 10, 11, 12, 13, or 15", + adapter_gpio_get_name(gpio_index)); + goto init_fail; + } + } else { + if (gpio.gpio_num < 2 || gpio.gpio_num > 9) { + LOG_ERROR("The '%s' signal pin must be 2, 3, 4, 5, 6, 7, 8, or 9", + adapter_gpio_get_name(gpio_index)); + goto init_fail; + } + } } - dataport_value = cable->port_init; + // Initialize signal pin states. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; + + // The TDO (input) and LED (controlled by the adapter) pins cannot be + // initialized. + if (gpio_index == ADAPTER_GPIO_IDX_TDO || gpio_index == ADAPTER_GPIO_IDX_LED) + continue; + + // Do not initialize unconfigured GPIO pins. + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) + continue; + + if (gpio.init_state == ADAPTER_GPIO_INIT_STATE_ACTIVE) + set_pin_state(gpio_index, true); + else if (gpio.init_state == ADAPTER_GPIO_INIT_STATE_INACTIVE) + set_pin_state(gpio_index, false); + } #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { - LOG_ERROR("device is already opened"); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Parallel port is already open"); + goto init_fail; } + if (!parport_device_file) { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - LOG_DEBUG("opening /dev/ppi%d...", parport_port); + parport_device_file = strdup("/dev/ppi0"); +#else + parport_device_file = strdup("/dev/parport0"); +#endif + LOG_WARNING("No parallel port specified, using %s", parport_device_file); + LOG_WARNING("DEPRECATED! The lack of a parallel port specification is deprecated and will no longer work in the future"); + } - snprintf(buffer, 256, "/dev/ppi%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#else /* not __FreeBSD__, __FreeBSD_kernel__ */ - LOG_DEBUG("opening /dev/parport%d...", parport_port); + LOG_DEBUG("Using parallel port %s", parport_device_file); - snprintf(buffer, 256, "/dev/parport%d", parport_port); - device_handle = open(buffer, O_WRONLY); -#endif /* __FreeBSD__, __FreeBSD_kernel__ */ + device_handle = open(parport_device_file, O_WRONLY); if (device_handle < 0) { int err = errno; - LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Failed to open parallel port %s (errno = %d)", + parport_device_file, err); + LOG_ERROR("Check whether the device exists and if you have the required access rights"); + goto init_fail; } - LOG_DEBUG("...open"); - #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - int i = ioctl(device_handle, PPCLAIM); + int retval = ioctl(device_handle, PPCLAIM); - if (i < 0) { - LOG_ERROR("cannot claim device"); - return ERROR_JTAG_INIT_FAILED; + if (retval < 0) { + LOG_ERROR("Failed to claim parallel port %s", parport_device_file); + goto init_fail; } - i = PARPORT_MODE_COMPAT; - i = ioctl(device_handle, PPSETMODE, &i); - if (i < 0) { - LOG_ERROR(" cannot set compatible mode to device"); - return ERROR_JTAG_INIT_FAILED; + int value = PARPORT_MODE_COMPAT; + retval = ioctl(device_handle, PPSETMODE, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible mode to device"); + goto init_fail; } - i = IEEE1284_MODE_COMPAT; - i = ioctl(device_handle, PPNEGOT, &i); - if (i < 0) { - LOG_ERROR("cannot set compatible 1284 mode to device"); - return ERROR_JTAG_INIT_FAILED; + value = IEEE1284_MODE_COMPAT; + retval = ioctl(device_handle, PPNEGOT, &value); + + if (retval < 0) { + LOG_ERROR("Cannot set compatible 1284 mode to device"); + goto init_fail; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ #else /* not PARPORT_USE_PPDEV */ + LOG_WARNING("DEPRECATED: Parallel port access with direct I/O is deprecated and support will be removed in the next release"); + if (!parport_port) { parport_port = 0x378; - LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); + LOG_WARNING("No parallel port specified, using default 0x378 (LPT1)"); } + LOG_DEBUG("Using parallel port 0x%x", parport_port); + dataport = parport_port; statusport = parport_port + 1; - LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 - if (parport_get_giveio_access() != 0) { + if (!parport_get_giveio_access()) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ - LOG_ERROR("missing privileges for direct i/o"); - return ERROR_JTAG_INIT_FAILED; + LOG_ERROR("Missing privileges for direct I/O"); + goto init_fail; } - LOG_DEBUG("...privileges granted"); - // Make sure parallel port is in right mode (clear tristate and interrupt. + // Make sure parallel port is in right mode (clear tristate and interrupt). #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else @@ -369,110 +377,153 @@ static int parport_init(void) #endif /* PARPORT_USE_PPDEV */ if (parport_reset(0, 0) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; + if (parport_write(0, 0, 0) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; + if (parport_led(true) != ERROR_OK) - return ERROR_FAIL; + goto init_fail; bitbang_interface = &parport_bitbang; return ERROR_OK; + +init_fail: + free(parport_device_file); + return ERROR_JTAG_INIT_FAILED; } static int parport_quit(void) { - if (parport_led(false) != ERROR_OK) - return ERROR_FAIL; + free(parport_device_file); + + // Deinitialize signal pin states. + for (size_t i = 0; i < ARRAY_SIZE(all_signals); i++) { + const enum adapter_gpio_config_index gpio_index = all_signals[i].gpio_index; + const struct adapter_gpio_config gpio = adapter_gpio_config[gpio_index]; + + // The TDO (input) and LED (controlled by the adapter) pins cannot be + // deinitialized. + if (gpio_index == ADAPTER_GPIO_IDX_TDO || gpio_index == ADAPTER_GPIO_IDX_LED) + continue; + + // Do not deinitialize unconfigured GPIO pins. + if (gpio.gpio_num == ADAPTER_GPIO_NOT_SET) + continue; + + if (gpio.exit_state == ADAPTER_GPIO_EXIT_STATE_ACTIVE) + set_pin_state(gpio_index, true); + else if (gpio.exit_state == ADAPTER_GPIO_EXIT_STATE_INACTIVE) + set_pin_state(gpio_index, false); + } - if (parport_exit) { - dataport_value = cable->port_exit; + if (parport_write_exit_state) parport_write_data(); - } - free(parport_cable); - parport_cable = NULL; + if (parport_led(false) != ERROR_OK) + return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(parport_handle_port_command) { - if (CMD_ARGC == 1) { - // Only if the port wasn't overwritten by cmdline. - if (!parport_port) { - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); - } else { - LOG_ERROR("The parport port was already configured!"); - return ERROR_FAIL; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + +#if PARPORT_USE_PPDEV == 1 + if (parport_device_file) { + LOG_ERROR("The parallel port device file is already configured"); + return ERROR_FAIL; } - command_print(CMD, "parport port = 0x%" PRIx16 "", parport_port); + char *tmp; - return ERROR_OK; -} + // We do not use the parse_xxx() or COMMAND_PARSE_xxx() functions here since + // they generate an error message if parsing fails. + char *endptr = NULL; + unsigned long port_number = strtoul(CMD_ARGV[0], &endptr, 0); -COMMAND_HANDLER(parport_handle_cable_command) -{ - if (!CMD_ARGC) - return ERROR_OK; + if (*endptr == '\0' && endptr != CMD_ARGV[0]) { + LOG_WARNING("DEPRECATED! Using a port number is deprecated, use the device file instead"); - // Only if the cable name wasn't overwritten by cmdline. - if (!parport_cable) { - // TODO: REVISIT first verify that it's listed in cables[]. - parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); - if (!parport_cable) { - LOG_ERROR("Out of memory"); - return ERROR_FAIL; - } - strcpy(parport_cable, CMD_ARGV[0]); +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + tmp = alloc_printf("/dev/ppi%lu", port_number); +#else + tmp = alloc_printf("/dev/parport%lu", port_number); +#endif + } else { + tmp = strdup(CMD_ARGV[0]); + } + + if (!tmp) { + LOG_ERROR("Failed to allocate memory"); + return ERROR_FAIL; + } + + free(parport_device_file); + parport_device_file = tmp; +#else + if (parport_port > 0) { + command_print(CMD, "The parallel port is already configured"); + return ERROR_FAIL; } - // TODO: REVISIT it's probably worth returning the current value. + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); +#endif return ERROR_OK; } +// This command is only for backward compatibility and will be removed in the +// future. +COMMAND_HANDLER(parport_handle_cable_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + return command_run_linef(CMD_CTX, "parport_select_cable %s", CMD_ARGV[0]); +} + COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); + LOG_WARNING("DEPRECATED: 'parport write_on_exit' will be removed in the future, use the 'adapter gpio' command to configure the exit state for pins"); + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_write_exit_state); return ERROR_OK; } COMMAND_HANDLER(parport_handle_toggling_time_command) { - if (CMD_ARGC == 1) { - uint32_t ns; - int retval = parse_u32(CMD_ARGV[0], &ns); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; - if (retval != ERROR_OK) - return retval; + uint32_t toggling_time; - if (!ns) { - LOG_ERROR("0 ns is not a valid parport toggling time"); - return ERROR_FAIL; - } + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], toggling_time); - parport_toggling_time_ns = ns; - retval = adapter_get_speed(&wait_states); - if (retval != ERROR_OK) { - /* - * If adapter_get_speed fails then the clock_mode has - * not been configured, this happens if toggling_time is - * called before the adapter speed is set. - */ - LOG_INFO("no parport speed set - defaulting to zero wait states"); - wait_states = 0; - } + if (!toggling_time) { + command_print(CMD, "toggling time must not be 0 ns"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - command_print(CMD, "parport toggling time = %" PRIu32 " ns", - parport_toggling_time_ns); + parport_toggling_time_ns = toggling_time; + int retval = adapter_get_speed(&wait_states); + + if (retval != ERROR_OK) { + /* + * If adapter_get_speed fails then the clock_mode has not been + * configured, this happens if toggling_time is called before the + * adapter speed is set. + */ + LOG_INFO("No parallel port speed set, using zero wait states"); + wait_states = 0; + } return ERROR_OK; } @@ -482,35 +533,30 @@ static const struct command_registration parport_subcommand_handlers[] = { .name = "port", .handler = parport_handle_port_command, .mode = COMMAND_CONFIG, - .help = "Display the address of the I/O port (e.g. 0x378) " - "or the number of the '/dev/parport' device used. " - "If a parameter is provided, first change that port.", - .usage = "[port_number]", + .help = "Specify the device file of the parallel port", + .usage = "file", }, { .name = "cable", .handler = parport_handle_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " - "used to connect to the target.", - // TODO: REVISIT there's no way to list layouts we know. - .usage = "[layout]", + "used to connect to the target", + .usage = "cable", }, { .name = "write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, - .help = "Configure the parallel driver to write " - "a known value to the parallel interface on exit.", + .help = "Configure the driver to write a value to the parallel port on shutdown", .usage = "('on'|'off')", }, { .name = "toggling_time", .handler = parport_handle_toggling_time_command, .mode = COMMAND_CONFIG, - .help = "Displays or assigns how many nanoseconds it " - "takes for the hardware to toggle TCK.", - .usage = "[nanoseconds]", + .help = "Configure how many nanoseconds it takes for the hardware to toggle TCK", + .usage = "time", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 449c616545..71ec572b3c 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -179,14 +179,14 @@ static int remote_bitbang_quit(void) static enum bb_value char_to_int(int c) { switch (c) { - case '0': - return BB_LOW; - case '1': - return BB_HIGH; - default: - remote_bitbang_quit(); - LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); - return BB_ERROR; + case '0': + return BB_LOW; + case '1': + return BB_HIGH; + default: + remote_bitbang_quit(); + LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c); + return BB_ERROR; } } diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index a818996255..83c6d68530 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -321,67 +321,53 @@ static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const u } switch (header->type) { - case DTCLOAD_COMMENT: - break; - - case DTCLOAD_ENTRY: - /* store entry addresses somewhere */ - if (!strncmp("download", (char *)buffer + 1, 8)) - dtc_entry_download = buffer[0]; - break; - - case DTCLOAD_LOAD: - /* Send the DTC program to ST7 RAM. */ - usb_err = ep1_memory_write( - hdev_param, - DTC_LOAD_BUFFER, - header->length + 1, buffer - ); - if (usb_err < 0) - return usb_err; - - /* Load it into the DTC. */ - usb_err = ep1_generic_commandl( - hdev_param, 3, - EP1_CMD_DTC_LOAD, - (DTC_LOAD_BUFFER >> 8), - DTC_LOAD_BUFFER - ); - if (usb_err < 0) - return usb_err; - - break; - - case DTCLOAD_RUN: - usb_err = ep1_generic_commandl( - hdev_param, 3, - EP1_CMD_DTC_CALL, - buffer[0], - EP1_CMD_DTC_WAIT - ); - if (usb_err < 0) - return usb_err; - - break; - - case DTCLOAD_LUT_START: - lut_start = buffer[0]; - break; - - case DTCLOAD_LUT: - usb_err = ep1_memory_write( - hdev_param, - ST7_USB_BUF_EP0OUT + lut_start, - header->length + 1, buffer - ); - if (usb_err < 0) - return usb_err; - break; - - default: - LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); - exit(1); - break; + case DTCLOAD_COMMENT: + break; + + case DTCLOAD_ENTRY: + /* store entry addresses somewhere */ + if (!strncmp("download", (char *)buffer + 1, 8)) + dtc_entry_download = buffer[0]; + break; + + case DTCLOAD_LOAD: + /* Send the DTC program to ST7 RAM. */ + usb_err = ep1_memory_write(hdev_param, DTC_LOAD_BUFFER, + header->length + 1, buffer); + if (usb_err < 0) + return usb_err; + + /* Load it into the DTC. */ + usb_err = ep1_generic_commandl(hdev_param, 3, EP1_CMD_DTC_LOAD, + (DTC_LOAD_BUFFER >> 8), DTC_LOAD_BUFFER); + if (usb_err < 0) + return usb_err; + + break; + + case DTCLOAD_RUN: + usb_err = ep1_generic_commandl(hdev_param, 3, EP1_CMD_DTC_CALL, + buffer[0], EP1_CMD_DTC_WAIT); + if (usb_err < 0) + return usb_err; + + break; + + case DTCLOAD_LUT_START: + lut_start = buffer[0]; + break; + + case DTCLOAD_LUT: + usb_err = ep1_memory_write(hdev_param, + ST7_USB_BUF_EP0OUT + lut_start, header->length + 1, buffer); + if (usb_err < 0) + return usb_err; + break; + + default: + LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); + exit(1); + break; } buffer += (header->length + 1); @@ -1147,15 +1133,15 @@ static int rlink_scan(struct jtag_command *cmd, enum scan_type type, chunk_bytes = chunk_bits / 8; switch (type) { - case SCAN_IN: - x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); - break; - case SCAN_OUT: - x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); - break; - default: - x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); - break; + case SCAN_IN: + x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); + break; + case SCAN_OUT: + x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); + break; + default: + x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); + break; } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; @@ -1281,69 +1267,69 @@ static int rlink_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_RUNTEST: - case JTAG_TLR_RESET: - case JTAG_PATHMOVE: - case JTAG_SCAN: - break; - - default: - /* some events, such as resets, need a queue flush to ensure - *consistency */ - tap_state_queue_run(); - dtc_queue_run(); - break; + case JTAG_RUNTEST: + case JTAG_TLR_RESET: + case JTAG_PATHMOVE: + case JTAG_SCAN: + break; + + default: + /* some events, such as resets, need a queue flush to ensure + *consistency */ + tap_state_queue_run(); + dtc_queue_run(); + break; } switch (cmd->type) { - case JTAG_RESET: - LOG_DEBUG_IO("reset trst: %i srst %i", - cmd->cmd.reset->trst, - cmd->cmd.reset->srst); - if ((cmd->cmd.reset->trst == 1) || - (cmd->cmd.reset->srst && - (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) - tap_set_state(TAP_RESET); - rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); - break; - case JTAG_RUNTEST: - LOG_DEBUG_IO("runtest %i cycles, end in %i", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state); - if (cmd->cmd.runtest->end_state != -1) - rlink_end_state(cmd->cmd.runtest->end_state); - rlink_runtest(cmd->cmd.runtest->num_cycles); - break; - case JTAG_TLR_RESET: - LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); - if (cmd->cmd.statemove->end_state != -1) - rlink_end_state(cmd->cmd.statemove->end_state); - rlink_state_move(); - break; - case JTAG_PATHMOVE: - LOG_DEBUG_IO("pathmove: %u states, end in %i", - cmd->cmd.pathmove->num_states, - cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); - rlink_path_move(cmd->cmd.pathmove); - break; - case JTAG_SCAN: - LOG_DEBUG_IO("%s scan end in %i", - (cmd->cmd.scan->ir_scan) ? "IR" : "DR", - cmd->cmd.scan->end_state); - if (cmd->cmd.scan->end_state != -1) - rlink_end_state(cmd->cmd.scan->end_state); - scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); - type = jtag_scan_type(cmd->cmd.scan); - if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) - retval = ERROR_FAIL; - break; - case JTAG_SLEEP: - LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); - jtag_sleep(cmd->cmd.sleep->us); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type encountered"); - exit(-1); + case JTAG_RESET: + LOG_DEBUG_IO("reset trst: %i srst %i", + cmd->cmd.reset->trst, + cmd->cmd.reset->srst); + if (cmd->cmd.reset->trst == 1 || + (cmd->cmd.reset->srst && + (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) + tap_set_state(TAP_RESET); + rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); + break; + case JTAG_RUNTEST: + LOG_DEBUG_IO("runtest %i cycles, end in %i", + cmd->cmd.runtest->num_cycles, + cmd->cmd.runtest->end_state); + if (cmd->cmd.runtest->end_state != -1) + rlink_end_state(cmd->cmd.runtest->end_state); + rlink_runtest(cmd->cmd.runtest->num_cycles); + break; + case JTAG_TLR_RESET: + LOG_DEBUG_IO("statemove end in %i", cmd->cmd.statemove->end_state); + if (cmd->cmd.statemove->end_state != -1) + rlink_end_state(cmd->cmd.statemove->end_state); + rlink_state_move(); + break; + case JTAG_PATHMOVE: + LOG_DEBUG_IO("pathmove: %u states, end in %i", + cmd->cmd.pathmove->num_states, + cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); + rlink_path_move(cmd->cmd.pathmove); + break; + case JTAG_SCAN: + LOG_DEBUG_IO("%s scan end in %i", + (cmd->cmd.scan->ir_scan) ? "IR" : "DR", + cmd->cmd.scan->end_state); + if (cmd->cmd.scan->end_state != -1) + rlink_end_state(cmd->cmd.scan->end_state); + scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); + type = jtag_scan_type(cmd->cmd.scan); + if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) + retval = ERROR_FAIL; + break; + case JTAG_SLEEP: + LOG_DEBUG_IO("sleep %" PRIu32, cmd->cmd.sleep->us); + jtag_sleep(cmd->cmd.sleep->us); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type encountered"); + exit(-1); } cmd = cmd->next; } diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 5ee1f85261..b4d21100cc 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -608,28 +608,28 @@ static int transfer_error_status(const struct libusb_transfer *transfer) int r = 0; switch (transfer->status) { - case LIBUSB_TRANSFER_COMPLETED: - r = 0; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - r = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - r = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - r = LIBUSB_ERROR_OVERFLOW; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - r = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_ERROR: - case LIBUSB_TRANSFER_CANCELLED: - r = LIBUSB_ERROR_IO; - break; - default: - r = LIBUSB_ERROR_OTHER; - break; + case LIBUSB_TRANSFER_COMPLETED: + r = 0; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + r = LIBUSB_ERROR_TIMEOUT; + break; + case LIBUSB_TRANSFER_STALL: + r = LIBUSB_ERROR_PIPE; + break; + case LIBUSB_TRANSFER_OVERFLOW: + r = LIBUSB_ERROR_OVERFLOW; + break; + case LIBUSB_TRANSFER_NO_DEVICE: + r = LIBUSB_ERROR_NO_DEVICE; + break; + case LIBUSB_TRANSFER_ERROR: + case LIBUSB_TRANSFER_CANCELLED: + r = LIBUSB_ERROR_IO; + break; + default: + r = LIBUSB_ERROR_OTHER; + break; } return r; @@ -1058,13 +1058,13 @@ static int stlink_usb_error_check(void *handle) if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { switch (h->databuf[0]) { - case STLINK_SWIM_ERR_OK: - return ERROR_OK; - case STLINK_SWIM_BUSY: - return ERROR_WAIT; - default: - LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); - return ERROR_FAIL; + case STLINK_SWIM_ERR_OK: + return ERROR_OK; + case STLINK_SWIM_BUSY: + return ERROR_WAIT; + default: + LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); + return ERROR_FAIL; } } @@ -1073,64 +1073,64 @@ static int stlink_usb_error_check(void *handle) h->databuf[0] = STLINK_DEBUG_ERR_OK; switch (h->databuf[0]) { - case STLINK_DEBUG_ERR_OK: - return ERROR_OK; - case STLINK_DEBUG_ERR_FAULT: - LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT); - return ERROR_FAIL; - case STLINK_SWD_AP_WAIT: - LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); - return ERROR_WAIT; - case STLINK_SWD_DP_WAIT: - LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT); - return ERROR_WAIT; - case STLINK_JTAG_GET_IDCODE_ERROR: - LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR"); - return ERROR_FAIL; - case STLINK_JTAG_WRITE_ERROR: - LOG_DEBUG("Write error"); - return ERROR_FAIL; - case STLINK_JTAG_WRITE_VERIF_ERROR: - LOG_DEBUG("Write verify error, ignoring"); - return ERROR_OK; - case STLINK_SWD_AP_FAULT: - /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 - * returns ERROR_OK with the comment: - * Change in error status when reading outside RAM. - * This fix allows CDT plugin to visualize memory. - */ - LOG_DEBUG("STLINK_SWD_AP_FAULT"); - return ERROR_FAIL; - case STLINK_SWD_AP_ERROR: - LOG_DEBUG("STLINK_SWD_AP_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_PARITY_ERROR: - LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_DP_FAULT: - LOG_DEBUG("STLINK_SWD_DP_FAULT"); - return ERROR_FAIL; - case STLINK_SWD_DP_ERROR: - LOG_DEBUG("STLINK_SWD_DP_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_DP_PARITY_ERROR: - LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_WDATA_ERROR: - LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_STICKY_ERROR: - LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR"); - return ERROR_FAIL; - case STLINK_SWD_AP_STICKYORUN_ERROR: - LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR"); - return ERROR_FAIL; - case STLINK_BAD_AP_ERROR: - LOG_DEBUG("STLINK_BAD_AP_ERROR"); - return ERROR_FAIL; - default: - LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); - return ERROR_FAIL; + case STLINK_DEBUG_ERR_OK: + return ERROR_OK; + case STLINK_DEBUG_ERR_FAULT: + LOG_DEBUG("SWD fault response (0x%x)", STLINK_DEBUG_ERR_FAULT); + return ERROR_FAIL; + case STLINK_SWD_AP_WAIT: + LOG_DEBUG("wait status SWD_AP_WAIT (0x%x)", STLINK_SWD_AP_WAIT); + return ERROR_WAIT; + case STLINK_SWD_DP_WAIT: + LOG_DEBUG("wait status SWD_DP_WAIT (0x%x)", STLINK_SWD_DP_WAIT); + return ERROR_WAIT; + case STLINK_JTAG_GET_IDCODE_ERROR: + LOG_DEBUG("STLINK_JTAG_GET_IDCODE_ERROR"); + return ERROR_FAIL; + case STLINK_JTAG_WRITE_ERROR: + LOG_DEBUG("Write error"); + return ERROR_FAIL; + case STLINK_JTAG_WRITE_VERIF_ERROR: + LOG_DEBUG("Write verify error, ignoring"); + return ERROR_OK; + case STLINK_SWD_AP_FAULT: + /* git://git.ac6.fr/openocd commit 657e3e885b9ee10 + * returns ERROR_OK with the comment: + * Change in error status when reading outside RAM. + * This fix allows CDT plugin to visualize memory. + */ + LOG_DEBUG("STLINK_SWD_AP_FAULT"); + return ERROR_FAIL; + case STLINK_SWD_AP_ERROR: + LOG_DEBUG("STLINK_SWD_AP_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_PARITY_ERROR: + LOG_DEBUG("STLINK_SWD_AP_PARITY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_DP_FAULT: + LOG_DEBUG("STLINK_SWD_DP_FAULT"); + return ERROR_FAIL; + case STLINK_SWD_DP_ERROR: + LOG_DEBUG("STLINK_SWD_DP_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_DP_PARITY_ERROR: + LOG_DEBUG("STLINK_SWD_DP_PARITY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_WDATA_ERROR: + LOG_DEBUG("STLINK_SWD_AP_WDATA_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_STICKY_ERROR: + LOG_DEBUG("STLINK_SWD_AP_STICKY_ERROR"); + return ERROR_FAIL; + case STLINK_SWD_AP_STICKYORUN_ERROR: + LOG_DEBUG("STLINK_SWD_AP_STICKYORUN_ERROR"); + return ERROR_FAIL; + case STLINK_BAD_AP_ERROR: + LOG_DEBUG("STLINK_BAD_AP_ERROR"); + return ERROR_FAIL; + default: + LOG_DEBUG("unknown/unexpected STLINK status code 0x%x", h->databuf[0]); + return ERROR_FAIL; } } @@ -1597,31 +1597,31 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) stlink_usb_init_buffer(handle, h->rx_ep, rx_size); switch (type) { - case STLINK_MODE_DEBUG_JTAG: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - if (h->version.jtag_api == STLINK_JTAG_API_V1) - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; - else - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG_NO_RESET; - break; - case STLINK_MODE_DEBUG_SWD: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - if (h->version.jtag_api == STLINK_JTAG_API_V1) - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; - else - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD_NO_RESET; - break; - case STLINK_MODE_DEBUG_SWIM: - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; - /* swim enter does not return any response or status */ - return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); - case STLINK_MODE_DFU: - case STLINK_MODE_MASS: - default: - return ERROR_FAIL; + case STLINK_MODE_DEBUG_JTAG: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + if (h->version.jtag_api == STLINK_JTAG_API_V1) + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; + else + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG_NO_RESET; + break; + case STLINK_MODE_DEBUG_SWD: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + if (h->version.jtag_api == STLINK_JTAG_API_V1) + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; + else + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD_NO_RESET; + break; + case STLINK_MODE_DEBUG_SWIM: + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; + /* swim enter does not return any response or status */ + return stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); + case STLINK_MODE_DFU: + case STLINK_MODE_MASS: + default: + return ERROR_FAIL; } return stlink_cmd_allow_retry(handle, h->databuf, rx_size); @@ -1639,22 +1639,22 @@ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) stlink_usb_init_buffer(handle, h->rx_ep, 0); switch (type) { - case STLINK_MODE_DEBUG_JTAG: - case STLINK_MODE_DEBUG_SWD: - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; - break; - case STLINK_MODE_DEBUG_SWIM: - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; - break; - case STLINK_MODE_DFU: - h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; - h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; - break; - case STLINK_MODE_MASS: - default: - return ERROR_FAIL; + case STLINK_MODE_DEBUG_JTAG: + case STLINK_MODE_DEBUG_SWD: + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; + break; + case STLINK_MODE_DEBUG_SWIM: + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; + break; + case STLINK_MODE_DFU: + h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; + h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; + break; + case STLINK_MODE_MASS: + default: + return ERROR_FAIL; } res = stlink_usb_xfer_noerrcheck(handle, h->databuf, 0); @@ -1697,20 +1697,20 @@ static int stlink_usb_exit_mode(void *handle) /* try to exit current mode */ switch (mode) { - case STLINK_DEV_DFU_MODE: - emode = STLINK_MODE_DFU; - break; - case STLINK_DEV_DEBUG_MODE: - emode = STLINK_MODE_DEBUG_SWD; - break; - case STLINK_DEV_SWIM_MODE: - emode = STLINK_MODE_DEBUG_SWIM; - break; - case STLINK_DEV_BOOTLOADER_MODE: - case STLINK_DEV_MASS_MODE: - default: - emode = STLINK_MODE_UNKNOWN; - break; + case STLINK_DEV_DFU_MODE: + emode = STLINK_MODE_DFU; + break; + case STLINK_DEV_DEBUG_MODE: + emode = STLINK_MODE_DEBUG_SWD; + break; + case STLINK_DEV_SWIM_MODE: + emode = STLINK_MODE_DEBUG_SWIM; + break; + case STLINK_DEV_BOOTLOADER_MODE: + case STLINK_DEV_MASS_MODE: + default: + emode = STLINK_MODE_UNKNOWN; + break; } if (emode != STLINK_MODE_UNKNOWN) @@ -3430,34 +3430,34 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param *param) /* wrap version for first read */ switch (pid) { - case STLINK_V1_PID: - h->version.stlink = 1; - h->tx_ep = STLINK_TX_EP; - break; - case STLINK_V3_USBLOADER_PID: - case STLINK_V3E_PID: - case STLINK_V3S_PID: - case STLINK_V3_2VCP_PID: - case STLINK_V3E_NO_MSD_PID: - case STLINK_V3P_USBLOADER_PID: - case STLINK_V3P_PID: - h->version.stlink = 3; - h->tx_ep = STLINK_V2_1_TX_EP; - h->trace_ep = STLINK_V2_1_TRACE_EP; - break; - case STLINK_V2_1_PID: - case STLINK_V2_1_NO_MSD_PID: - h->version.stlink = 2; - h->tx_ep = STLINK_V2_1_TX_EP; - h->trace_ep = STLINK_V2_1_TRACE_EP; - break; - default: - /* fall through - we assume V2 to be the default version*/ - case STLINK_V2_PID: - h->version.stlink = 2; - h->tx_ep = STLINK_TX_EP; - h->trace_ep = STLINK_TRACE_EP; - break; + case STLINK_V1_PID: + h->version.stlink = 1; + h->tx_ep = STLINK_TX_EP; + break; + case STLINK_V3_USBLOADER_PID: + case STLINK_V3E_PID: + case STLINK_V3S_PID: + case STLINK_V3_2VCP_PID: + case STLINK_V3E_NO_MSD_PID: + case STLINK_V3P_USBLOADER_PID: + case STLINK_V3P_PID: + h->version.stlink = 3; + h->tx_ep = STLINK_V2_1_TX_EP; + h->trace_ep = STLINK_V2_1_TRACE_EP; + break; + case STLINK_V2_1_PID: + case STLINK_V2_1_NO_MSD_PID: + h->version.stlink = 2; + h->tx_ep = STLINK_V2_1_TX_EP; + h->trace_ep = STLINK_V2_1_TRACE_EP; + break; + default: + /* fall through - we assume V2 to be the default version */ + case STLINK_V2_PID: + h->version.stlink = 2; + h->tx_ep = STLINK_TX_EP; + h->trace_ep = STLINK_TRACE_EP; + break; } /* get the device version */ @@ -3758,21 +3758,21 @@ static int stlink_open(struct hl_interface_param *param, enum stlink_mode mode, int err = ERROR_OK; switch (h->st_mode) { - case STLINK_MODE_DEBUG_SWD: - if (h->version.jtag_api == STLINK_JTAG_API_V1) - err = ERROR_FAIL; - /* fall-through */ - case STLINK_MODE_DEBUG_JTAG: - if (h->version.jtag == 0) - err = ERROR_FAIL; - break; - case STLINK_MODE_DEBUG_SWIM: - if (h->version.swim == 0) - err = ERROR_FAIL; - break; - default: + case STLINK_MODE_DEBUG_SWD: + if (h->version.jtag_api == STLINK_JTAG_API_V1) err = ERROR_FAIL; - break; + /* fall-through */ + case STLINK_MODE_DEBUG_JTAG: + if (h->version.jtag == 0) + err = ERROR_FAIL; + break; + case STLINK_MODE_DEBUG_SWIM: + if (h->version.swim == 0) + err = ERROR_FAIL; + break; + default: + err = ERROR_FAIL; + break; } if (err != ERROR_OK) { @@ -4194,7 +4194,7 @@ static int stlink_dap_op_connect(struct adiv5_dap *dap) uint32_t idcode; int retval; - LOG_INFO("stlink_dap_op_connect(%sconnect)", dap->do_reconnect ? "re" : ""); + LOG_DEBUG("%s(%sconnect)", __func__, dap->do_reconnect ? "re" : ""); /* Check if we should reset srst already when connecting, but not if reconnecting. */ if (!dap->do_reconnect) { diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 0e01171ea9..9f0791f3d2 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -692,14 +692,14 @@ static int icdi_usb_open(struct hl_interface_param *param, void **fd) switch (param->transport) { #if 0 - /* TODO place holder as swd is not currently supported */ - case HL_TRANSPORT_SWD: + /* TODO place holder as swd is not currently supported */ + case HL_TRANSPORT_SWD: #endif - case HL_TRANSPORT_JTAG: - break; - default: - retval = ERROR_FAIL; - break; + case HL_TRANSPORT_JTAG: + break; + default: + retval = ERROR_FAIL; + break; } if (retval != ERROR_OK) { diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c index 417d560cde..1f14b1a047 100644 --- a/src/jtag/drivers/ulink.c +++ b/src/jtag/drivers/ulink.c @@ -523,32 +523,30 @@ static int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, } switch (direction) { - case PAYLOAD_DIRECTION_OUT: - if (ulink_cmd->payload_out) { - LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); - free(payload); - return ERROR_FAIL; - } else { - ulink_cmd->payload_out = payload; - ulink_cmd->payload_out_size = size; - } - break; - case PAYLOAD_DIRECTION_IN: - if (ulink_cmd->payload_in_start) { - LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); - free(payload); - return ERROR_FAIL; - } else { - ulink_cmd->payload_in_start = payload; - ulink_cmd->payload_in = payload; - ulink_cmd->payload_in_size = size; - - /* By default, free payload_in_start in ulink_clear_queue(). Commands - * that do not want this behavior (e. g. split scans) must turn it off - * separately! */ - ulink_cmd->free_payload_in_start = true; - } - break; + case PAYLOAD_DIRECTION_OUT: + if (ulink_cmd->payload_out) { + LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); + free(payload); + return ERROR_FAIL; + } + ulink_cmd->payload_out = payload; + ulink_cmd->payload_out_size = size; + break; + case PAYLOAD_DIRECTION_IN: + if (ulink_cmd->payload_in_start) { + LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); + free(payload); + return ERROR_FAIL; + } + ulink_cmd->payload_in_start = payload; + ulink_cmd->payload_in = payload; + ulink_cmd->payload_in_size = size; + + /* By default, free payload_in_start in ulink_clear_queue(). Commands + * that do not want this behavior (e.g. split scans) must turn it off + * separately! */ + ulink_cmd->free_payload_in_start = true; + break; } return ERROR_OK; @@ -572,12 +570,12 @@ static int ulink_get_queue_size(struct ulink *device, while (current) { switch (direction) { - case PAYLOAD_DIRECTION_OUT: - sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ - break; - case PAYLOAD_DIRECTION_IN: - sum += current->payload_in_size; - break; + case PAYLOAD_DIRECTION_OUT: + sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ + break; + case PAYLOAD_DIRECTION_IN: + sum += current->payload_in_size; + break; } current = current->next; @@ -881,31 +879,31 @@ static int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, /* Allocate out_payload depending on scan type */ switch (scan_type) { - case SCAN_IN: - if (device->delay_scan_in < 0) - cmd->id = CMD_SCAN_IN; - else - cmd->id = CMD_SLOW_SCAN_IN; - ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); - break; - case SCAN_OUT: - if (device->delay_scan_out < 0) - cmd->id = CMD_SCAN_OUT; - else - cmd->id = CMD_SLOW_SCAN_OUT; - ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); - break; - case SCAN_IO: - if (device->delay_scan_io < 0) - cmd->id = CMD_SCAN_IO; - else - cmd->id = CMD_SLOW_SCAN_IO; - ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); - break; - default: - LOG_ERROR("BUG: ulink_append_scan_cmd() encountered an unknown scan type"); - ret = ERROR_FAIL; - break; + case SCAN_IN: + if (device->delay_scan_in < 0) + cmd->id = CMD_SCAN_IN; + else + cmd->id = CMD_SLOW_SCAN_IN; + ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_OUT: + if (device->delay_scan_out < 0) + cmd->id = CMD_SCAN_OUT; + else + cmd->id = CMD_SLOW_SCAN_OUT; + ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_IO: + if (device->delay_scan_io < 0) + cmd->id = CMD_SCAN_IO; + else + cmd->id = CMD_SLOW_SCAN_IO; + ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + default: + LOG_ERROR("BUG: %s() encountered an unknown scan type", __func__); + ret = ERROR_FAIL; + break; } if (ret != ERROR_OK) { @@ -1287,24 +1285,24 @@ static int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) t = 1.0 / (float)(f); switch (type) { - case DELAY_CLOCK_TCK: - x = (t - (float)(6E-6)) / (float)(4E-6); - break; - case DELAY_CLOCK_TMS: - x = (t - (float)(8.5E-6)) / (float)(4E-6); - break; - case DELAY_SCAN_IN: - x = (t - (float)(8.8308E-6)) / (float)(4E-6); - break; - case DELAY_SCAN_OUT: - x = (t - (float)(1.0527E-5)) / (float)(4E-6); - break; - case DELAY_SCAN_IO: - x = (t - (float)(1.3132E-5)) / (float)(4E-6); - break; - default: - return ERROR_FAIL; - break; + case DELAY_CLOCK_TCK: + x = (t - (float)(6E-6)) / (float)(4E-6); + break; + case DELAY_CLOCK_TMS: + x = (t - (float)(8.5E-6)) / (float)(4E-6); + break; + case DELAY_SCAN_IN: + x = (t - (float)(8.8308E-6)) / (float)(4E-6); + break; + case DELAY_SCAN_OUT: + x = (t - (float)(1.0527E-5)) / (float)(4E-6); + break; + case DELAY_SCAN_IO: + x = (t - (float)(1.3132E-5)) / (float)(4E-6); + break; + default: + return ERROR_FAIL; + break; } /* Check if the delay value is negative. This happens when a frequency is @@ -1347,38 +1345,38 @@ static long ulink_calculate_frequency(enum ulink_delay_type type, int delay) return 0; switch (type) { - case DELAY_CLOCK_TCK: - if (delay < 0) - t = (float)(2.666E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(6E-6); - break; - case DELAY_CLOCK_TMS: - if (delay < 0) - t = (float)(5.666E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); - break; - case DELAY_SCAN_IN: - if (delay < 0) - t = (float)(5.5E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); - break; - case DELAY_SCAN_OUT: - if (delay < 0) - t = (float)(7.0E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); - break; - case DELAY_SCAN_IO: - if (delay < 0) - t = (float)(9.926E-6); - else - t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); - break; - default: - return 0; + case DELAY_CLOCK_TCK: + if (delay < 0) + t = (float)(2.666E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(6E-6); + break; + case DELAY_CLOCK_TMS: + if (delay < 0) + t = (float)(5.666E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); + break; + case DELAY_SCAN_IN: + if (delay < 0) + t = (float)(5.5E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); + break; + case DELAY_SCAN_OUT: + if (delay < 0) + t = (float)(7.0E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); + break; + case DELAY_SCAN_IO: + if (delay < 0) + t = (float)(9.926E-6); + else + t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); + break; + default: + return 0; } f_float = 1.0 / t; @@ -1823,19 +1821,18 @@ static int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) int ret; switch (jtag_scan_type(cmd->cmd.scan)) { - case SCAN_IN: - case SCAN_IO: - ret = jtag_read_buffer(ulink_cmd->payload_in_start, cmd->cmd.scan); - break; - case SCAN_OUT: - /* Nothing to do for OUT scans */ - ret = ERROR_OK; - break; - default: - LOG_ERROR("BUG: ulink_post_process_scan() encountered an unknown" - " JTAG scan type"); - ret = ERROR_FAIL; - break; + case SCAN_IN: + case SCAN_IO: + ret = jtag_read_buffer(ulink_cmd->payload_in_start, cmd->cmd.scan); + break; + case SCAN_OUT: + /* Nothing to do for OUT scans */ + ret = ERROR_OK; + break; + default: + LOG_ERROR("BUG: %s() encountered an unknown JTAG scan type", __func__); + ret = ERROR_FAIL; + break; } return ret; @@ -1863,23 +1860,22 @@ static int ulink_post_process_queue(struct ulink *device) * OpenULINK command */ if (current->needs_postprocessing && openocd_cmd) { switch (openocd_cmd->type) { - case JTAG_SCAN: - ret = ulink_post_process_scan(current); - break; - case JTAG_TLR_RESET: - case JTAG_RUNTEST: - case JTAG_RESET: - case JTAG_PATHMOVE: - case JTAG_SLEEP: - case JTAG_STABLECLOCKS: - /* Nothing to do for these commands */ - ret = ERROR_OK; - break; - default: - ret = ERROR_FAIL; - LOG_ERROR("BUG: ulink_post_process_queue() encountered unknown JTAG " - "command type"); - break; + case JTAG_SCAN: + ret = ulink_post_process_scan(current); + break; + case JTAG_TLR_RESET: + case JTAG_RUNTEST: + case JTAG_RESET: + case JTAG_PATHMOVE: + case JTAG_SLEEP: + case JTAG_STABLECLOCKS: + /* Nothing to do for these commands */ + ret = ERROR_OK; + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: %s() encountered unknown JTAG command type", __func__); + break; } if (ret != ERROR_OK) @@ -1913,31 +1909,31 @@ static int ulink_execute_queue(struct jtag_command *cmd_queue) while (cmd) { switch (cmd->type) { - case JTAG_SCAN: - ret = ulink_queue_scan(ulink_handle, cmd); - break; - case JTAG_TLR_RESET: - ret = ulink_queue_tlr_reset(ulink_handle, cmd); - break; - case JTAG_RUNTEST: - ret = ulink_queue_runtest(ulink_handle, cmd); - break; - case JTAG_RESET: - ret = ulink_queue_reset(ulink_handle, cmd); - break; - case JTAG_PATHMOVE: - ret = ulink_queue_pathmove(ulink_handle, cmd); - break; - case JTAG_SLEEP: - ret = ulink_queue_sleep(ulink_handle, cmd); - break; - case JTAG_STABLECLOCKS: - ret = ulink_queue_stableclocks(ulink_handle, cmd); - break; - default: - ret = ERROR_FAIL; - LOG_ERROR("BUG: encountered unknown JTAG command type"); - break; + case JTAG_SCAN: + ret = ulink_queue_scan(ulink_handle, cmd); + break; + case JTAG_TLR_RESET: + ret = ulink_queue_tlr_reset(ulink_handle, cmd); + break; + case JTAG_RUNTEST: + ret = ulink_queue_runtest(ulink_handle, cmd); + break; + case JTAG_RESET: + ret = ulink_queue_reset(ulink_handle, cmd); + break; + case JTAG_PATHMOVE: + ret = ulink_queue_pathmove(ulink_handle, cmd); + break; + case JTAG_SLEEP: + ret = ulink_queue_sleep(ulink_handle, cmd); + break; + case JTAG_STABLECLOCKS: + ret = ulink_queue_stableclocks(ulink_handle, cmd); + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: encountered unknown JTAG command type"); + break; } if (ret != ERROR_OK) diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 264b45f721..4783e7569a 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -274,18 +274,18 @@ static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int void (*f)(struct usbprog_jtag *usbprog_jtag, char *buffer_local, int size); switch (type) { - case SCAN_OUT: - f = &usbprog_jtag_write_tdi; - break; - case SCAN_IN: - f = &usbprog_jtag_read_tdo; - break; - case SCAN_IO: - f = &usbprog_jtag_write_and_read; - break; - default: - LOG_ERROR("unknown scan type: %i", type); - exit(-1); + case SCAN_OUT: + f = &usbprog_jtag_write_tdi; + break; + case SCAN_IN: + f = &usbprog_jtag_read_tdo; + break; + case SCAN_IO: + f = &usbprog_jtag_write_and_read; + break; + default: + LOG_ERROR("unknown scan type: %i", type); + exit(-1); } f(usbprog_jtag_handle, (char *)buffer, scan_size); diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index 38685950a8..29bfa8360d 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -47,19 +47,20 @@ #include "jtag/interface.h" #include "jtag/commands.h" #include "transport/transport.h" +#include "target/target.h" #include "target/arm_adi_v5.h" #include "helper/time_support.h" #include "helper/replacements.h" #include "helper/log.h" #include "helper/list.h" -#define VD_VERSION 48 +#define VD_VERSION 50 #define VD_BUFFER_LEN 4024 #define VD_CHEADER_LEN 24 #define VD_SHEADER_LEN 16 #define VD_MAX_MEMORIES 20 -#define VD_POLL_INTERVAL 500 +#define VD_POLL_INTERVAL 1000 #define VD_SCALE_PSTOMS 1000000000 /** @@ -205,6 +206,7 @@ struct vd_client { uint32_t poll_max; uint32_t targ_time; int hsocket; + int64_t poll_ts; char server_name[32]; char bfm_path[128]; char mem_path[VD_MAX_MEMORIES][128]; @@ -839,6 +841,35 @@ static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx) } +/* function gets invoked through a callback every VD_POLL_INTERVAL ms + * if the idle time, measured by VD_POLL_INTERVAL - targ_time is more than poll_min + * the wait function is called and its time measured and wait cycles adjusted. + * The wait allows hardware to advance, when no data activity from the vdebug occurs + */ +static int vdebug_poll(void *priv) +{ + int64_t ts, te; + + ts = timeval_ms(); + if (ts - vdc.poll_ts - vdc.targ_time >= vdc.poll_min) { + vdebug_wait(vdc.hsocket, pbuf, vdc.poll_cycles); + te = timeval_ms(); + LOG_DEBUG("poll after %" PRId64 "ms, busy %" PRIu32 "ms; wait %" PRIu32 " %" PRId64 "ms", + ts - vdc.poll_ts, vdc.targ_time, vdc.poll_cycles, te - ts); + + if (te - ts + vdc.targ_time < vdc.poll_max / 2) + vdc.poll_cycles *= 2; + else if (te - ts + vdc.targ_time > vdc.poll_max) + vdc.poll_cycles /= 2; + } else { + LOG_DEBUG("poll after %" PRId64 "ms, busy %" PRIu32 "ms", ts - vdc.poll_ts, vdc.targ_time); + } + vdc.poll_ts = ts; + vdc.targ_time = 0; /* reset target time counter */ + + return ERROR_OK; +} + static int vdebug_init(void) { vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port); @@ -858,6 +889,7 @@ static int vdebug_init(void) } vdc.trans_first = 1; vdc.poll_cycles = vdc.poll_max; + vdc.poll_ts = timeval_ms(); uint32_t sig_mask = VD_SIG_RESET; if (transport_is_jtag()) sig_mask |= VD_SIG_TRST | VD_SIG_TCKDIV; @@ -876,6 +908,8 @@ static int vdebug_init(void) LOG_ERROR("0x%x cannot connect to %s", rc, vdc.mem_path[i]); } + target_register_timer_callback(vdebug_poll, VD_POLL_INTERVAL, + TARGET_TIMER_TYPE_PERIODIC, &vdc); LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16, VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port); } @@ -885,6 +919,8 @@ static int vdebug_init(void) static int vdebug_quit(void) { + target_unregister_timer_callback(vdebug_poll, &vdc); + for (uint8_t i = 0; i < vdc.mem_ndx; i++) if (vdc.mem_width[i]) vdebug_mem_close(vdc.hsocket, pbuf, i); @@ -1299,16 +1335,16 @@ static const struct command_registration vdebug_command_handlers[] = { { .name = "batching", .handler = &vdebug_set_batching, - .mode = COMMAND_CONFIG, + .mode = COMMAND_ANY, .help = "set the transaction batching no|wr|rd [0|1|2]", .usage = "", }, { .name = "polling", .handler = &vdebug_set_polling, - .mode = COMMAND_CONFIG, - .help = "set the polling pause, executing hardware cycles between min and max", - .usage = " ", + .mode = COMMAND_ANY, + .help = "set the min idle time and max wait time in ms", + .usage = " ", }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index d1bb705908..a2b0dd213e 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -428,7 +428,7 @@ static bool usb_connect(void) /* Log the results */ if (result == 0) - LOG_INFO("XDS110: connected"); + LOG_DEBUG("XDS110: connected"); else LOG_ERROR("XDS110: failed to connect"); @@ -448,7 +448,7 @@ static void usb_disconnect(void) xds110.ctx = NULL; } - LOG_INFO("XDS110: disconnected"); + LOG_DEBUG("XDS110: disconnected"); } static bool usb_read(unsigned char *buffer, int size, int *bytes_read, @@ -1551,42 +1551,42 @@ static void xds110_flush(void) while (xds110.txn_requests[request] != 0) { command = xds110.txn_requests[request++]; switch (command) { - case CMD_IR_SCAN: - case CMD_DR_SCAN: - if (command == CMD_IR_SCAN) - shift_state = XDS_JTAG_STATE_SHIFT_IR; - else - shift_state = XDS_JTAG_STATE_SHIFT_DR; - end_state = (uint32_t)(xds110.txn_requests[request++]); - bits = (uint32_t)(xds110.txn_requests[request++]) << 0; - bits |= (uint32_t)(xds110.txn_requests[request++]) << 8; - data_out = &xds110.txn_requests[request]; - bytes = DIV_ROUND_UP(bits, 8); - xds110_legacy_scan(shift_state, bits, end_state, data_out, - &data_in[result]); - result += bytes; - request += bytes; - break; - case CMD_RUNTEST: - clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; - end_state = (uint32_t)xds110.txn_requests[request++]; - xds110_legacy_runtest(clocks, end_state); - break; - case CMD_STABLECLOCKS: - clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; - clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; - xds110_legacy_stableclocks(clocks); - break; - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", - command); - exit(-1); - break; + case CMD_IR_SCAN: + case CMD_DR_SCAN: + if (command == CMD_IR_SCAN) + shift_state = XDS_JTAG_STATE_SHIFT_IR; + else + shift_state = XDS_JTAG_STATE_SHIFT_DR; + end_state = (uint32_t)(xds110.txn_requests[request++]); + bits = (uint32_t)(xds110.txn_requests[request++]) << 0; + bits |= (uint32_t)(xds110.txn_requests[request++]) << 8; + data_out = &xds110.txn_requests[request]; + bytes = DIV_ROUND_UP(bits, 8); + xds110_legacy_scan(shift_state, bits, end_state, data_out, + &data_in[result]); + result += bytes; + request += bytes; + break; + case CMD_RUNTEST: + clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; + end_state = (uint32_t)xds110.txn_requests[request++]; + xds110_legacy_runtest(clocks, end_state); + break; + case CMD_STABLECLOCKS: + clocks = (uint32_t)(xds110.txn_requests[request++]) << 0; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 8; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 16; + clocks |= (uint32_t)(xds110.txn_requests[request++]) << 24; + xds110_legacy_stableclocks(clocks); + break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", + command); + exit(-1); + break; } } } @@ -1809,32 +1809,32 @@ static void xds110_queue_stableclocks(struct jtag_command *cmd) static void xds110_execute_command(struct jtag_command *cmd) { switch (cmd->type) { - case JTAG_SLEEP: - xds110_flush(); - xds110_execute_sleep(cmd); - break; - case JTAG_TLR_RESET: - xds110_flush(); - xds110_execute_tlr_reset(cmd); - break; - case JTAG_PATHMOVE: - xds110_flush(); - xds110_execute_pathmove(cmd); - break; - case JTAG_SCAN: - xds110_queue_scan(cmd); - break; - case JTAG_RUNTEST: - xds110_queue_runtest(cmd); - break; - case JTAG_STABLECLOCKS: - xds110_queue_stableclocks(cmd); - break; - case JTAG_TMS: - default: - LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", - cmd->type); - exit(-1); + case JTAG_SLEEP: + xds110_flush(); + xds110_execute_sleep(cmd); + break; + case JTAG_TLR_RESET: + xds110_flush(); + xds110_execute_tlr_reset(cmd); + break; + case JTAG_PATHMOVE: + xds110_flush(); + xds110_execute_pathmove(cmd); + break; + case JTAG_SCAN: + xds110_queue_scan(cmd); + break; + case JTAG_RUNTEST: + xds110_queue_runtest(cmd); + break; + case JTAG_STABLECLOCKS: + xds110_queue_stableclocks(cmd); + break; + case JTAG_TMS: + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%x encountered", + cmd->type); + exit(-1); } } diff --git a/src/jtag/drivers/xlnx-pcie-xvc.c b/src/jtag/drivers/xlnx-xvc.c similarity index 50% rename from src/jtag/drivers/xlnx-pcie-xvc.c rename to src/jtag/drivers/xlnx-xvc.c index 3baa183d95..f00650671d 100644 --- a/src/jtag/drivers/xlnx-pcie-xvc.c +++ b/src/jtag/drivers/xlnx-xvc.c @@ -1,8 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2019 Google, LLC. - * Author: Moritz Fischer + * Copyright (C) 2019 Google, LLC. + * Moritz Fischer + * + * Copyright (C) 2021 Western Digital Corporation or its affiliates + * Jeremy Garff + * + * Copyright (C) 2024 Inria + * Nicolas Derumigny */ #ifdef HAVE_CONFIG_H @@ -11,13 +17,14 @@ #include #include -#include #include #include +#include #include -#include #include +#include +#include #include #include @@ -28,14 +35,24 @@ #define PCIE_EXT_CAP_LST 0x100 -#define XLNX_XVC_EXT_CAP 0x00 -#define XLNX_XVC_VSEC_HDR 0x04 -#define XLNX_XVC_LEN_REG 0x0C -#define XLNX_XVC_TMS_REG 0x10 -#define XLNX_XVC_TDX_REG 0x14 +#define XLNX_PCIE_XVC_EXT_CAP 0x00 +#define XLNX_PCIE_XVC_VSEC_HDR 0x04 +#define XLNX_PCIE_XVC_LEN_REG 0x0C +#define XLNX_PCIE_XVC_TMS_REG 0x10 +#define XLNX_PCIE_XVC_TDX_REG 0x14 + +#define XLNX_PCIE_XVC_CAP_SIZE 0x20 +#define XLNX_PCIE_XVC_VSEC_ID 0x8 + +#define XLNX_AXI_XVC_LEN_REG 0x00 +#define XLNX_AXI_XVC_TMS_REG 0x04 +#define XLNX_AXI_XVC_TDI_REG 0x08 +#define XLNX_AXI_XVC_TDO_REG 0x0c +#define XLNX_AXI_XVC_CTRL_REG 0x10 +#define XLNX_AXI_XVC_MAX_REG 0x18 + +#define XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK 0x01 -#define XLNX_XVC_CAP_SIZE 0x20 -#define XLNX_XVC_VSEC_ID 0x8 #define XLNX_XVC_MAX_BITS 0x20 #define MASK_ACK(x) (((x) >> 9) & 0x7) @@ -47,8 +64,23 @@ struct xlnx_pcie_xvc { char *device; }; +struct xlnx_axi_xvc { + int fd; + uint32_t *base; + char *device_addr; + // Defaults to `/dev/mem` if NULL + char *device_file; +}; + +enum xlnx_xvc_type_t { + PCIE, + AXI +}; + static struct xlnx_pcie_xvc xlnx_pcie_xvc_state; static struct xlnx_pcie_xvc *xlnx_pcie_xvc = &xlnx_pcie_xvc_state; +static struct xlnx_axi_xvc xlnx_axi_xvc_state; +static struct xlnx_axi_xvc *xlnx_axi_xvc = &xlnx_axi_xvc_state; static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) { @@ -60,9 +92,9 @@ static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) * space accessor functions */ err = pread(xlnx_pcie_xvc->fd, &res, sizeof(res), - xlnx_pcie_xvc->offset + offset); + xlnx_pcie_xvc->offset + offset); if (err != sizeof(res)) { - LOG_ERROR("Failed to read offset %x", offset); + LOG_ERROR("Failed to read offset 0x%x", offset); return ERROR_JTAG_DEVICE_ERROR; } @@ -72,6 +104,19 @@ static int xlnx_pcie_xvc_read_reg(const int offset, uint32_t *val) return ERROR_OK; } +static int xlnx_axi_xvc_read_reg(const int offset, uint32_t *val) +{ + uintptr_t b = ((uintptr_t)xlnx_axi_xvc->base) + offset; + volatile uint32_t *w = (uint32_t *)b; + + if (val) { + __atomic_thread_fence(__ATOMIC_SEQ_CST); + *val = *w; + } + + return ERROR_OK; +} + static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) { int err; @@ -81,9 +126,9 @@ static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) * space accessor functions */ err = pwrite(xlnx_pcie_xvc->fd, &val, sizeof(val), - xlnx_pcie_xvc->offset + offset); + xlnx_pcie_xvc->offset + offset); if (err != sizeof(val)) { - LOG_ERROR("Failed to write offset: %x with value: %" PRIx32, + LOG_ERROR("Failed to write offset: 0x%x with value: %" PRIx32, offset, val); return ERROR_JTAG_DEVICE_ERROR; } @@ -91,37 +136,117 @@ static int xlnx_pcie_xvc_write_reg(const int offset, const uint32_t val) return ERROR_OK; } +static int xlnx_axi_xvc_write_reg(const int offset, const uint32_t val) +{ + uintptr_t b = ((uintptr_t)xlnx_axi_xvc->base) + offset; + volatile uint32_t *w = (uint32_t *)b; + + *w = val; + __atomic_thread_fence(__ATOMIC_SEQ_CST); + + return ERROR_OK; +} + static int xlnx_pcie_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, uint32_t *tdo) { int err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_LEN_REG, num_bits); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_XVC_LEN_REG, num_bits); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TMS_REG, tms); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_XVC_TMS_REG, tms); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_write_reg(XLNX_XVC_TDX_REG, tdi); + err = xlnx_pcie_xvc_write_reg(XLNX_PCIE_XVC_TDX_REG, tdi); if (err != ERROR_OK) return err; - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_TDX_REG, tdo); + err = xlnx_pcie_xvc_read_reg(XLNX_PCIE_XVC_TDX_REG, tdo); if (err != ERROR_OK) return err; if (tdo) LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: %" PRIx32, - num_bits, tms, tdi, *tdo); + num_bits, tms, tdi, *tdo); else LOG_DEBUG_IO("Transact num_bits: %zu, tms: %" PRIx32 ", tdi: %" PRIx32 ", tdo: ", - num_bits, tms, tdi); + num_bits, tms, tdi); + return ERROR_OK; +} + +static int xlnx_axi_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo) +{ + uint32_t ctrl; + int done = 0; + int err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_LEN_REG, num_bits); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_TMS_REG, tms); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_TDI_REG, tdi); + if (err != ERROR_OK) + return err; + + err = xlnx_axi_xvc_write_reg(XLNX_AXI_XVC_CTRL_REG, XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK); + if (err != ERROR_OK) + return err; + + while (!done) { + err = xlnx_axi_xvc_read_reg(XLNX_AXI_XVC_CTRL_REG, &ctrl); + if (err != ERROR_OK) + return err; + + if (!(ctrl & XLNX_AXI_XVC_CTRL_REG_ENABLE_MASK)) + done = 1; + + /* + There is no delay here intentionally. The usleep() + function doesn't block and burns CPU cycles anyway. + The turnaround time is fast enough at high JTAG rates + that adding the call can slow down the overall + throughput. So we'll just sacrifice the CPU to get + best performance. + + Additionally there is no timeout. The underlying + hardware is guaranteed to unset the enable bit within + 32 JTAG clock cycles. There is no hardware condition + that will keep it set forever. Essentially, the hardware + is also our timeout mechanism. + */ + } + + err = xlnx_axi_xvc_read_reg(XLNX_AXI_XVC_TDO_REG, tdo); + if (err != ERROR_OK) + return err; + + if (tdo) + LOG_DEBUG_IO("Transact num_bits: %zu, tms: 0x%x, tdi: 0x%x, tdo: 0x%x", + num_bits, tms, tdi, *tdo); + else + LOG_DEBUG_IO("Transact num_bits: %zu, tms: 0x%x, tdi: 0x%x, tdo: ", + num_bits, tms, tdi); return ERROR_OK; } -static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) +static int xlnx_xvc_transact(size_t num_bits, uint32_t tms, uint32_t tdi, + uint32_t *tdo, enum xlnx_xvc_type_t xvc_type) +{ + if (xvc_type == PCIE) + return xlnx_pcie_xvc_transact(num_bits, tms, tdi, tdo); + assert(xvc_type == AXI); + return xlnx_axi_xvc_transact(num_bits, tms, tdi, tdo); +} + +static int xlnx_xvc_execute_stableclocks(struct jtag_command *cmd, enum xlnx_xvc_type_t xvc_type) { int tms = tap_get_state() == TAP_RESET ? 1 : 0; size_t left = cmd->cmd.stableclocks->num_cycles; @@ -132,7 +257,7 @@ static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); - err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + err = xlnx_xvc_transact(write, tms, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -141,12 +266,12 @@ static int xlnx_pcie_xvc_execute_stableclocks(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_statemove(size_t skip) +static int xlnx_xvc_execute_statemove(size_t skip, enum xlnx_xvc_type_t xvc_type) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), - tap_get_end_state()); + tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), - tap_get_end_state()); + tap_get_end_state()); int err; LOG_DEBUG("statemove starting at (skip: %zu) %s end in %s", skip, @@ -154,7 +279,7 @@ static int xlnx_pcie_xvc_execute_statemove(size_t skip) tap_state_name(tap_get_end_state())); - err = xlnx_pcie_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL); + err = xlnx_xvc_transact(tms_count - skip, tms_scan >> skip, 0, NULL, xvc_type); if (err != ERROR_OK) return err; @@ -163,7 +288,8 @@ static int xlnx_pcie_xvc_execute_statemove(size_t skip) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) +static int xlnx_xvc_execute_runtest(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { int err = ERROR_OK; @@ -175,7 +301,7 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) if (tap_get_state() != TAP_IDLE) { tap_set_end_state(TAP_IDLE); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) return err; }; @@ -185,7 +311,7 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); - err = xlnx_pcie_xvc_transact(write, 0, 0, NULL); + err = xlnx_xvc_transact(write, 0, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -193,12 +319,13 @@ static int xlnx_pcie_xvc_execute_runtest(struct jtag_command *cmd) tap_set_end_state(tmp_state); if (tap_get_state() != tap_get_end_state()) - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); return err; } -static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) +static int xlnx_xvc_execute_pathmove(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { unsigned int num_states = cmd->cmd.pathmove->num_states; enum tap_state *path = cmd->cmd.pathmove->path; @@ -210,9 +337,9 @@ static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) for (unsigned int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) { - err = xlnx_pcie_xvc_transact(1, 1, 0, NULL); + err = xlnx_xvc_transact(1, 0, 0, NULL, xvc_type); } else if (path[i] == tap_state_transition(tap_get_state(), true)) { - err = xlnx_pcie_xvc_transact(1, 0, 0, NULL); + err = xlnx_xvc_transact(1, 1, 0, NULL, xvc_type); } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition.", tap_state_name(tap_get_state()), @@ -229,7 +356,8 @@ static int xlnx_pcie_xvc_execute_pathmove(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) +static int xlnx_xvc_execute_scan(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { enum scan_type type = jtag_scan_type(cmd->cmd.scan); enum tap_state saved_end_state = cmd->cmd.scan->end_state; @@ -253,13 +381,13 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) */ if (ir_scan && tap_get_state() != TAP_IRSHIFT) { tap_set_end_state(TAP_IRSHIFT); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); } else if (!ir_scan && (tap_get_state() != TAP_DRSHIFT)) { tap_set_end_state(TAP_DRSHIFT); - err = xlnx_pcie_xvc_execute_statemove(0); + err = xlnx_xvc_execute_statemove(0, xvc_type); if (err != ERROR_OK) goto out_err; tap_set_end_state(saved_end_state); @@ -271,8 +399,8 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) /* the last TMS should be a 1, to leave the state */ tms = left <= XLNX_XVC_MAX_BITS ? BIT(write - 1) : 0; tdi = (type != SCAN_IN) ? buf_get_u32(rd_ptr, 0, write) : 0; - err = xlnx_pcie_xvc_transact(write, tms, tdi, type != SCAN_OUT ? - &tdo : NULL); + err = xlnx_xvc_transact(write, tms, tdi, type != SCAN_OUT ? + &tdo : NULL, xvc_type); if (err != ERROR_OK) goto out_err; left -= write; @@ -285,7 +413,7 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) free(buf); if (tap_get_state() != tap_get_end_state()) - err = xlnx_pcie_xvc_execute_statemove(1); + err = xlnx_xvc_execute_statemove(1, xvc_type); return err; @@ -294,19 +422,14 @@ static int xlnx_pcie_xvc_execute_scan(struct jtag_command *cmd) return err; } -static void xlnx_pcie_xvc_execute_reset(struct jtag_command *cmd) -{ - LOG_DEBUG("reset trst: %i srst: %i", cmd->cmd.reset->trst, - cmd->cmd.reset->srst); -} - -static void xlnx_pcie_xvc_execute_sleep(struct jtag_command *cmd) +static void xlnx_xvc_execute_sleep(struct jtag_command *cmd) { - LOG_DEBUG("sleep %" PRIu32 "", cmd->cmd.sleep->us); + LOG_DEBUG("sleep %" PRIu32, cmd->cmd.sleep->us); usleep(cmd->cmd.sleep->us); } -static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) +static int xlnx_xvc_execute_tms(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { const size_t num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; @@ -320,7 +443,7 @@ static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); tms = buf_get_u32(bits, 0, write); - err = xlnx_pcie_xvc_transact(write, tms, 0, NULL); + err = xlnx_xvc_transact(write, tms, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -330,29 +453,30 @@ static int xlnx_pcie_xvc_execute_tms(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) +static int xlnx_xvc_execute_command(struct jtag_command *cmd, + enum xlnx_xvc_type_t xvc_type) { LOG_DEBUG("%s: cmd->type: %u", __func__, cmd->type); switch (cmd->type) { case JTAG_STABLECLOCKS: - return xlnx_pcie_xvc_execute_stableclocks(cmd); + return xlnx_xvc_execute_stableclocks(cmd, xvc_type); case JTAG_RUNTEST: - return xlnx_pcie_xvc_execute_runtest(cmd); + return xlnx_xvc_execute_runtest(cmd, xvc_type); case JTAG_TLR_RESET: tap_set_end_state(cmd->cmd.statemove->end_state); - return xlnx_pcie_xvc_execute_statemove(0); + return xlnx_xvc_execute_statemove(0, xvc_type); case JTAG_PATHMOVE: - return xlnx_pcie_xvc_execute_pathmove(cmd); + return xlnx_xvc_execute_pathmove(cmd, xvc_type); case JTAG_SCAN: - return xlnx_pcie_xvc_execute_scan(cmd); + return xlnx_xvc_execute_scan(cmd, xvc_type); case JTAG_RESET: - xlnx_pcie_xvc_execute_reset(cmd); + LOG_INFO("WARN: XVC driver has no reset."); break; case JTAG_SLEEP: - xlnx_pcie_xvc_execute_sleep(cmd); + xlnx_xvc_execute_sleep(cmd); break; case JTAG_TMS: - return xlnx_pcie_xvc_execute_tms(cmd); + return xlnx_xvc_execute_tms(cmd, xvc_type); default: LOG_ERROR("BUG: Unknown JTAG command type encountered."); return ERROR_JTAG_QUEUE_FAILED; @@ -361,13 +485,14 @@ static int xlnx_pcie_xvc_execute_command(struct jtag_command *cmd) return ERROR_OK; } -static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) +static int xlnx_xvc_execute_queue(struct jtag_command *cmd_queue, + enum xlnx_xvc_type_t xvc_type) { struct jtag_command *cmd = cmd_queue; int ret; while (cmd) { - ret = xlnx_pcie_xvc_execute_command(cmd); + ret = xlnx_xvc_execute_command(cmd, xvc_type); if (ret != ERROR_OK) return ret; @@ -378,6 +503,15 @@ static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) return ERROR_OK; } +static int xlnx_pcie_xvc_execute_queue(struct jtag_command *cmd_queue) +{ + return xlnx_xvc_execute_queue(cmd_queue, PCIE); +} + +static int xlnx_axi_xvc_execute_queue(struct jtag_command *cmd_queue) +{ + return xlnx_xvc_execute_queue(cmd_queue, AXI); +} static int xlnx_pcie_xvc_init(void) { @@ -399,8 +533,8 @@ static int xlnx_pcie_xvc_init(void) * vendor specific header */ xlnx_pcie_xvc->offset = PCIE_EXT_CAP_LST; while (xlnx_pcie_xvc->offset <= PCI_CFG_SPACE_EXP_SIZE - sizeof(cap) && - xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_EXT_CAP, &cap); + xlnx_pcie_xvc->offset >= PCIE_EXT_CAP_LST) { + err = xlnx_pcie_xvc_read_reg(XLNX_PCIE_XVC_EXT_CAP, &cap); if (err != ERROR_OK) return err; LOG_DEBUG("Checking capability at 0x%x; id=0x%04" PRIx32 " version=0x%" PRIx32 " next=0x%" PRIx32, @@ -409,7 +543,7 @@ static int xlnx_pcie_xvc_init(void) PCI_EXT_CAP_VER(cap), PCI_EXT_CAP_NEXT(cap)); if (PCI_EXT_CAP_ID(cap) == PCI_EXT_CAP_ID_VNDR) { - err = xlnx_pcie_xvc_read_reg(XLNX_XVC_VSEC_HDR, &vh); + err = xlnx_pcie_xvc_read_reg(XLNX_PCIE_XVC_VSEC_HDR, &vh); if (err != ERROR_OK) return err; LOG_DEBUG("Checking possible match at 0x%x; id: 0x%" PRIx32 "; rev: 0x%" PRIx32 "; length: 0x%" PRIx32, @@ -417,14 +551,14 @@ static int xlnx_pcie_xvc_init(void) PCI_VNDR_HEADER_ID(vh), PCI_VNDR_HEADER_REV(vh), PCI_VNDR_HEADER_LEN(vh)); - if ((PCI_VNDR_HEADER_ID(vh) == XLNX_XVC_VSEC_ID) && - (PCI_VNDR_HEADER_LEN(vh) == XLNX_XVC_CAP_SIZE)) + if ((PCI_VNDR_HEADER_ID(vh) == XLNX_PCIE_XVC_VSEC_ID) && + (PCI_VNDR_HEADER_LEN(vh) == XLNX_PCIE_XVC_CAP_SIZE)) break; } xlnx_pcie_xvc->offset = PCI_EXT_CAP_NEXT(cap); } - if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_XVC_CAP_SIZE) || - xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { + if ((xlnx_pcie_xvc->offset > PCI_CFG_SPACE_EXP_SIZE - XLNX_PCIE_XVC_CAP_SIZE) || + xlnx_pcie_xvc->offset < PCIE_EXT_CAP_LST) { close(xlnx_pcie_xvc->fd); return ERROR_JTAG_INIT_FAILED; } @@ -434,6 +568,44 @@ static int xlnx_pcie_xvc_init(void) return ERROR_OK; } +static int xlnx_axi_xvc_init(void) +{ + uint64_t baseaddr; + + if (xlnx_axi_xvc->device_addr) { + baseaddr = strtoul(xlnx_axi_xvc->device_addr, NULL, 0); + } else { + LOG_ERROR("Please set device addr."); + return ERROR_JTAG_INIT_FAILED; + } + + if (xlnx_axi_xvc->device_file) { + LOG_INFO("Opening %s for AXI communication", xlnx_axi_xvc->device_file); + xlnx_axi_xvc->fd = open(xlnx_axi_xvc->device_file, O_RDWR | O_SYNC); + } else { + LOG_INFO("Opening /dev/mem for AXI communication"); + xlnx_axi_xvc->fd = open("/dev/mem", O_RDWR | O_SYNC); + } + + if (xlnx_axi_xvc->fd < 0) { + LOG_ERROR("Failed to open device file, check permissions."); + return ERROR_JTAG_INIT_FAILED; + } + + xlnx_axi_xvc->base = mmap(0, XLNX_AXI_XVC_MAX_REG, PROT_READ | PROT_WRITE, + MAP_SHARED, xlnx_axi_xvc->fd, baseaddr); + if (xlnx_axi_xvc->base == MAP_FAILED) { + LOG_ERROR("mmap() failed, check permissions."); + close(xlnx_axi_xvc->fd); + return ERROR_JTAG_INIT_FAILED; + } + + LOG_INFO("Mapped Xilinx XVC/AXI vaddr %p paddr 0x%" PRIx64, + xlnx_axi_xvc->base, baseaddr); + + return ERROR_OK; +} + static int xlnx_pcie_xvc_quit(void) { int err; @@ -445,21 +617,55 @@ static int xlnx_pcie_xvc_quit(void) return ERROR_OK; } +static int xlnx_axi_xvc_quit(void) +{ + int err; + + munmap(xlnx_axi_xvc->base, XLNX_AXI_XVC_MAX_REG); + free(xlnx_pcie_xvc->device); + free(xlnx_axi_xvc->device_file); + free(xlnx_axi_xvc->device_addr); + + err = close(xlnx_axi_xvc->fd); + if (err) + return err; + + return ERROR_OK; +} + COMMAND_HANDLER(xlnx_pcie_xvc_handle_config_command) { - if (CMD_ARGC < 1) + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - /* we can't really free this in a safe manner, so at least - * limit the memory we're leaking by freeing the old one first - * before allocating a new one ... - */ free(xlnx_pcie_xvc->device); xlnx_pcie_xvc->device = strdup(CMD_ARGV[0]); return ERROR_OK; } +COMMAND_HANDLER(xlnx_axi_xvc_handle_dev_addr_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(xlnx_axi_xvc->device_addr); + + xlnx_axi_xvc->device_addr = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + +COMMAND_HANDLER(xlnx_axi_xvc_handle_dev_file_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(xlnx_axi_xvc->device_file); + + xlnx_axi_xvc->device_file = strdup(CMD_ARGV[0]); + return ERROR_OK; +} + static const struct command_registration xlnx_pcie_xvc_subcommand_handlers[] = { { .name = "config", @@ -482,11 +688,45 @@ static const struct command_registration xlnx_pcie_xvc_command_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration xlnx_axi_xvc_subcommand_handlers[] = { + { + .name = "dev_addr", + .handler = xlnx_axi_xvc_handle_dev_addr_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/AXI JTAG device memory address", + .usage = "addr", + }, + { + .name = "dev_file", + .handler = xlnx_axi_xvc_handle_dev_file_command, + .mode = COMMAND_CONFIG, + .help = "Configure XVC/AXI JTAG device file location", + .usage = "addr", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration xlnx_axi_xvc_command_handlers[] = { + { + .name = "xlnx_axi_xvc", + .mode = COMMAND_ANY, + .help = "perform xlnx_axi_xvc management", + .chain = xlnx_axi_xvc_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + static struct jtag_interface xlnx_pcie_xvc_jtag_ops = { .execute_queue = &xlnx_pcie_xvc_execute_queue, }; -static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) +static struct jtag_interface xlnx_axi_xvc_jtag_ops = { + .execute_queue = &xlnx_axi_xvc_execute_queue, +}; + +static int xlnx_xvc_swd_sequence(const uint8_t *seq, size_t length, + enum xlnx_xvc_type_t xvc_type) { size_t left, write; uint32_t send; @@ -496,7 +736,7 @@ static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) while (left) { write = MIN(XLNX_XVC_MAX_BITS, left); send = buf_get_u32(seq, 0, write); - err = xlnx_pcie_xvc_transact(write, send, 0, NULL); + err = xlnx_xvc_transact(write, send, 0, NULL, xvc_type); if (err != ERROR_OK) return err; left -= write; @@ -506,21 +746,22 @@ static int xlnx_pcie_xvc_swd_sequence(const uint8_t *seq, size_t length) return ERROR_OK; } -static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) +static int xlnx_xvc_swd_switch_seq(enum swd_special_seq seq, + enum xlnx_xvc_type_t xvc_type) { switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_line_reset, - swd_seq_line_reset_len); + return xlnx_xvc_swd_sequence(swd_seq_line_reset, + swd_seq_line_reset_len, xvc_type); case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_jtag_to_swd, - swd_seq_jtag_to_swd_len); + return xlnx_xvc_swd_sequence(swd_seq_jtag_to_swd, + swd_seq_jtag_to_swd_len, xvc_type); case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); - return xlnx_pcie_xvc_swd_sequence(swd_seq_swd_to_jtag, - swd_seq_swd_to_jtag_len); + return xlnx_xvc_swd_sequence(swd_seq_swd_to_jtag, + swd_seq_swd_to_jtag_len, xvc_type); default: LOG_ERROR("Sequence %d not supported", seq); return ERROR_FAIL; @@ -529,19 +770,31 @@ static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) return ERROR_OK; } +static int xlnx_pcie_xvc_swd_switch_seq(enum swd_special_seq seq) +{ + return xlnx_xvc_swd_switch_seq(seq, PCIE); +} + +static int xlnx_axi_xvc_swd_switch_seq(enum swd_special_seq seq) +{ + return xlnx_xvc_swd_switch_seq(seq, AXI); +} + static int queued_retval; -static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, - uint32_t ap_delay_clk); +static void xlnx_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type); -static void swd_clear_sticky_errors(void) +static void swd_clear_sticky_errors(enum xlnx_xvc_type_t xvc_type) { - xlnx_pcie_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), - STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0); + xlnx_xvc_swd_write_reg(swd_cmd(false, false, DP_ABORT), + STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR, 0, xvc_type); } -static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, - uint32_t ap_delay_clk) +static void xlnx_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type) { uint32_t res, ack, rpar; int err; @@ -550,23 +803,23 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + ack */ - err = xlnx_pcie_xvc_transact(12, cmd, 0, &res); + err = xlnx_xvc_transact(12, cmd, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* read data */ - err = xlnx_pcie_xvc_transact(32, 0, 0, &res); + err = xlnx_xvc_transact(32, 0, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; /* parity + trn */ - err = xlnx_pcie_xvc_transact(2, 0, 0, &rpar); + err = xlnx_xvc_transact(2, 0, 0, &rpar, xvc_type); if (err != ERROR_OK) goto err_out; - LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + LOG_DEBUG("%s %s %s reg %X = %08" PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", @@ -583,19 +836,19 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, if (value) *value = res; if (cmd & SWD_CMD_APNDP) - err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + err = xlnx_xvc_transact(ap_delay_clk, 0, 0, NULL, xvc_type); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); - swd_clear_sticky_errors(); + swd_clear_sticky_errors(xvc_type); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: - LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + LOG_DEBUG_IO("No valid acknowledge: ack=%02" PRIx32, ack); queued_retval = ack; return; } @@ -603,8 +856,21 @@ static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, queued_retval = err; } -static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, +static void xlnx_pcie_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_read_reg(cmd, value, ap_delay_clk, PCIE); +} + +static void xlnx_axi_xvc_swd_read_reg(uint8_t cmd, uint32_t *value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_read_reg(cmd, value, ap_delay_clk, AXI); +} + +static void xlnx_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk, + enum xlnx_xvc_type_t xvc_type) { uint32_t res, ack; int err; @@ -613,23 +879,23 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, cmd |= SWD_CMD_START | SWD_CMD_PARK; /* cmd + trn + ack */ - err = xlnx_pcie_xvc_transact(13, cmd, 0, &res); + err = xlnx_xvc_transact(13, cmd, 0, &res, xvc_type); if (err != ERROR_OK) goto err_out; ack = MASK_ACK(res); /* write data */ - err = xlnx_pcie_xvc_transact(32, value, 0, NULL); + err = xlnx_xvc_transact(32, value, 0, NULL, xvc_type); if (err != ERROR_OK) goto err_out; /* parity + trn */ - err = xlnx_pcie_xvc_transact(2, parity_u32(value), 0, NULL); + err = xlnx_xvc_transact(2, parity_u32(value), 0, NULL, xvc_type); if (err != ERROR_OK) goto err_out; - LOG_DEBUG("%s %s %s reg %X = %08"PRIx32, + LOG_DEBUG("%s %s %s reg %X = %08" PRIx32, ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK", cmd & SWD_CMD_APNDP ? "AP" : "DP", @@ -640,19 +906,19 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, switch (ack) { case SWD_ACK_OK: if (cmd & SWD_CMD_APNDP) - err = xlnx_pcie_xvc_transact(ap_delay_clk, 0, 0, NULL); + err = xlnx_xvc_transact(ap_delay_clk, 0, 0, NULL, xvc_type); queued_retval = err; return; case SWD_ACK_WAIT: LOG_DEBUG_IO("SWD_ACK_WAIT"); - swd_clear_sticky_errors(); + swd_clear_sticky_errors(xvc_type); return; case SWD_ACK_FAULT: LOG_DEBUG_IO("SWD_ACK_FAULT"); queued_retval = ack; return; default: - LOG_DEBUG_IO("No valid acknowledge: ack=%02"PRIx32, ack); + LOG_DEBUG_IO("No valid acknowledge: ack=%02" PRIx32, ack); queued_retval = ack; return; } @@ -661,12 +927,24 @@ static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, queued_retval = err; } -static int xlnx_pcie_xvc_swd_run_queue(void) +static void xlnx_pcie_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_write_reg(cmd, value, ap_delay_clk, PCIE); +} + +static void xlnx_axi_xvc_swd_write_reg(uint8_t cmd, uint32_t value, + uint32_t ap_delay_clk) +{ + xlnx_xvc_swd_write_reg(cmd, value, ap_delay_clk, AXI); +} + +static int xlnx_xvc_swd_run_queue(enum xlnx_xvc_type_t xvc_type) { int err; /* we want at least 8 idle cycles between each transaction */ - err = xlnx_pcie_xvc_transact(8, 0, 0, NULL); + err = xlnx_xvc_transact(8, 0, 0, NULL, xvc_type); if (err != ERROR_OK) return err; @@ -677,19 +955,37 @@ static int xlnx_pcie_xvc_swd_run_queue(void) return err; } -static int xlnx_pcie_xvc_swd_init(void) +static int xlnx_pcie_xvc_swd_run_queue(void) +{ + return xlnx_xvc_swd_run_queue(PCIE); +} + +static int xlnx_axi_xvc_swd_run_queue(void) +{ + return xlnx_xvc_swd_run_queue(AXI); +} + +static int xlnx_xvc_swd_init(void) { return ERROR_OK; } static const struct swd_driver xlnx_pcie_xvc_swd_ops = { - .init = xlnx_pcie_xvc_swd_init, + .init = xlnx_xvc_swd_init, .switch_seq = xlnx_pcie_xvc_swd_switch_seq, .read_reg = xlnx_pcie_xvc_swd_read_reg, .write_reg = xlnx_pcie_xvc_swd_write_reg, .run = xlnx_pcie_xvc_swd_run_queue, }; +static const struct swd_driver xlnx_axi_xvc_swd_ops = { + .init = xlnx_xvc_swd_init, + .switch_seq = xlnx_axi_xvc_swd_switch_seq, + .read_reg = xlnx_axi_xvc_swd_read_reg, + .write_reg = xlnx_axi_xvc_swd_write_reg, + .run = xlnx_axi_xvc_swd_run_queue, +}; + struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .name = "xlnx_pcie_xvc", .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, @@ -702,3 +998,16 @@ struct adapter_driver xlnx_pcie_xvc_adapter_driver = { .jtag_ops = &xlnx_pcie_xvc_jtag_ops, .swd_ops = &xlnx_pcie_xvc_swd_ops, }; + +struct adapter_driver xlnx_axi_xvc_adapter_driver = { + .name = "xlnx_axi_xvc", + .transport_ids = TRANSPORT_JTAG | TRANSPORT_SWD, + .transport_preferred_id = TRANSPORT_JTAG, + .commands = xlnx_axi_xvc_command_handlers, + + .init = &xlnx_axi_xvc_init, + .quit = &xlnx_axi_xvc_quit, + + .jtag_ops = &xlnx_axi_xvc_jtag_ops, + .swd_ops = &xlnx_axi_xvc_swd_ops, +}; diff --git a/src/jtag/interface.c b/src/jtag/interface.c index 92c88ca934..23b5bcf4f1 100644 --- a/src/jtag/interface.c +++ b/src/jtag/interface.c @@ -67,28 +67,28 @@ int tap_move_ndx(enum tap_state astate) int ndx; switch (astate) { - case TAP_RESET: - ndx = 0; - break; - case TAP_IDLE: - ndx = 1; - break; - case TAP_DRSHIFT: - ndx = 2; - break; - case TAP_DRPAUSE: - ndx = 3; - break; - case TAP_IRSHIFT: - ndx = 4; - break; - case TAP_IRPAUSE: - ndx = 5; - break; - default: - LOG_ERROR("FATAL: unstable state \"%s\" in tap_move_ndx()", - tap_state_name(astate)); - exit(1); + case TAP_RESET: + ndx = 0; + break; + case TAP_IDLE: + ndx = 1; + break; + case TAP_DRSHIFT: + ndx = 2; + break; + case TAP_DRPAUSE: + ndx = 3; + break; + case TAP_IRSHIFT: + ndx = 4; + break; + case TAP_IRPAUSE: + ndx = 5; + break; + default: + LOG_ERROR("FATAL: unstable state \"%s\" in %s()", + tap_state_name(astate), __func__); + exit(1); } return ndx; @@ -205,16 +205,16 @@ bool tap_is_state_stable(enum tap_state astate) * (not value dependent like an array), and can also check bounds. */ switch (astate) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRSHIFT: - case TAP_DRPAUSE: - case TAP_IRSHIFT: - case TAP_IRPAUSE: - is_stable = true; - break; - default: - is_stable = false; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRSHIFT: + case TAP_DRPAUSE: + case TAP_IRSHIFT: + case TAP_IRPAUSE: + is_stable = true; + break; + default: + is_stable = false; } return is_stable; @@ -230,83 +230,83 @@ enum tap_state tap_state_transition(enum tap_state cur_state, bool tms) if (tms) { switch (cur_state) { - case TAP_RESET: - new_state = cur_state; - break; - case TAP_IDLE: - case TAP_DRUPDATE: - case TAP_IRUPDATE: - new_state = TAP_DRSELECT; - break; - case TAP_DRSELECT: - new_state = TAP_IRSELECT; - break; - case TAP_DRCAPTURE: - case TAP_DRSHIFT: - new_state = TAP_DREXIT1; - break; - case TAP_DREXIT1: - case TAP_DREXIT2: - new_state = TAP_DRUPDATE; - break; - case TAP_DRPAUSE: - new_state = TAP_DREXIT2; - break; - case TAP_IRSELECT: - new_state = TAP_RESET; - break; - case TAP_IRCAPTURE: - case TAP_IRSHIFT: - new_state = TAP_IREXIT1; - break; - case TAP_IREXIT1: - case TAP_IREXIT2: - new_state = TAP_IRUPDATE; - break; - case TAP_IRPAUSE: - new_state = TAP_IREXIT2; - break; - default: - LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); - exit(1); - break; + case TAP_RESET: + new_state = cur_state; + break; + case TAP_IDLE: + case TAP_DRUPDATE: + case TAP_IRUPDATE: + new_state = TAP_DRSELECT; + break; + case TAP_DRSELECT: + new_state = TAP_IRSELECT; + break; + case TAP_DRCAPTURE: + case TAP_DRSHIFT: + new_state = TAP_DREXIT1; + break; + case TAP_DREXIT1: + case TAP_DREXIT2: + new_state = TAP_DRUPDATE; + break; + case TAP_DRPAUSE: + new_state = TAP_DREXIT2; + break; + case TAP_IRSELECT: + new_state = TAP_RESET; + break; + case TAP_IRCAPTURE: + case TAP_IRSHIFT: + new_state = TAP_IREXIT1; + break; + case TAP_IREXIT1: + case TAP_IREXIT2: + new_state = TAP_IRUPDATE; + break; + case TAP_IRPAUSE: + new_state = TAP_IREXIT2; + break; + default: + LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); + exit(1); + break; } } else { switch (cur_state) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRUPDATE: - case TAP_IRUPDATE: - new_state = TAP_IDLE; - break; - case TAP_DRSELECT: - new_state = TAP_DRCAPTURE; - break; - case TAP_DRCAPTURE: - case TAP_DRSHIFT: - case TAP_DREXIT2: - new_state = TAP_DRSHIFT; - break; - case TAP_DREXIT1: - case TAP_DRPAUSE: - new_state = TAP_DRPAUSE; - break; - case TAP_IRSELECT: - new_state = TAP_IRCAPTURE; - break; - case TAP_IRCAPTURE: - case TAP_IRSHIFT: - case TAP_IREXIT2: - new_state = TAP_IRSHIFT; - break; - case TAP_IREXIT1: - case TAP_IRPAUSE: - new_state = TAP_IRPAUSE; - break; - default: - LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); - exit(1); - break; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRUPDATE: + case TAP_IRUPDATE: + new_state = TAP_IDLE; + break; + case TAP_DRSELECT: + new_state = TAP_DRCAPTURE; + break; + case TAP_DRCAPTURE: + case TAP_DRSHIFT: + case TAP_DREXIT2: + new_state = TAP_DRSHIFT; + break; + case TAP_DREXIT1: + case TAP_DRPAUSE: + new_state = TAP_DRPAUSE; + break; + case TAP_IRSELECT: + new_state = TAP_IRCAPTURE; + break; + case TAP_IRCAPTURE: + case TAP_IRSHIFT: + case TAP_IREXIT2: + new_state = TAP_IRSHIFT; + break; + case TAP_IREXIT1: + case TAP_IRPAUSE: + new_state = TAP_IRPAUSE; + break; + default: + LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); + exit(1); + break; } } diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 475dbed36e..51cbf9ac0d 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -371,6 +371,7 @@ int adapter_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, unsigned int traceclkin_freq, uint16_t *prescaler); int adapter_poll_trace(uint8_t *buf, size_t *size); +// Keep in alphabetic order this list of drivers extern struct adapter_driver am335xgpio_adapter_driver; extern struct adapter_driver amt_jtagaccel_adapter_driver; extern struct adapter_driver angie_adapter_driver; @@ -378,6 +379,7 @@ extern struct adapter_driver armjtagew_adapter_driver; extern struct adapter_driver at91rm9200_adapter_driver; extern struct adapter_driver bcm2835gpio_adapter_driver; extern struct adapter_driver buspirate_adapter_driver; +extern struct adapter_driver ch347_adapter_driver; extern struct adapter_driver cmsis_dap_adapter_driver; extern struct adapter_driver dmem_dap_adapter_driver; extern struct adapter_driver dummy_adapter_driver; @@ -410,6 +412,7 @@ extern struct adapter_driver usbprog_adapter_driver; extern struct adapter_driver vdebug_adapter_driver; extern struct adapter_driver vsllink_adapter_driver; extern struct adapter_driver xds110_adapter_driver; +extern struct adapter_driver xlnx_axi_xvc_adapter_driver; extern struct adapter_driver xlnx_pcie_xvc_adapter_driver; #endif /* OPENOCD_JTAG_INTERFACE_H */ diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index e49bd9e0f3..e29937b587 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -36,125 +36,132 @@ * drivers that were enabled by the @c configure script. */ struct adapter_driver *adapter_drivers[] = { -#if BUILD_PARPORT == 1 - &parport_adapter_driver, + // Keep in alphabetic order this list of drivers + +#if BUILD_AM335XGPIO == 1 + &am335xgpio_adapter_driver, #endif -#if BUILD_DUMMY == 1 - &dummy_adapter_driver, +#if BUILD_AMTJTAGACCEL == 1 + &amt_jtagaccel_adapter_driver, #endif -#if BUILD_FTDI == 1 - &ftdi_adapter_driver, +#if BUILD_ANGIE == 1 + &angie_adapter_driver, #endif -#if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1 - &usb_blaster_adapter_driver, +#if BUILD_ARMJTAGEW == 1 + &armjtagew_adapter_driver, #endif -#if BUILD_ESP_USB_JTAG == 1 - &esp_usb_adapter_driver, +#if BUILD_AT91RM9200 == 1 + &at91rm9200_adapter_driver, #endif -#if BUILD_JTAG_VPI == 1 - &jtag_vpi_adapter_driver, +#if BUILD_BCM2835GPIO == 1 + &bcm2835gpio_adapter_driver, #endif -#if BUILD_VDEBUG == 1 - &vdebug_adapter_driver, +#if BUILD_BUS_PIRATE == 1 + &buspirate_adapter_driver, #endif -#if BUILD_JTAG_DPI == 1 - &jtag_dpi_adapter_driver, +#if BUILD_CH347 == 1 + &ch347_adapter_driver, #endif -#if BUILD_FT232R == 1 - &ft232r_adapter_driver, +#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 + &cmsis_dap_adapter_driver, #endif -#if BUILD_AMTJTAGACCEL == 1 - &amt_jtagaccel_adapter_driver, +#if BUILD_DMEM == 1 + &dmem_dap_adapter_driver, +#endif +#if BUILD_DUMMY == 1 + &dummy_adapter_driver, #endif #if BUILD_EP93XX == 1 &ep93xx_adapter_driver, #endif -#if BUILD_AT91RM9200 == 1 - &at91rm9200_adapter_driver, +#if BUILD_ESP_USB_JTAG == 1 + &esp_usb_adapter_driver, +#endif +#if BUILD_FT232R == 1 + &ft232r_adapter_driver, +#endif +#if BUILD_FTDI == 1 + &ftdi_adapter_driver, #endif #if BUILD_GW16012 == 1 &gw16012_adapter_driver, #endif -#if BUILD_PRESTO - &presto_adapter_driver, -#endif -#if BUILD_USBPROG == 1 - &usbprog_adapter_driver, +#if BUILD_HLADAPTER == 1 + &hl_adapter_driver, #endif -#if BUILD_OPENJTAG == 1 - &openjtag_adapter_driver, +#if BUILD_IMX_GPIO == 1 + &imx_gpio_adapter_driver, #endif #if BUILD_JLINK == 1 &jlink_adapter_driver, #endif -#if BUILD_VSLLINK == 1 - &vsllink_adapter_driver, -#endif -#if BUILD_RLINK == 1 - &rlink_adapter_driver, +#if BUILD_JTAG_DPI == 1 + &jtag_dpi_adapter_driver, #endif -#if BUILD_ULINK == 1 - &ulink_adapter_driver, +#if BUILD_JTAG_VPI == 1 + &jtag_vpi_adapter_driver, #endif -#if BUILD_ANGIE == 1 - &angie_adapter_driver, +#if BUILD_KITPROG == 1 + &kitprog_adapter_driver, #endif -#if BUILD_ARMJTAGEW == 1 - &armjtagew_adapter_driver, +#if BUILD_LINUXGPIOD == 1 + &linuxgpiod_adapter_driver, #endif -#if BUILD_BUS_PIRATE == 1 - &buspirate_adapter_driver, +#if BUILD_LINUXSPIDEV == 1 + &linuxspidev_adapter_driver, #endif -#if BUILD_REMOTE_BITBANG == 1 - &remote_bitbang_adapter_driver, +#if BUILD_OPENDOUS == 1 + &opendous_adapter_driver, #endif -#if BUILD_HLADAPTER == 1 - &hl_adapter_driver, +#if BUILD_OPENJTAG == 1 + &openjtag_adapter_driver, #endif #if BUILD_OSBDM == 1 &osbdm_adapter_driver, #endif -#if BUILD_OPENDOUS == 1 - &opendous_adapter_driver, +#if BUILD_PARPORT == 1 + &parport_adapter_driver, #endif -#if BUILD_SYSFSGPIO == 1 - &sysfsgpio_adapter_driver, +#if BUILD_PRESTO == 1 + &presto_adapter_driver, #endif -#if BUILD_LINUXGPIOD == 1 - &linuxgpiod_adapter_driver, +#if BUILD_REMOTE_BITBANG == 1 + &remote_bitbang_adapter_driver, #endif -#if BUILD_LINUXSPIDEV == 1 - &linuxspidev_adapter_driver, +#if BUILD_RLINK == 1 + &rlink_adapter_driver, #endif -#if BUILD_XLNX_PCIE_XVC == 1 - &xlnx_pcie_xvc_adapter_driver, +#if BUILD_RSHIM == 1 + &rshim_dap_adapter_driver, #endif -#if BUILD_BCM2835GPIO == 1 - &bcm2835gpio_adapter_driver, +#if BUILD_HLADAPTER_STLINK == 1 + &stlink_dap_adapter_driver, #endif -#if BUILD_CMSIS_DAP_USB == 1 || BUILD_CMSIS_DAP_HID == 1 - &cmsis_dap_adapter_driver, +#if BUILD_SYSFSGPIO == 1 + &sysfsgpio_adapter_driver, #endif -#if BUILD_KITPROG == 1 - &kitprog_adapter_driver, +#if BUILD_ULINK == 1 + &ulink_adapter_driver, #endif -#if BUILD_IMX_GPIO == 1 - &imx_gpio_adapter_driver, +#if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1 + &usb_blaster_adapter_driver, #endif -#if BUILD_XDS110 == 1 - &xds110_adapter_driver, +#if BUILD_USBPROG == 1 + &usbprog_adapter_driver, #endif -#if BUILD_HLADAPTER_STLINK == 1 - &stlink_dap_adapter_driver, +#if BUILD_VDEBUG == 1 + &vdebug_adapter_driver, #endif -#if BUILD_RSHIM == 1 - &rshim_dap_adapter_driver, +#if BUILD_VSLLINK == 1 + &vsllink_adapter_driver, #endif -#if BUILD_DMEM == 1 - &dmem_dap_adapter_driver, +#if BUILD_XDS110 == 1 + &xds110_adapter_driver, #endif -#if BUILD_AM335XGPIO == 1 - &am335xgpio_adapter_driver, +#if BUILD_XLNX_XVC == 1 + &xlnx_pcie_xvc_adapter_driver, + &xlnx_axi_xvc_adapter_driver, #endif + NULL, - }; +}; diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index 2d8ebf0410..5c466c628a 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -359,6 +359,27 @@ proc parport_cable args { eval parport cable $args } +lappend _telnet_autocomplete_skip parport_select_cable +proc parport_select_cable {cable} { + echo "DEPRECATED! Do not use 'parport cable' but use a cable configuration file in interface/parport" + + switch $cable { + "wiggler" { source [find interface/parport/wiggler.cfg] } + "wiggler2" { source [find interface/parport/wiggler2.cfg] } + "wiggler_ntrst_inverted" { source [find interface/parport/wiggler-ntrst-inverted.cfg] } + "old_amt_wiggler" { source [find interface/parport/amt-wiggler-old.cfg ] } + "arm-jtag" { source [find interface/parport/arm-jtag.cfg] } + "chameleon" { source [find interface/parport/chameleon.cfg] } + "dlc5" { source [find interface/parport/dlc5.cfg] } + "triton" { source [find interface/parport/triton.cfg] } + "lattice" { source [find interface/parport/lattice.cfg] } + "flashlink" { source [find interface/parport/flashlink.cfg] } + "altium" { source [find interface/parport/altium.cfg] } + "aspo" { source [find interface/parport/aspo.cfg] } + default { error "invalid parallel port cable '$cable'" } + } +} + lappend _telnet_autocomplete_skip parport_write_on_exit proc parport_write_on_exit args { echo "DEPRECATED! use 'parport write_on_exit' not 'parport_write_on_exit'" @@ -413,6 +434,12 @@ proc xlnx_pcie_xvc_config args { eval xlnx_pcie_xvc config $args } +lappend _telnet_autocomplete_skip xlnx_axi_xvc_config +proc xlnx_axi_xvc_config args { + echo "DEPRECATED! use 'xlnx_axi_xvc config' not 'xlnx_axi_xvc_config'" + eval xlnx_axi_xvc config $args +} + lappend _telnet_autocomplete_skip ulink_download_firmware proc ulink_download_firmware args { echo "DEPRECATED! use 'ulink download_firmware' not 'ulink_download_firmware'" diff --git a/src/jtag/swd.h b/src/jtag/swd.h index 3fe1365b58..c4b6215abd 100644 --- a/src/jtag/swd.h +++ b/src/jtag/swd.h @@ -270,6 +270,7 @@ struct swd_driver { * @param Where to store value to read from register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs + * or zero in case of DP read. */ void (*read_reg)(uint8_t cmd, uint32_t *value, uint32_t ap_delay_hint); @@ -280,6 +281,7 @@ struct swd_driver { * @param Value to be written to the register * @param ap_delay_hint Number of idle cycles that may be * needed after an AP access to avoid WAITs + * or zero in case of DP write. */ void (*write_reg)(uint8_t cmd, uint32_t value, uint32_t ap_delay_hint); diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 8b0bc7affb..9cffd6b5d1 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -64,13 +64,13 @@ struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) static bool scan_is_safe(enum tap_state state) { switch (state) { - case TAP_RESET: - case TAP_IDLE: - case TAP_DRPAUSE: - case TAP_IRPAUSE: - return true; - default: - return false; + case TAP_RESET: + case TAP_IDLE: + case TAP_DRPAUSE: + case TAP_IRPAUSE: + return true; + default: + return false; } } @@ -558,18 +558,18 @@ static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) } switch (e) { - case JTAG_TAP_EVENT_ENABLE: - case JTAG_TAP_EVENT_DISABLE: - /* NOTE: we currently assume the handlers - * can't fail. Right here is where we should - * really be verifying the scan chains ... - */ - tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); - LOG_INFO("JTAG tap: %s %s", tap->dotted_name, + case JTAG_TAP_EVENT_ENABLE: + case JTAG_TAP_EVENT_DISABLE: + /* NOTE: we currently assume the handlers + * can't fail. Right here is where we should + * really be verifying the scan chains ... + */ + tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); + LOG_INFO("JTAG tap: %s %s", tap->dotted_name, tap->enabled ? "enabled" : "disabled"); - break; - default: - break; + break; + default: + break; } } } diff --git a/src/openocd.c b/src/openocd.c index 3fbece3955..f3e1bee48e 100644 --- a/src/openocd.c +++ b/src/openocd.c @@ -75,20 +75,20 @@ static int log_target_callback_event_handler(struct target *target, void *priv) { switch (event) { - case TARGET_EVENT_GDB_START: - target->verbose_halt_msg = false; - break; - case TARGET_EVENT_GDB_END: - target->verbose_halt_msg = true; - break; - case TARGET_EVENT_HALTED: - if (target->verbose_halt_msg) { - /* do not display information when debugger caused the halt */ - target_arch_state(target); - } - break; - default: - break; + case TARGET_EVENT_GDB_START: + target->verbose_halt_msg = false; + break; + case TARGET_EVENT_GDB_END: + target->verbose_halt_msg = true; + break; + case TARGET_EVENT_HALTED: + if (target->verbose_halt_msg) { + /* do not display information when debugger caused the halt */ + target_arch_state(target); + } + break; + default: + break; } return ERROR_OK; @@ -170,7 +170,8 @@ COMMAND_HANDLER(handle_init_command) jtag_poll_unmask(save_poll_mask); /* initialize telnet subsystem */ - gdb_target_add_all(all_targets); + if (gdb_target_add_all(all_targets) != ERROR_OK) + return ERROR_FAIL; target_register_event_callback(log_target_callback_event_handler, CMD_CTX); diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c index e4cc52ef97..1c04c74906 100644 --- a/src/pld/xilinx_bit.c +++ b/src/pld/xilinx_bit.c @@ -113,7 +113,7 @@ int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) return ERROR_PLD_FILE_LOAD_FAILED; } - LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32 "", bit_file->source_file, bit_file->part_name, + LOG_DEBUG("bit_file: %s %s %s,%s %" PRIu32, bit_file->source_file, bit_file->part_name, bit_file->date, bit_file->time, bit_file->length); fclose(input_file); diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index af590c2cb1..0cd99e4720 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -515,10 +515,10 @@ static int chibios_create(struct target *target) for (unsigned int i = 0; i < ARRAY_SIZE(chibios_params_list); i++) if (strcmp(chibios_params_list[i].target_name, target_type_name(target)) == 0) { target->rtos->rtos_specific_params = (void *)&chibios_params_list[i]; - return 0; + return ERROR_OK; } LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility " "list", target_type_name(target)); - return -1; + return ERROR_FAIL; } diff --git a/src/rtos/ecos.c b/src/rtos/ecos.c index 7048b006e0..41159bf094 100644 --- a/src/rtos/ecos.c +++ b/src/rtos/ecos.c @@ -539,7 +539,7 @@ static int ecos_check_app_info(struct rtos *rtos, struct ecos_params *param) return -1; if (param->flush_common) { - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { for (unsigned int idx = 0; idx < ARRAY_SIZE(ecos_symbol_list); idx++) { LOG_DEBUG("eCos: %s 0x%016" PRIX64 " %s", rtos->symbols[idx].optional ? "OPTIONAL" : " ", @@ -1004,7 +1004,7 @@ static int ecos_update_threads(struct rtos *rtos) if (tr_extra && reason_desc) soff += snprintf(&eistr[soff], (eilen - soff), " (%s)", reason_desc); if (pri_extra) - (void)snprintf(&eistr[soff], (eilen - soff), ", Priority: %" PRId64 "", priority); + (void)snprintf(&eistr[soff], (eilen - soff), ", Priority: %" PRId64, priority); rtos->thread_details[tasks_found].extra_info_str = eistr; rtos->thread_details[tasks_found].exists = true; @@ -1073,7 +1073,7 @@ static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, param->uid_width, (uint8_t *)&id); if (retval != ERROR_OK) { - LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32 "", thread_index); + LOG_ERROR("Error reading unique id from eCos thread 0x%08" PRIX32, thread_index); return retval; } @@ -1213,12 +1213,12 @@ static int ecos_create(struct target *target) target->rtos->gdb_thread_packet = ecos_packet_hook; /* We do not currently use the target->rtos->gdb_target_for_threadid * hook. */ - return 0; + return ERROR_OK; } tnames++; } } LOG_ERROR("Could not find target in eCos compatibility list"); - return -1; + return ERROR_FAIL; } diff --git a/src/rtos/embkernel.c b/src/rtos/embkernel.c index 7e6de7902a..7ad937be59 100644 --- a/src/rtos/embkernel.c +++ b/src/rtos/embkernel.c @@ -115,11 +115,11 @@ static int embkernel_create(struct target *target) if (i >= ARRAY_SIZE(embkernel_params_list)) { LOG_WARNING("Could not find target \"%s\" in embKernel compatibility " "list", target_type_name(target)); - return -1; + return ERROR_FAIL; } target->rtos->rtos_specific_params = (void *) &embkernel_params_list[i]; - return 0; + return ERROR_OK; } static int embkernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embkernel_params *param, diff --git a/src/rtos/hwthread.c b/src/rtos/hwthread.c index 3e4a4ec42d..5c0c0f07a0 100644 --- a/src/rtos/hwthread.c +++ b/src/rtos/hwthread.c @@ -211,8 +211,8 @@ static int hwthread_update_threads(struct rtos *rtos) else rtos->current_thread = threadid_from_target(target); - LOG_TARGET_DEBUG(target, "current_thread=%i, threads_found=%d", - (int)rtos->current_thread, threads_found); + LOG_TARGET_DEBUG(target, "current_thread=%" PRId64 ", threads_found=%d", + rtos->current_thread, threads_found); return 0; } @@ -422,7 +422,7 @@ static int hwthread_create(struct target *target) target->rtos->thread_details = NULL; target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid; target->rtos->gdb_thread_packet = hwthread_thread_packet; - return 0; + return ERROR_OK; } static bool hwthread_needs_fake_step(struct target *target, int64_t thread_id) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 5efdc9f609..5f59dc883a 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -1282,86 +1282,77 @@ static int linux_thread_packet(struct connection *connection, char const *packet target->rtos->rtos_specific_params; switch (packet[0]) { - case 'T': /* Is thread alive?*/ - - linux_gdb_t_packet(connection, target, packet, packet_size); - break; - case 'H': /* Set current thread */ - /* ( 'c' for step and continue, 'g' for all other operations )*/ - /*LOG_INFO(" H packet received '%s'", packet);*/ - linux_gdb_h_packet(connection, target, packet, packet_size); - break; - case 'q': - - if (strncmp(packet, "qSymbol", 7) == 0) { - if (rtos_qsymbol(connection, packet, packet_size) == 1) { - linux_compute_virt2phys(target, - target->rtos->symbols[INIT_TASK].address); - } - - break; - } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { - if (!linux_os->thread_list) { - retval = linux_gdb_thread_packet(target, - connection, - packet, - packet_size); - break; - } else { - retval = linux_gdb_thread_update(target, - connection, - packet, - packet_size); - break; - } - } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { - gdb_put_packet(connection, "l", 1); - break; - } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { - linux_thread_extra_info(target, connection, packet, + case 'T': /* Is thread alive?*/ + linux_gdb_t_packet(connection, target, packet, packet_size); + break; + + case 'H': /* Set current thread */ + /* ( 'c' for step and continue, 'g' for all other operations )*/ + /*LOG_INFO(" H packet received '%s'", packet);*/ + linux_gdb_h_packet(connection, target, packet, packet_size); + break; + + case 'q': + if (!strncmp(packet, "qSymbol", 7)) { + if (rtos_qsymbol(connection, packet, packet_size) == 1) { + linux_compute_virt2phys(target, + target->rtos->symbols[INIT_TASK].address); + } + } else if (!strncmp(packet, "qfThreadInfo", 12)) { + if (!linux_os->thread_list) { + retval = linux_gdb_thread_packet(target, + connection, + packet, packet_size); - break; } else { - retval = GDB_THREAD_PACKET_NOT_CONSUMED; - break; + retval = linux_gdb_thread_update(target, + connection, + packet, + packet_size); } - - case 'Q': - /* previously response was : thread not found - * gdb_put_packet(connection, "E01", 3); */ + } else if (!strncmp(packet, "qsThreadInfo", 12)) { + gdb_put_packet(connection, "l", 1); + } else if (!strncmp(packet, "qThreadExtraInfo,", 17)) { + linux_thread_extra_info(target, connection, packet, + packet_size); + } else { retval = GDB_THREAD_PACKET_NOT_CONSUMED; - break; - case 'c': - case 's': { - if (linux_os->threads_lookup == 1) { - ct = linux_os->current_threads; + } + break; - while ((ct) && (ct->core_id) != target->coreid) - ct = ct->next; + case 'Q': + /* previously response was : thread not found + * gdb_put_packet(connection, "E01", 3); */ + retval = GDB_THREAD_PACKET_NOT_CONSUMED; + break; - if ((ct) && (ct->threadid == -1)) { - ct = linux_os->current_threads; + case 'c': + case 's': + if (linux_os->threads_lookup == 1) { + ct = linux_os->current_threads; - while ((ct) && (ct->threadid == -1)) - ct = ct->next; - } + while ((ct) && (ct->core_id) != target->coreid) + ct = ct->next; - if ((ct) && (ct->threadid != - target->rtos->current_threadid) - && (target->rtos->current_threadid != -1)) - LOG_WARNING("WARNING! current GDB thread do not match " - "current thread running. " - "Switch thread in GDB to threadid %d", - (int)ct->threadid); + if ((ct) && (ct->threadid == -1)) { + ct = linux_os->current_threads; - LOG_INFO("threads_needs_update = 1"); - linux_os->threads_needs_update = 1; + while ((ct) && (ct->threadid == -1)) + ct = ct->next; } - } - /* if a packet handler returned an error, exit input loop */ - if (retval != ERROR_OK) - return retval; + if ((ct) && (ct->threadid != + target->rtos->current_threadid) + && (target->rtos->current_threadid != -1)) + LOG_WARNING("WARNING! current GDB thread do not match " + "current thread running. " + "Switch thread in GDB to threadid %d", + (int)ct->threadid); + + LOG_INFO("threads_needs_update = 1"); + linux_os->threads_needs_update = 1; + } + break; } return retval; @@ -1424,7 +1415,7 @@ static int linux_os_create(struct target *target) /* initialize a default virt 2 phys translation */ os_linux->phys_mask = ~0xc0000000; os_linux->phys_base = 0x0; - return JIM_OK; + return ERROR_OK; } static char *linux_ps_command(struct target *target) diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 017fd2b01c..dbb48952f2 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -251,11 +251,11 @@ static int mqx_create( if (strcmp(mqx_params_list[i].target_name, target_type_name(target)) == 0) { target->rtos->rtos_specific_params = (void *)&mqx_params_list[i]; /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target_type_name(target)); */ - return 0; + return ERROR_OK; } } LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target_type_name(target)); - return -1; + return ERROR_FAIL; } /* diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c index 821e550885..27bf086c83 100644 --- a/src/rtos/nuttx.c +++ b/src/rtos/nuttx.c @@ -129,13 +129,13 @@ static int nuttx_create(struct target *target) if (i >= ARRAY_SIZE(nuttx_params_list)) { LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target)); - return JIM_ERR; + return ERROR_FAIL; } /* We found a target in our list, copy its reference. */ target->rtos->rtos_specific_params = (void *)param; - return JIM_OK; + return ERROR_OK; } static int nuttx_smp_init(struct target *target) diff --git a/src/rtos/rtkernel.c b/src/rtos/rtkernel.c index aebbf3d94d..2be1996fcd 100644 --- a/src/rtos/rtkernel.c +++ b/src/rtos/rtkernel.c @@ -364,12 +364,12 @@ static int rtkernel_create(struct target *target) for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) { if (strcmp(rtkernel_params_list[i].target_name, target_type_name(target)) == 0) { target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i]; - return 0; + return ERROR_OK; } } LOG_ERROR("Could not find target in rt-kernel compatibility list"); - return -1; + return ERROR_FAIL; } const struct rtos_type rtkernel_rtos = { diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index e87e51cbd6..5a968ade90 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -14,29 +14,29 @@ #include "target/smp.h" #include "helper/log.h" #include "helper/binarybuffer.h" +#include "helper/types.h" #include "server/gdb_server.h" static const struct rtos_type *rtos_types[] = { - &threadx_rtos, - &freertos_rtos, - &ecos_rtos, - &linux_rtos, + // Keep in alphabetic order this list of rtos, except hwthread &chibios_rtos, &chromium_ec_rtos, + &ecos_rtos, &embkernel_rtos, + &freertos_rtos, + &linux_rtos, &mqx_rtos, - &ucos_iii_rtos, &nuttx_rtos, &riot_rtos, - &zephyr_rtos, &rtkernel_rtos, - /* keep this as last, as it always matches with rtos auto */ + &threadx_rtos, + &ucos_iii_rtos, + &zephyr_rtos, + + // keep this as last, as it always matches with rtos auto &hwthread_rtos, - NULL }; -static int rtos_try_next(struct target *target); - int rtos_smp_init(struct target *target) { if (target->rtos->type->smp_init) @@ -61,7 +61,7 @@ static int os_alloc(struct target *target, const struct rtos_type *ostype, struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); if (!os) - return JIM_ERR; + return ERROR_FAIL; os->type = ostype; os->current_threadid = -1; @@ -74,7 +74,7 @@ static int os_alloc(struct target *target, const struct rtos_type *ostype, os->gdb_target_for_threadid = rtos_target_for_threadid; os->cmd_ctx = cmd_ctx; - return JIM_OK; + return ERROR_OK; } static void os_free(struct target *target) @@ -92,40 +92,26 @@ static int os_alloc_create(struct target *target, const struct rtos_type *ostype struct command_context *cmd_ctx) { int ret = os_alloc(target, ostype, cmd_ctx); + if (ret != ERROR_OK) + return ret; - if (ret == JIM_OK) { - ret = target->rtos->type->create(target); - if (ret != JIM_OK) - os_free(target); - } + ret = target->rtos->type->create(target); + if (ret != ERROR_OK) + os_free(target); return ret; } -int rtos_create(struct jim_getopt_info *goi, struct target *target) +int rtos_create(struct command_invocation *cmd, struct target *target, + const char *rtos_name) { - int x; - const char *cp; - Jim_Obj *res; - int e; - - if (!goi->is_configure && goi->argc != 0) { - Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); - return JIM_ERR; - } - - struct command_context *cmd_ctx = current_command_context(goi->interp); - os_free(target); + target->rtos_auto_detect = false; - e = jim_getopt_string(goi, &cp, NULL); - if (e != JIM_OK) - return e; - - if (strcmp(cp, "none") == 0) - return JIM_OK; + if (strcmp(rtos_name, "none") == 0) + return ERROR_OK; - if (strcmp(cp, "auto") == 0) { + if (strcmp(rtos_name, "auto") == 0) { /* Auto detect tries to look up all symbols for each RTOS, * and runs the RTOS driver's _detect() function when GDB * finds all symbols for any RTOS. See rtos_qsymbol(). */ @@ -133,20 +119,32 @@ int rtos_create(struct jim_getopt_info *goi, struct target *target) /* rtos_qsymbol() will iterate over all RTOSes. Allocate * target->rtos here, and set it to the first RTOS type. */ - return os_alloc(target, rtos_types[0], cmd_ctx); + return os_alloc(target, rtos_types[0], CMD_CTX); } - for (x = 0; rtos_types[x]; x++) - if (strcmp(cp, rtos_types[x]->name) == 0) - return os_alloc_create(target, rtos_types[x], cmd_ctx); + for (size_t x = 0; x < ARRAY_SIZE(rtos_types); x++) + if (strcmp(rtos_name, rtos_types[x]->name) == 0) + return os_alloc_create(target, rtos_types[x], CMD_CTX); - Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp); - res = Jim_GetResult(goi->interp); - for (x = 0; rtos_types[x]; x++) - Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL); - Jim_AppendStrings(goi->interp, res, ", auto or none", NULL); + char *all = NULL; + for (size_t x = 0; x < ARRAY_SIZE(rtos_types); x++) { + char *prev = all; + if (all) + all = alloc_printf("%s, %s", all, rtos_types[x]->name); + else + all = alloc_printf("%s", rtos_types[x]->name); + free(prev); + if (!all) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + } - return JIM_ERR; + command_print(cmd, "Unknown RTOS type %s, try one of: %s, auto or none", + rtos_name, all); + free(all); + + return ERROR_COMMAND_ARGUMENT_INVALID; } void rtos_destroy(struct target *target) @@ -163,6 +161,29 @@ int gdb_thread_packet(struct connection *connection, char const *packet, int pac return target->rtos->gdb_thread_packet(connection, packet, packet_size); } +static bool rtos_try_next(struct target *target) +{ + struct rtos *os = target->rtos; + + if (!os) + return false; + + for (size_t x = 0; x < ARRAY_SIZE(rtos_types) - 1; x++) { + if (os->type == rtos_types[x]) { + // Use next RTOS in the list + os->type = rtos_types[x + 1]; + + free(os->symbols); + os->symbols = NULL; + + return true; + } + } + + // No next RTOS to try + return false; +} + static struct symbol_table_elem *find_symbol(const struct rtos *os, const char *symbol) { struct symbol_table_elem *s; @@ -791,28 +812,6 @@ int rtos_generic_stack_write_reg(struct target *target, return ERROR_OK; } -static int rtos_try_next(struct target *target) -{ - struct rtos *os = target->rtos; - const struct rtos_type **type = rtos_types; - - if (!os) - return 0; - - while (*type && os->type != *type) - type++; - - if (!*type || !*(++type)) - return 0; - - os->type = *type; - - free(os->symbols); - os->symbols = NULL; - - return 1; -} - struct rtos *rtos_of_target(struct target *target) { /* Primarily consider the rtos field of the target itself, secondarily consider diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 210f4fc99e..0375f64757 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -11,7 +11,6 @@ #include "server/server.h" #include "target/breakpoints.h" #include "target/target.h" -#include typedef int64_t threadid_t; typedef int64_t symbol_address_t; @@ -139,7 +138,8 @@ struct rtos_register_stacking { #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) -int rtos_create(struct jim_getopt_info *goi, struct target *target); +int rtos_create(struct command_invocation *cmd, struct target *target, + const char *rtos_name); void rtos_destroy(struct target *target); int rtos_set_reg(struct connection *connection, int reg_num, uint8_t *reg_value); @@ -174,6 +174,7 @@ struct target *rtos_swbp_target(struct target *target, target_addr_t address, uint32_t length, enum breakpoint_type type); struct rtos *rtos_of_target(struct target *target); +// Keep in alphabetic order this list of rtos extern const struct rtos_type chibios_rtos; extern const struct rtos_type chromium_ec_rtos; extern const struct rtos_type ecos_rtos; diff --git a/src/rtos/threadx.c b/src/rtos/threadx.c index 61c49264e8..620f43cc8e 100644 --- a/src/rtos/threadx.c +++ b/src/rtos/threadx.c @@ -611,9 +611,9 @@ static int threadx_create(struct target *target) target->rtos->rtos_specific_params = (void *)&threadx_params_list[i]; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; - return 0; + return ERROR_OK; } LOG_ERROR("Could not find target in ThreadX compatibility list"); - return -1; + return ERROR_FAIL; } diff --git a/src/rtt/rtt.c b/src/rtt/rtt.c index 15b9a373a5..3c7a966a79 100644 --- a/src/rtt/rtt.c +++ b/src/rtt/rtt.c @@ -288,7 +288,7 @@ int rtt_set_polling_interval(unsigned int interval) int rtt_write_channel(unsigned int channel_index, const uint8_t *buffer, size_t *length) { - if (channel_index >= rtt.ctrl.num_up_channels) { + if (channel_index >= rtt.ctrl.num_down_channels) { LOG_WARNING("rtt: Down-channel %u is not available", channel_index); return ERROR_OK; } diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d9825c57eb..e9e8503b65 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -50,6 +50,8 @@ * found in most modern embedded processors. */ +#define CTRL(c) ((c) - '@') + enum gdb_output_flag { /* GDB doesn't accept 'O' packets */ GDB_OUTPUT_NO, @@ -477,6 +479,10 @@ static int gdb_put_packet_inner(struct connection *connection, gdb_putback_char(connection, reply); LOG_DEBUG("Unexpected start of new packet"); break; + } else if (reply == CTRL('C')) { + /* do not discard Ctrl-C */ + gdb_putback_char(connection, reply); + break; } LOG_DEBUG("Discard unexpected char %c", reply); @@ -488,7 +494,7 @@ static int gdb_put_packet_inner(struct connection *connection, char local_buffer[1024]; local_buffer[0] = '$'; - if ((size_t)len + 4 <= sizeof(local_buffer)) { + if ((size_t)len + 5 <= sizeof(local_buffer)) { /* performance gain on smaller packets by only a single call to gdb_write() */ memcpy(local_buffer + 1, buffer, len++); len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum); @@ -525,7 +531,7 @@ static int gdb_put_packet_inner(struct connection *connection, gdb_con->output_flag = GDB_OUTPUT_NO; gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative reply, retrying"); - } else if (reply == 0x3) { + } else if (reply == CTRL('C')) { gdb_con->ctrl_c = true; gdb_log_incoming_packet(connection, ""); retval = gdb_get_char(connection, &reply); @@ -735,7 +741,7 @@ static int gdb_get_packet_inner(struct connection *connection, gdb_log_incoming_packet(connection, "-"); LOG_WARNING("negative acknowledgment, but no packet pending"); break; - case 0x3: + case CTRL('C'): gdb_log_incoming_packet(connection, ""); gdb_con->ctrl_c = true; *len = 0; @@ -1058,8 +1064,8 @@ static int gdb_new_connection(struct connection *connection) * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ - breakpoint_clear_target(target); - watchpoint_clear_target(target); + breakpoint_remove_all(target); + watchpoint_remove_all(target); /* Since version 3.95 (gdb-19990504), with the exclusion of 6.5~6.8, GDB * sends an ACK at connection with the following comment in its source code: @@ -1579,7 +1585,7 @@ static int gdb_read_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%16.16" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) @@ -1651,7 +1657,7 @@ static int gdb_write_memory_packet(struct connection *connection, buffer = malloc(len); - LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); if (unhexify(buffer, separator, len) != len) LOG_ERROR("unable to decode memory packet"); @@ -1727,7 +1733,7 @@ static int gdb_write_memory_binary_packet(struct connection *connection, } if (len) { - LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32 "", addr, len); + LOG_DEBUG("addr: 0x%" PRIx64 ", len: 0x%8.8" PRIx32, addr, len); retval = ERROR_NOT_IMPLEMENTED; if (target->rtos) @@ -2904,7 +2910,7 @@ static int gdb_query_packet(struct connection *connection, gdb_connection->output_flag = GDB_OUTPUT_NO; if (retval == ERROR_OK) { - snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum); + snprintf(gdb_reply, 10, "C%8.8" PRIx32, checksum); gdb_put_packet(connection, gdb_reply, 9); } else { retval = gdb_error(connection, retval); @@ -3039,7 +3045,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p __attribute__((unused)) int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct target *target = get_target_from_connection(connection); + struct target *target = get_available_target_from_connection(connection); const char *parse = packet; int retval; @@ -3284,8 +3290,8 @@ static void gdb_restart_inferior(struct connection *connection, const char *pack struct gdb_connection *gdb_con = connection->priv; struct target *target = get_target_from_connection(connection); - breakpoint_clear_target(target); - watchpoint_clear_target(target); + breakpoint_remove_all(target); + watchpoint_remove_all(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ diff --git a/src/server/server.c b/src/server/server.c index 0649ec942b..5f6bb584e5 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -43,10 +43,10 @@ enum shutdown_reason { SHUTDOWN_WITH_ERROR_CODE, /* set by shutdown command; quit with non-zero return code */ SHUTDOWN_WITH_SIGNAL_CODE /* set by sig_handler; exec shutdown then exit with signal as return code */ }; -static enum shutdown_reason shutdown_openocd = CONTINUE_MAIN_LOOP; +static volatile sig_atomic_t shutdown_openocd = CONTINUE_MAIN_LOOP; /* store received signal to exit application by killing ourselves */ -static int last_signal; +static volatile sig_atomic_t last_signal; /* set the polling period to 100ms */ static int polling_period = 100; @@ -604,6 +604,7 @@ static void sig_handler(int sig) /* store only first signal that hits us */ if (shutdown_openocd == CONTINUE_MAIN_LOOP) { shutdown_openocd = SHUTDOWN_WITH_SIGNAL_CODE; + assert(sig >= SIG_ATOMIC_MIN && sig <= SIG_ATOMIC_MAX); last_signal = sig; LOG_DEBUG("Terminating on Signal %d", sig); } else diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index 2c3f769801..3634a2a592 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -671,7 +671,7 @@ static void telnet_auto_complete(struct connection *connection) } else if (jimcmd_is_oocd_command(jim_cmd)) { struct command *cmd = jimcmd_privdata(jim_cmd); - if (cmd && !cmd->handler && !cmd->jim_handler) { + if (cmd && !cmd->handler) { /* Initial part of a multi-word command. Ignore it! */ ignore_cmd = true; } else if (cmd && cmd->mode == COMMAND_CONFIG) { diff --git a/src/svf/svf.c b/src/svf/svf.c index ce994686f1..7491ad6515 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -702,71 +702,71 @@ static int svf_read_command_from_file(FILE *fd) ch = svf_read_line[0]; while (!cmd_ok && (ch != 0)) { switch (ch) { - case '!': + case '!': + slash = 0; + if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + return ERROR_FAIL; + svf_line_number++; + i = -1; + break; + case '/': + if (++slash == 2) { slash = 0; - if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + if (svf_getline(&svf_read_line, &svf_read_line_size, + svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; + } + break; + case ';': + slash = 0; + cmd_ok = 1; + break; + case '\n': + svf_line_number++; + if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + return ERROR_FAIL; + i = -1; + /* fallthrough */ + case '\r': + slash = 0; + /* Don't save '\r' and '\n' if no data is parsed */ + if (!cmd_pos) break; - case '/': - if (++slash == 2) { - slash = 0; - if (svf_getline(&svf_read_line, &svf_read_line_size, - svf_fd) <= 0) - return ERROR_FAIL; - svf_line_number++; - i = -1; - } - break; - case ';': - slash = 0; - cmd_ok = 1; - break; - case '\n': - svf_line_number++; - if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) + /* fallthrough */ + default: + /* The parsing code currently expects a space + * before parentheses -- "TDI (123)". Also a + * space afterwards -- "TDI (123) TDO(456)". + * But such spaces are optional... instead of + * parser updates, cope with that by adding the + * spaces as needed. + * + * Ensure there are 3 bytes available, for: + * - current character + * - added space. + * - terminating NUL ('\0') + */ + if (cmd_pos + 3 > svf_command_buffer_size) { + svf_command_buffer = realloc(svf_command_buffer, cmd_pos + 3); + svf_command_buffer_size = cmd_pos + 3; + if (!svf_command_buffer) { + LOG_ERROR("not enough memory"); return ERROR_FAIL; - i = -1; - /* fallthrough */ - case '\r': - slash = 0; - /* Don't save '\r' and '\n' if no data is parsed */ - if (!cmd_pos) - break; - /* fallthrough */ - default: - /* The parsing code currently expects a space - * before parentheses -- "TDI (123)". Also a - * space afterwards -- "TDI (123) TDO(456)". - * But such spaces are optional... instead of - * parser updates, cope with that by adding the - * spaces as needed. - * - * Ensure there are 3 bytes available, for: - * - current character - * - added space. - * - terminating NUL ('\0') - */ - if (cmd_pos + 3 > svf_command_buffer_size) { - svf_command_buffer = realloc(svf_command_buffer, cmd_pos + 3); - svf_command_buffer_size = cmd_pos + 3; - if (!svf_command_buffer) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } } + } - /* insert a space before '(' */ - if ('(' == ch) - svf_command_buffer[cmd_pos++] = ' '; + /* insert a space before '(' */ + if ('(' == ch) + svf_command_buffer[cmd_pos++] = ' '; - svf_command_buffer[cmd_pos++] = (char)toupper(ch); + svf_command_buffer[cmd_pos++] = (char)toupper(ch); - /* insert a space after ')' */ - if (')' == ch) - svf_command_buffer[cmd_pos++] = ' '; - break; + /* insert a space after ')' */ + if (')' == ch) + svf_command_buffer[cmd_pos++] = ' '; + break; } ch = svf_read_line[++i]; } @@ -780,31 +780,33 @@ static int svf_read_command_from_file(FILE *fd) static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_argu) { - int pos = 0, num = 0, space_found = 1, in_bracket = 0; + bool space_found = true, in_bracket = false; + int pos = 0, num = 0; while (pos < len) { switch (str[pos]) { - case '!': - case '/': - LOG_ERROR("fail to parse svf command"); - return ERROR_FAIL; - case '(': - in_bracket = 1; - goto parse_char; - case ')': - in_bracket = 0; - goto parse_char; - default: -parse_char: - if (!in_bracket && isspace((int) str[pos])) { - space_found = 1; - str[pos] = '\0'; - } else if (space_found) { - argus[num++] = &str[pos]; - space_found = 0; - } - break; + case '!': + case '/': + LOG_ERROR("fail to parse svf command"); + return ERROR_FAIL; + case '(': + in_bracket = true; + break; + case ')': + in_bracket = false; + break; + default: + break; + } + + if (!in_bracket && isspace((int)str[pos])) { + space_found = true; + str[pos] = '\0'; + } else if (space_found) { + argus[num++] = &str[pos]; + space_found = false; } + pos++; } @@ -979,10 +981,295 @@ static int svf_execute_tap(void) return ERROR_OK; } +static int svf_xxr_common(char **argus, int num_of_argu, char command, struct svf_xxr_para *xxr_para_tmp) +{ + int i, i_tmp; + uint8_t **pbuffer_tmp; + struct scan_field field; + + /* XXR length [TDI (tdi)] [TDO (tdo)][MASK (mask)] [SMASK (smask)] */ + if (num_of_argu > 10 || (num_of_argu % 2)) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + i_tmp = xxr_para_tmp->len; + xxr_para_tmp->len = atoi(argus[1]); + /* If we are to enlarge the buffers, all parts of xxr_para_tmp + * need to be freed */ + if (i_tmp < xxr_para_tmp->len) { + free(xxr_para_tmp->tdi); + xxr_para_tmp->tdi = NULL; + free(xxr_para_tmp->tdo); + xxr_para_tmp->tdo = NULL; + free(xxr_para_tmp->mask); + xxr_para_tmp->mask = NULL; + free(xxr_para_tmp->smask); + xxr_para_tmp->smask = NULL; + } + + LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); + xxr_para_tmp->data_mask = 0; + for (i = 2; i < num_of_argu; i += 2) { + if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || + argus[i + 1][strlen(argus[i + 1]) - 1] != ')') { + LOG_ERROR("data section error"); + return ERROR_FAIL; + } + argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; + /* TDI, TDO, MASK, SMASK */ + if (!strcmp(argus[i], "TDI")) { + /* TDI */ + pbuffer_tmp = &xxr_para_tmp->tdi; + xxr_para_tmp->data_mask |= XXR_TDI; + } else if (!strcmp(argus[i], "TDO")) { + /* TDO */ + pbuffer_tmp = &xxr_para_tmp->tdo; + xxr_para_tmp->data_mask |= XXR_TDO; + } else if (!strcmp(argus[i], "MASK")) { + /* MASK */ + pbuffer_tmp = &xxr_para_tmp->mask; + xxr_para_tmp->data_mask |= XXR_MASK; + } else if (!strcmp(argus[i], "SMASK")) { + /* SMASK */ + pbuffer_tmp = &xxr_para_tmp->smask; + xxr_para_tmp->data_mask |= XXR_SMASK; + } else { + LOG_ERROR("unknown parameter: %s", argus[i]); + return ERROR_FAIL; + } + if (svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, + xxr_para_tmp->len) != ERROR_OK) { + LOG_ERROR("fail to parse hex value"); + return ERROR_FAIL; + } + SVF_BUF_LOG(DEBUG, *pbuffer_tmp, xxr_para_tmp->len, argus[i]); + } + /* If a command changes the length of the last scan of the same type and the + * MASK parameter is absent, */ + /* the mask pattern used is all cares */ + if (!(xxr_para_tmp->data_mask & XXR_MASK) && i_tmp != xxr_para_tmp->len) { + /* MASK not defined and length changed */ + if (svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); + } + /* If TDO is absent, no comparison is needed, set the mask to 0 */ + if (!(xxr_para_tmp->data_mask & XXR_TDO)) { + if (!xxr_para_tmp->tdo) { + if (svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + } + if (!xxr_para_tmp->mask) { + if (svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len) + != ERROR_OK) { + LOG_ERROR("fail to adjust length of array"); + return ERROR_FAIL; + } + } + memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); + } + /* do scan if necessary */ + if (command == SDR) { + /* check buffer size first, reallocate if necessary */ + i = svf_para.hdr_para.len + svf_para.sdr_para.len + + svf_para.tdr_para.len; + if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { + /* reallocate buffer */ + if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + } + + /* assemble dr data */ + i = 0; + buf_set_buf(svf_para.hdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + i += svf_para.tdr_para.len; + + /* add check data */ + if (svf_para.sdr_para.data_mask & XXR_TDO) { + /* assemble dr mask data */ + i = 0; + buf_set_buf(svf_para.hdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + + /* assemble dr check data */ + i = 0; + buf_set_buf(svf_para.hdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.hdr_para.len); + i += svf_para.hdr_para.len; + buf_set_buf(svf_para.sdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.sdr_para.len); + i += svf_para.sdr_para.len; + buf_set_buf(svf_para.tdr_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.tdr_para.len); + i += svf_para.tdr_para.len; + + svf_add_check_para(1, svf_buffer_index, i); + } else { + svf_add_check_para(0, svf_buffer_index, i); + } + field.num_bits = i; + field.out_value = &svf_tdi_buffer[svf_buffer_index]; + field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; + if (!svf_nil) { + /* NOTE: doesn't use SVF-specified state paths */ + jtag_add_plain_dr_scan(field.num_bits, + field.out_value, + field.in_value, + svf_para.dr_end_state); + } + + if (svf_addcycles) + jtag_add_clocks(svf_addcycles); + + svf_buffer_index += (i + 7) >> 3; + } else if (command == SIR) { + /* check buffer size first, reallocate if necessary */ + i = svf_para.hir_para.len + svf_para.sir_para.len + + svf_para.tir_para.len; + if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { + if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { + LOG_ERROR("not enough memory"); + return ERROR_FAIL; + } + } + + /* assemble ir data */ + i = 0; + buf_set_buf(svf_para.hir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.tdi, + 0, + &svf_tdi_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + i += svf_para.tir_para.len; + + /* add check data */ + if (svf_para.sir_para.data_mask & XXR_TDO) { + /* assemble dr mask data */ + i = 0; + buf_set_buf(svf_para.hir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.mask, + 0, + &svf_mask_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + + /* assemble dr check data */ + i = 0; + buf_set_buf(svf_para.hir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.hir_para.len); + i += svf_para.hir_para.len; + buf_set_buf(svf_para.sir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.sir_para.len); + i += svf_para.sir_para.len; + buf_set_buf(svf_para.tir_para.tdo, + 0, + &svf_tdo_buffer[svf_buffer_index], + i, + svf_para.tir_para.len); + i += svf_para.tir_para.len; + + svf_add_check_para(1, svf_buffer_index, i); + } else { + svf_add_check_para(0, svf_buffer_index, i); + } + field.num_bits = i; + field.out_value = &svf_tdi_buffer[svf_buffer_index]; + field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; + if (!svf_nil) { + /* NOTE: doesn't use SVF-specified state paths */ + jtag_add_plain_ir_scan(field.num_bits, + field.out_value, + field.in_value, + svf_para.ir_end_state); + } + + svf_buffer_index += (i + 7) >> 3; + } + + return ERROR_OK; +} + static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) { char *argus[256], command; - int num_of_argu = 0, i; + int num_of_argu = 0, i, retval; /* tmp variable */ int i_tmp; @@ -990,10 +1277,6 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) /* for RUNTEST */ int run_count; float min_time; - /* for XXR */ - struct svf_xxr_para *xxr_para_tmp; - uint8_t **pbuffer_tmp; - struct scan_field field; /* for STATE */ enum tap_state *path = NULL, state; /* flag padding commands skipped due to -tap command */ @@ -1009,594 +1292,327 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) command = svf_find_string_in_array(argus[0], (char **)svf_command_name, ARRAY_SIZE(svf_command_name)); switch (command) { - case ENDDR: - case ENDIR: - if (num_of_argu != 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); - return ERROR_FAIL; - } + case ENDDR: + case ENDIR: + if (num_of_argu != 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } - i_tmp = tap_state_by_name(argus[1]); + i_tmp = tap_state_by_name(argus[1]); - if (svf_tap_state_is_stable(i_tmp)) { - if (command == ENDIR) { - svf_para.ir_end_state = i_tmp; - LOG_DEBUG("\tIR end_state = %s", - tap_state_name(i_tmp)); - } else { - svf_para.dr_end_state = i_tmp; - LOG_DEBUG("\tDR end_state = %s", - tap_state_name(i_tmp)); - } + if (svf_tap_state_is_stable(i_tmp)) { + if (command == ENDIR) { + svf_para.ir_end_state = i_tmp; + LOG_DEBUG("\tIR end_state = %s", + tap_state_name(i_tmp)); } else { - LOG_ERROR("%s: %s is not a stable state", - argus[0], argus[1]); - return ERROR_FAIL; + svf_para.dr_end_state = i_tmp; + LOG_DEBUG("\tDR end_state = %s", + tap_state_name(i_tmp)); } - break; - case FREQUENCY: - if ((num_of_argu != 1) && (num_of_argu != 3)) { - LOG_ERROR("invalid parameter of %s", argus[0]); + } else { + LOG_ERROR("%s: %s is not a stable state", + argus[0], argus[1]); + return ERROR_FAIL; + } + break; + case FREQUENCY: + if (num_of_argu != 1 && num_of_argu != 3) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (num_of_argu == 1) { + /* TODO: set jtag speed to full speed */ + svf_para.frequency = 0; + } else { + if (strcmp(argus[2], "HZ")) { + LOG_ERROR("HZ not found in FREQUENCY command"); return ERROR_FAIL; } - if (num_of_argu == 1) { - /* TODO: set jtag speed to full speed */ - svf_para.frequency = 0; - } else { - if (strcmp(argus[2], "HZ")) { - LOG_ERROR("HZ not found in FREQUENCY command"); - return ERROR_FAIL; - } - if (svf_execute_tap() != ERROR_OK) - return ERROR_FAIL; - svf_para.frequency = atof(argus[1]); - /* TODO: set jtag speed to */ - if (svf_para.frequency > 0) { - command_run_linef(cmd_ctx, - "adapter speed %d", - (int)svf_para.frequency / 1000); - LOG_DEBUG("\tfrequency = %f", svf_para.frequency); - } - } - break; - case HDR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.hdr_para; - goto xxr_common; - case HIR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.hir_para; - goto xxr_common; - case TDR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.tdr_para; - goto xxr_common; - case TIR: - if (svf_tap_is_specified) { - padding_command_skipped = 1; - break; - } - xxr_para_tmp = &svf_para.tir_para; - goto xxr_common; - case SDR: - xxr_para_tmp = &svf_para.sdr_para; - goto xxr_common; - case SIR: - xxr_para_tmp = &svf_para.sir_para; - goto xxr_common; -xxr_common: - /* XXR length [TDI (tdi)] [TDO (tdo)][MASK (mask)] [SMASK (smask)] */ - if ((num_of_argu > 10) || (num_of_argu % 2)) { - LOG_ERROR("invalid parameter of %s", argus[0]); + if (svf_execute_tap() != ERROR_OK) return ERROR_FAIL; + svf_para.frequency = atof(argus[1]); + /* TODO: set jtag speed to */ + if (svf_para.frequency > 0) { + command_run_linef(cmd_ctx, + "adapter speed %d", + (int)svf_para.frequency / 1000); + LOG_DEBUG("\tfrequency = %f", svf_para.frequency); } - i_tmp = xxr_para_tmp->len; - xxr_para_tmp->len = atoi(argus[1]); - /* If we are to enlarge the buffers, all parts of xxr_para_tmp - * need to be freed */ - if (i_tmp < xxr_para_tmp->len) { - free(xxr_para_tmp->tdi); - xxr_para_tmp->tdi = NULL; - free(xxr_para_tmp->tdo); - xxr_para_tmp->tdo = NULL; - free(xxr_para_tmp->mask); - xxr_para_tmp->mask = NULL; - free(xxr_para_tmp->smask); - xxr_para_tmp->smask = NULL; - } - - LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); - xxr_para_tmp->data_mask = 0; - for (i = 2; i < num_of_argu; i += 2) { - if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || - (argus[i + 1][strlen(argus[i + 1]) - 1] != ')')) { - LOG_ERROR("data section error"); - return ERROR_FAIL; - } - argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; - /* TDI, TDO, MASK, SMASK */ - if (!strcmp(argus[i], "TDI")) { - /* TDI */ - pbuffer_tmp = &xxr_para_tmp->tdi; - xxr_para_tmp->data_mask |= XXR_TDI; - } else if (!strcmp(argus[i], "TDO")) { - /* TDO */ - pbuffer_tmp = &xxr_para_tmp->tdo; - xxr_para_tmp->data_mask |= XXR_TDO; - } else if (!strcmp(argus[i], "MASK")) { - /* MASK */ - pbuffer_tmp = &xxr_para_tmp->mask; - xxr_para_tmp->data_mask |= XXR_MASK; - } else if (!strcmp(argus[i], "SMASK")) { - /* SMASK */ - pbuffer_tmp = &xxr_para_tmp->smask; - xxr_para_tmp->data_mask |= XXR_SMASK; - } else { - LOG_ERROR("unknown parameter: %s", argus[i]); - return ERROR_FAIL; - } - if (ERROR_OK != - svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to parse hex value"); - return ERROR_FAIL; - } - SVF_BUF_LOG(DEBUG, *pbuffer_tmp, xxr_para_tmp->len, argus[i]); - } - /* If a command changes the length of the last scan of the same type and the - * MASK parameter is absent, */ - /* the mask pattern used is all cares */ - if (!(xxr_para_tmp->data_mask & XXR_MASK) && (i_tmp != xxr_para_tmp->len)) { - /* MASK not defined and length changed */ - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); - } - /* If TDO is absent, no comparison is needed, set the mask to 0 */ - if (!(xxr_para_tmp->data_mask & XXR_TDO)) { - if (!xxr_para_tmp->tdo) { - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - } - if (!xxr_para_tmp->mask) { - if (ERROR_OK != - svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, - xxr_para_tmp->len)) { - LOG_ERROR("fail to adjust length of array"); - return ERROR_FAIL; - } - } - memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); - } - /* do scan if necessary */ - if (command == SDR) { - /* check buffer size first, reallocate if necessary */ - i = svf_para.hdr_para.len + svf_para.sdr_para.len + - svf_para.tdr_para.len; - if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { - /* reallocate buffer */ - if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } - } - - /* assemble dr data */ - i = 0; - buf_set_buf(svf_para.hdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - i += svf_para.tdr_para.len; - - /* add check data */ - if (svf_para.sdr_para.data_mask & XXR_TDO) { - /* assemble dr mask data */ - i = 0; - buf_set_buf(svf_para.hdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - - /* assemble dr check data */ - i = 0; - buf_set_buf(svf_para.hdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.hdr_para.len); - i += svf_para.hdr_para.len; - buf_set_buf(svf_para.sdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.sdr_para.len); - i += svf_para.sdr_para.len; - buf_set_buf(svf_para.tdr_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.tdr_para.len); - i += svf_para.tdr_para.len; - - svf_add_check_para(1, svf_buffer_index, i); - } else - svf_add_check_para(0, svf_buffer_index, i); - field.num_bits = i; - field.out_value = &svf_tdi_buffer[svf_buffer_index]; - field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; - if (!svf_nil) { - /* NOTE: doesn't use SVF-specified state paths */ - jtag_add_plain_dr_scan(field.num_bits, - field.out_value, - field.in_value, - svf_para.dr_end_state); - } - - if (svf_addcycles) - jtag_add_clocks(svf_addcycles); - - svf_buffer_index += (i + 7) >> 3; - } else if (command == SIR) { - /* check buffer size first, reallocate if necessary */ - i = svf_para.hir_para.len + svf_para.sir_para.len + - svf_para.tir_para.len; - if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { - if (svf_realloc_buffers(svf_buffer_index + ((i + 7) >> 3)) != ERROR_OK) { - LOG_ERROR("not enough memory"); - return ERROR_FAIL; - } - } - - /* assemble ir data */ - i = 0; - buf_set_buf(svf_para.hir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.tdi, - 0, - &svf_tdi_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - i += svf_para.tir_para.len; - - /* add check data */ - if (svf_para.sir_para.data_mask & XXR_TDO) { - /* assemble dr mask data */ - i = 0; - buf_set_buf(svf_para.hir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.mask, - 0, - &svf_mask_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - - /* assemble dr check data */ - i = 0; - buf_set_buf(svf_para.hir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.hir_para.len); - i += svf_para.hir_para.len; - buf_set_buf(svf_para.sir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.sir_para.len); - i += svf_para.sir_para.len; - buf_set_buf(svf_para.tir_para.tdo, - 0, - &svf_tdo_buffer[svf_buffer_index], - i, - svf_para.tir_para.len); - i += svf_para.tir_para.len; - - svf_add_check_para(1, svf_buffer_index, i); - } else - svf_add_check_para(0, svf_buffer_index, i); - field.num_bits = i; - field.out_value = &svf_tdi_buffer[svf_buffer_index]; - field.in_value = (xxr_para_tmp->data_mask & XXR_TDO) ? &svf_tdi_buffer[svf_buffer_index] : NULL; - if (!svf_nil) { - /* NOTE: doesn't use SVF-specified state paths */ - jtag_add_plain_ir_scan(field.num_bits, - field.out_value, - field.in_value, - svf_para.ir_end_state); - } - - svf_buffer_index += (i + 7) >> 3; - } + } + break; + case HDR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; break; - case PIO: - case PIOMAP: - LOG_ERROR("PIO and PIOMAP are not supported"); + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.hdr_para); + if (retval != ERROR_OK) + return retval; + break; + case HIR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.hir_para); + if (retval != ERROR_OK) + return retval; + break; + case TDR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.tdr_para); + if (retval != ERROR_OK) + return retval; + break; + case TIR: + if (svf_tap_is_specified) { + padding_command_skipped = 1; + break; + } + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.tir_para); + if (retval != ERROR_OK) + return retval; + break; + case SDR: + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.sdr_para); + if (retval != ERROR_OK) + return retval; + break; + case SIR: + retval = svf_xxr_common(argus, num_of_argu, command, &svf_para.sir_para); + if (retval != ERROR_OK) + return retval; + break; + case PIO: + case PIOMAP: + LOG_ERROR("PIO and PIOMAP are not supported"); + return ERROR_FAIL; + case RUNTEST: + /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time + * SEC]] [ENDSTATE end_state] */ + /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE + * end_state] */ + if (num_of_argu < 3 || num_of_argu > 11) { + LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; - case RUNTEST: - /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time - * SEC]] [ENDSTATE end_state] */ - /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE - * end_state] */ - if ((num_of_argu < 3) || (num_of_argu > 11)) { - LOG_ERROR("invalid parameter of %s", argus[0]); + } + /* init */ + run_count = 0; + min_time = 0; + i = 1; + + /* run_state */ + i_tmp = tap_state_by_name(argus[i]); + if (i_tmp != TAP_INVALID) { + if (svf_tap_state_is_stable(i_tmp)) { + svf_para.runtest_run_state = i_tmp; + + /* When a run_state is specified, the new + * run_state becomes the default end_state. + */ + svf_para.runtest_end_state = i_tmp; + LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); + i++; + } else { + LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } - /* init */ - run_count = 0; - min_time = 0; - i = 1; - - /* run_state */ - i_tmp = tap_state_by_name(argus[i]); - if (i_tmp != TAP_INVALID) { - if (svf_tap_state_is_stable(i_tmp)) { - svf_para.runtest_run_state = i_tmp; - - /* When a run_state is specified, the new - * run_state becomes the default end_state. - */ - svf_para.runtest_end_state = i_tmp; - LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); - i++; - } else { - LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); - return ERROR_FAIL; - } - } + } - /* run_count run_clk */ - if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { - if (!strcmp(argus[i + 1], "TCK")) { - /* clock source is TCK */ - run_count = atoi(argus[i]); - LOG_DEBUG("\trun_count@TCK = %d", run_count); - } else { - LOG_ERROR("%s not supported for clock", argus[i + 1]); - return ERROR_FAIL; - } - i += 2; - } - /* min_time SEC */ - if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { - min_time = atof(argus[i]); - LOG_DEBUG("\tmin_time = %fs", min_time); - i += 2; - } - /* MAXIMUM max_time SEC */ - if (((i + 3) <= num_of_argu) && - !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { - float max_time = 0; - max_time = atof(argus[i + 1]); - LOG_DEBUG("\tmax_time = %fs", max_time); - i += 3; + /* run_count run_clk */ + if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { + if (!strcmp(argus[i + 1], "TCK")) { + /* clock source is TCK */ + run_count = atoi(argus[i]); + LOG_DEBUG("\trun_count@TCK = %d", run_count); + } else { + LOG_ERROR("%s not supported for clock", argus[i + 1]); + return ERROR_FAIL; } - /* ENDSTATE end_state */ - if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { - i_tmp = tap_state_by_name(argus[i + 1]); + i += 2; + } + /* min_time SEC */ + if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { + min_time = atof(argus[i]); + LOG_DEBUG("\tmin_time = %fs", min_time); + i += 2; + } + /* MAXIMUM max_time SEC */ + if (((i + 3) <= num_of_argu) && + !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { + float max_time = 0; + max_time = atof(argus[i + 1]); + LOG_DEBUG("\tmax_time = %fs", max_time); + i += 3; + } + /* ENDSTATE end_state */ + if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { + i_tmp = tap_state_by_name(argus[i + 1]); - if (svf_tap_state_is_stable(i_tmp)) { - svf_para.runtest_end_state = i_tmp; - LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); - } else { - LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); - return ERROR_FAIL; - } - i += 2; + if (svf_tap_state_is_stable(i_tmp)) { + svf_para.runtest_end_state = i_tmp; + LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); + } else { + LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); + return ERROR_FAIL; } + i += 2; + } - /* all parameter should be parsed */ - if (i == num_of_argu) { + /* all parameter should be parsed */ + if (i == num_of_argu) { #if 1 - /* FIXME handle statemove failures */ - uint32_t min_usec = 1000000 * min_time; + /* FIXME handle statemove failures */ + uint32_t min_usec = 1000000 * min_time; - /* enter into run_state if necessary */ - if (cmd_queue_cur_state != svf_para.runtest_run_state) - svf_add_statemove(svf_para.runtest_run_state); + /* enter into run_state if necessary */ + if (cmd_queue_cur_state != svf_para.runtest_run_state) + svf_add_statemove(svf_para.runtest_run_state); - /* add clocks and/or min wait */ - if (run_count > 0) { - if (!svf_nil) - jtag_add_clocks(run_count); - } + /* add clocks and/or min wait */ + if (run_count > 0) { + if (!svf_nil) + jtag_add_clocks(run_count); + } - if (min_usec > 0) { - if (!svf_nil) - jtag_add_sleep(min_usec); - } + if (min_usec > 0) { + if (!svf_nil) + jtag_add_sleep(min_usec); + } - /* move to end_state if necessary */ - if (svf_para.runtest_end_state != svf_para.runtest_run_state) - svf_add_statemove(svf_para.runtest_end_state); + /* move to end_state if necessary */ + if (svf_para.runtest_end_state != svf_para.runtest_run_state) + svf_add_statemove(svf_para.runtest_end_state); #else - if (svf_para.runtest_run_state != TAP_IDLE) { - LOG_ERROR("cannot runtest in %s state", - tap_state_name(svf_para.runtest_run_state)); - return ERROR_FAIL; - } - - if (!svf_nil) - jtag_add_runtest(run_count, svf_para.runtest_end_state); -#endif - } else { - LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", - i, - num_of_argu); + if (svf_para.runtest_run_state != TAP_IDLE) { + LOG_ERROR("cannot runtest in %s state", + tap_state_name(svf_para.runtest_run_state)); return ERROR_FAIL; } - break; - case STATE: - /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ - if (num_of_argu < 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); + + if (!svf_nil) + jtag_add_runtest(run_count, svf_para.runtest_end_state); +#endif + } else { + LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", + i, + num_of_argu); + return ERROR_FAIL; + } + break; + case STATE: + /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ + if (num_of_argu < 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (num_of_argu > 2) { + /* STATE pathstate1 ... stable_state */ + path = malloc((num_of_argu - 1) * sizeof(enum tap_state)); + if (!path) { + LOG_ERROR("not enough memory"); return ERROR_FAIL; } - if (num_of_argu > 2) { - /* STATE pathstate1 ... stable_state */ - path = malloc((num_of_argu - 1) * sizeof(enum tap_state)); - if (!path) { - LOG_ERROR("not enough memory"); + num_of_argu--; /* num of path */ + i_tmp = 1; /* path is from parameter 1 */ + for (i = 0; i < num_of_argu; i++, i_tmp++) { + path[i] = tap_state_by_name(argus[i_tmp]); + if (path[i] == TAP_INVALID) { + LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); + free(path); return ERROR_FAIL; } - num_of_argu--; /* num of path */ - i_tmp = 1; /* path is from parameter 1 */ - for (i = 0; i < num_of_argu; i++, i_tmp++) { - path[i] = tap_state_by_name(argus[i_tmp]); - if (path[i] == TAP_INVALID) { - LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); - free(path); - return ERROR_FAIL; - } - /* OpenOCD refuses paths containing TAP_RESET */ - if (path[i] == TAP_RESET) { - /* FIXME last state MUST be stable! */ - if (i > 0) { - if (!svf_nil) - jtag_add_pathmove(i, path); - } + /* OpenOCD refuses paths containing TAP_RESET */ + if (path[i] == TAP_RESET) { + /* FIXME last state MUST be stable! */ + if (i > 0) { if (!svf_nil) - jtag_add_tlr(); - num_of_argu -= i + 1; - i = -1; - } - } - if (num_of_argu > 0) { - /* execute last path if necessary */ - if (svf_tap_state_is_stable(path[num_of_argu - 1])) { - /* last state MUST be stable state */ - if (!svf_nil) - jtag_add_pathmove(num_of_argu, path); - LOG_DEBUG("\tmove to %s by path_move", - tap_state_name(path[num_of_argu - 1])); - } else { - LOG_ERROR("%s: %s is not a stable state", - argus[0], - tap_state_name(path[num_of_argu - 1])); - free(path); - return ERROR_FAIL; + jtag_add_pathmove(i, path); } + if (!svf_nil) + jtag_add_tlr(); + num_of_argu -= i + 1; + i = -1; } - - free(path); - path = NULL; - } else { - /* STATE stable_state */ - state = tap_state_by_name(argus[1]); - if (svf_tap_state_is_stable(state)) { - LOG_DEBUG("\tmove to %s by svf_add_statemove", - tap_state_name(state)); - /* FIXME handle statemove failures */ - svf_add_statemove(state); + } + if (num_of_argu > 0) { + /* execute last path if necessary */ + if (svf_tap_state_is_stable(path[num_of_argu - 1])) { + /* last state MUST be stable state */ + if (!svf_nil) + jtag_add_pathmove(num_of_argu, path); + LOG_DEBUG("\tmove to %s by path_move", + tap_state_name(path[num_of_argu - 1])); } else { LOG_ERROR("%s: %s is not a stable state", - argus[0], tap_state_name(state)); + argus[0], + tap_state_name(path[num_of_argu - 1])); + free(path); return ERROR_FAIL; } } - break; - case TRST: - /* TRST trst_mode */ - if (num_of_argu != 2) { - LOG_ERROR("invalid parameter of %s", argus[0]); + + free(path); + path = NULL; + } else { + /* STATE stable_state */ + state = tap_state_by_name(argus[1]); + if (svf_tap_state_is_stable(state)) { + LOG_DEBUG("\tmove to %s by svf_add_statemove", + tap_state_name(state)); + /* FIXME handle statemove failures */ + svf_add_statemove(state); + } else { + LOG_ERROR("%s: %s is not a stable state", + argus[0], tap_state_name(state)); return ERROR_FAIL; } - if (svf_para.trst_mode != TRST_ABSENT) { - if (svf_execute_tap() != ERROR_OK) - return ERROR_FAIL; - i_tmp = svf_find_string_in_array(argus[1], - (char **)svf_trst_mode_name, - ARRAY_SIZE(svf_trst_mode_name)); - switch (i_tmp) { - case TRST_ON: - if (!svf_nil) - jtag_add_reset(1, 0); - break; - case TRST_Z: - case TRST_OFF: - if (!svf_nil) - jtag_add_reset(0, 0); - break; - case TRST_ABSENT: - break; - default: - LOG_ERROR("unknown TRST mode: %s", argus[1]); - return ERROR_FAIL; - } - svf_para.trst_mode = i_tmp; - LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); - } else { - LOG_ERROR("can not accept TRST command if trst_mode is ABSENT"); + } + break; + case TRST: + /* TRST trst_mode */ + if (num_of_argu != 2) { + LOG_ERROR("invalid parameter of %s", argus[0]); + return ERROR_FAIL; + } + if (svf_para.trst_mode != TRST_ABSENT) { + if (svf_execute_tap() != ERROR_OK) + return ERROR_FAIL; + i_tmp = svf_find_string_in_array(argus[1], + (char **)svf_trst_mode_name, + ARRAY_SIZE(svf_trst_mode_name)); + switch (i_tmp) { + case TRST_ON: + if (!svf_nil) + jtag_add_reset(1, 0); + break; + case TRST_Z: + case TRST_OFF: + if (!svf_nil) + jtag_add_reset(0, 0); + break; + case TRST_ABSENT: + break; + default: + LOG_ERROR("unknown TRST mode: %s", argus[1]); return ERROR_FAIL; } - break; - default: - LOG_ERROR("invalid svf command: %s", argus[0]); + svf_para.trst_mode = i_tmp; + LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); + } else { + LOG_ERROR("can not accept TRST command if trst_mode is ABSENT"); return ERROR_FAIL; + } + break; + default: + LOG_ERROR("invalid svf command: %s", argus[0]); + return ERROR_FAIL; } if (!svf_quiet) { @@ -1604,7 +1620,7 @@ static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) LOG_USER("(Above Padding command skipped, as per -tap argument)"); } - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* for convenient debugging, execute tap if possible */ if ((svf_buffer_index > 0) && (((command != STATE) && (command != RUNTEST)) || diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 1a76864180..0b5a85704c 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -75,6 +75,7 @@ ARMV6_SRC = \ ARMV7_SRC = \ %D%/armv7m.c \ + %D%/armv7m_cache.c \ %D%/armv7m_trace.c \ %D%/cortex_m.c \ %D%/armv7a.c \ @@ -183,6 +184,7 @@ ARC_SRC = \ %D%/armv4_5_cache.h \ %D%/armv7a.h \ %D%/armv7m.h \ + %D%/armv7m_cache.h \ %D%/armv7m_trace.h \ %D%/armv8.h \ %D%/armv8_dpm.h \ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 101cb14408..ed9cb48aa7 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -50,7 +50,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); -static int aarch64_mmu(struct target *target, int *enabled); +static int aarch64_mmu(struct target *target, bool *enabled); static int aarch64_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int aarch64_read_cpu_memory(struct target *target, @@ -613,22 +613,22 @@ static int aarch64_restore_one(struct target *target, bool current, * kill the return address */ switch (arm->core_state) { - case ARM_STATE_ARM: - resume_pc &= 0xFFFFFFFC; - break; - case ARM_STATE_AARCH64: - resume_pc &= 0xFFFFFFFFFFFFFFFCULL; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - resume_pc |= 0x1; - break; - case ARM_STATE_JAZELLE: - LOG_ERROR("How do I resume into Jazelle state??"); - return ERROR_FAIL; + case ARM_STATE_ARM: + resume_pc &= 0xFFFFFFFC; + break; + case ARM_STATE_AARCH64: + resume_pc &= 0xFFFFFFFFFFFFFFFCULL; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + resume_pc |= 0x1; + break; + case ARM_STATE_JAZELLE: + LOG_ERROR("How do I resume into Jazelle state??"); + return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%016" PRIx64, resume_pc); buf_set_u64(arm->pc->value, 0, 64, resume_pc); @@ -1095,20 +1095,19 @@ static int aarch64_post_debug_entry(struct target *target) LOG_DEBUG("System_register: %8.8" PRIx64, aarch64->system_control_reg); aarch64->system_control_reg_curr = aarch64->system_control_reg; - if (armv8->armv8_mmu.armv8_cache.info == -1) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } if (armv8->is_armv8r) { - armv8->armv8_mmu.mmu_enabled = 0; + armv8->armv8_mmu.mmu_enabled = false; } else { - armv8->armv8_mmu.mmu_enabled = - (aarch64->system_control_reg & 0x1U) ? 1 : 0; + armv8->armv8_mmu.mmu_enabled = aarch64->system_control_reg & 0x1U; } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = - (aarch64->system_control_reg & 0x4U) ? 1 : 0; + aarch64->system_control_reg & 0x4U; armv8->armv8_mmu.armv8_cache.i_cache_enabled = - (aarch64->system_control_reg & 0x1000U) ? 1 : 0; + aarch64->system_control_reg & 0x1000U; return ERROR_OK; } @@ -2529,7 +2528,7 @@ static int aarch64_read_phys_memory(struct target *target, static int aarch64_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - int mmu_enabled = 0; + bool mmu_enabled = false; int retval; /* determine if MMU was enabled on target stop */ @@ -2566,7 +2565,7 @@ static int aarch64_write_phys_memory(struct target *target, static int aarch64_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - int mmu_enabled = 0; + bool mmu_enabled = false; int retval; /* determine if MMU was enabled on target stop */ @@ -2877,7 +2876,7 @@ static void aarch64_deinit_target(struct target *target) free(aarch64); } -static int aarch64_mmu(struct target *target, int *enabled) +static int aarch64_mmu(struct target *target, bool *enabled) { struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; @@ -2886,7 +2885,7 @@ static int aarch64_mmu(struct target *target, int *enabled) return ERROR_TARGET_NOT_HALTED; } if (armv8->is_armv8r) - *enabled = 0; + *enabled = false; else *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; @@ -3027,14 +3026,14 @@ COMMAND_HANDLER(aarch64_handle_disassemble_command) target_addr_t address; switch (CMD_ARGC) { - case 2: - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); - /* FALL THROUGH */ - case 1: - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); + /* FALL THROUGH */ + case 1: + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return a64_disassemble(CMD, target, address, count); diff --git a/src/target/arc.c b/src/target/arc.c index f2482c25ef..629f79aa03 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -769,7 +769,7 @@ static int arc_exit_debug(struct target *target) target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_TARGET_DEBUG(target, "core stopped (halted) debug-reg: 0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); LOG_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); @@ -824,7 +824,7 @@ static int arc_halt(struct target *target) CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); /* some more debug information */ - if (debug_level >= LOG_LVL_DEBUG) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_TARGET_DEBUG(target, "core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); LOG_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); @@ -1148,7 +1148,7 @@ static int arc_arch_state(struct target *target) { uint32_t pc_value; - if (debug_level < LOG_LVL_DEBUG) + if (!LOG_LEVEL_IS(LOG_LVL_DEBUG)) return ERROR_OK; CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); @@ -1892,18 +1892,18 @@ static int arc_set_watchpoint(struct target *target, int enable = AP_AC_TT_DISABLE; switch (watchpoint->rw) { - case WPT_READ: - enable = AP_AC_TT_READ; - break; - case WPT_WRITE: - enable = AP_AC_TT_WRITE; - break; - case WPT_ACCESS: - enable = AP_AC_TT_READWRITE; - break; - default: - LOG_TARGET_ERROR(target, "BUG: watchpoint->rw neither read, write nor access"); - return ERROR_FAIL; + case WPT_READ: + enable = AP_AC_TT_READ; + break; + case WPT_WRITE: + enable = AP_AC_TT_WRITE; + break; + case WPT_ACCESS: + enable = AP_AC_TT_READWRITE; + break; + default: + LOG_TARGET_ERROR(target, "BUG: watchpoint->rw neither read, write nor access"); + return ERROR_FAIL; } int retval = arc_configure_actionpoint(target, wp_num, diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index bf8a8aa28b..2e42398d28 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -709,29 +709,29 @@ COMMAND_HANDLER(arc_handle_get_reg_field) int retval = arc_reg_get_field(target, reg_name, field_name, &value); switch (retval) { - case ERROR_OK: - break; - case ERROR_ARC_REGISTER_NOT_FOUND: - command_print(CMD, - "Register `%s' has not been found.", reg_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - case ERROR_ARC_REGISTER_IS_NOT_STRUCT: - command_print(CMD, - "Register `%s' must have 'struct' type.", reg_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: - command_print(CMD, - "Field `%s' has not been found in register `%s'.", - field_name, reg_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - case ERROR_ARC_FIELD_IS_NOT_BITFIELD: - command_print(CMD, - "Field `%s' is not a 'bitfield' field in a structure.", - field_name); - return ERROR_COMMAND_ARGUMENT_INVALID; - default: - /* Pass through other errors. */ - return retval; + case ERROR_OK: + break; + case ERROR_ARC_REGISTER_NOT_FOUND: + command_print(CMD, + "Register `%s' has not been found.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_IS_NOT_STRUCT: + command_print(CMD, + "Register `%s' must have 'struct' type.", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_REGISTER_FIELD_NOT_FOUND: + command_print(CMD, + "Field `%s' has not been found in register `%s'.", + field_name, reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + case ERROR_ARC_FIELD_IS_NOT_BITFIELD: + command_print(CMD, + "Field `%s' is not a 'bitfield' field in a structure.", + field_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + default: + /* Pass through other errors. */ + return retval; } command_print(CMD, "0x%" PRIx32, value); diff --git a/src/target/arm11.c b/src/target/arm11.c index 583830f948..81026c68c4 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -414,19 +414,19 @@ static uint32_t arm11_nextpc(struct arm11_common *arm11, bool current, * kill the return address */ switch (arm11->arm.core_state) { - case ARM_STATE_ARM: - address &= 0xFFFFFFFC; - break; - case ARM_STATE_THUMB: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - address |= 0x1; - break; - - /* catch-all for JAZELLE and THUMB_EE */ - default: - break; + case ARM_STATE_ARM: + address &= 0xFFFFFFFC; + break; + case ARM_STATE_THUMB: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + address |= 0x1; + break; + + /* catch-all for JAZELLE and THUMB_EE */ + default: + break; } buf_set_u32(value, 0, 32, address); @@ -469,7 +469,7 @@ static int arm11_resume(struct target *target, bool current, for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { - LOG_DEBUG("must step over %08" TARGET_PRIxADDR "", bp->address); + LOG_DEBUG("must step over %08" TARGET_PRIxADDR, bp->address); arm11_step(target, true, 0, false); break; } @@ -802,7 +802,7 @@ static int arm11_read_memory_inner(struct target *target, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", + LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32, address, size, count); @@ -819,46 +819,44 @@ static int arm11_read_memory_inner(struct target *target, return retval; switch (size) { - case 1: - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - /* ldrb r1, [r0], #1 */ - /* ldrb r1, [r0] */ - CHECK_RETVAL(arm11_run_instr_no_data1(arm11, - !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); + case 1: + arm11->arm.core_cache->reg_list[1].dirty = true; - uint32_t res; - /* MCR p14,0,R1,c0,c5,0 */ - CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); + for (size_t i = 0; i < count; i++) { + /* ldrb r1, [r0], #1 */ + /* ldrb r1, [r0] */ + CHECK_RETVAL(arm11_run_instr_no_data1(arm11, + !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); - *buffer++ = res; - } + uint32_t res; + /* MCR p14,0,R1,c0,c5,0 */ + CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); - break; + *buffer++ = res; + } - case 2: - { - arm11->arm.core_cache->reg_list[1].dirty = true; + break; - for (size_t i = 0; i < count; i++) { - /* ldrh r1, [r0], #2 */ - CHECK_RETVAL(arm11_run_instr_no_data1(arm11, - !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); + case 2: + arm11->arm.core_cache->reg_list[1].dirty = true; - uint32_t res; + for (size_t i = 0; i < count; i++) { + /* ldrh r1, [r0], #2 */ + CHECK_RETVAL(arm11_run_instr_no_data1(arm11, + !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); - /* MCR p14,0,R1,c0,c5,0 */ - CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); + uint32_t res; - uint16_t svalue = res; - memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); - } + /* MCR p14,0,R1,c0,c5,0 */ + CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); - break; + uint16_t svalue = res; + memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); } - case 4: + break; + + case 4: { uint32_t instr = !arm11_config_memrw_no_increment ? 0xecb05e01 : 0xed905e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ @@ -900,7 +898,7 @@ static int arm11_write_memory_inner(struct target *target, return ERROR_TARGET_NOT_HALTED; } - LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", + LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32, address, size, count); @@ -927,56 +925,53 @@ static int arm11_write_memory_inner(struct target *target, bool burst = arm11->memwrite_burst && (count > 1); switch (size) { - case 1: - { - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - /* load r1 from DCC with byte data */ - /* MRC p14,0,r1,c0,c5,0 */ - retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); - if (retval != ERROR_OK) - return retval; - - /* write r1 to memory */ - /* strb r1, [r0], #1 */ - /* strb r1, [r0] */ - retval = arm11_run_instr_no_data1(arm11, - !no_increment ? 0xe4c01001 : 0xe5c01000); - if (retval != ERROR_OK) - return retval; - } + case 1: + arm11->arm.core_cache->reg_list[1].dirty = true; - break; + for (size_t i = 0; i < count; i++) { + /* load r1 from DCC with byte data */ + /* MRC p14,0,r1,c0,c5,0 */ + retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); + if (retval != ERROR_OK) + return retval; + + /* write r1 to memory */ + /* strb r1, [r0], #1 */ + /* strb r1, [r0] */ + retval = arm11_run_instr_no_data1(arm11, + !no_increment ? 0xe4c01001 : 0xe5c01000); + if (retval != ERROR_OK) + return retval; } - case 2: - { - arm11->arm.core_cache->reg_list[1].dirty = true; - - for (size_t i = 0; i < count; i++) { - uint16_t value; - memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); - - /* load r1 from DCC with halfword data */ - /* MRC p14,0,r1,c0,c5,0 */ - retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); - if (retval != ERROR_OK) - return retval; - - /* write r1 to memory */ - /* strh r1, [r0], #2 */ - /* strh r1, [r0] */ - retval = arm11_run_instr_no_data1(arm11, - !no_increment ? 0xe0c010b2 : 0xe1c010b0); - if (retval != ERROR_OK) - return retval; - } + break; - break; + case 2: + arm11->arm.core_cache->reg_list[1].dirty = true; + + for (size_t i = 0; i < count; i++) { + uint16_t value; + memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); + + /* load r1 from DCC with halfword data */ + /* MRC p14,0,r1,c0,c5,0 */ + retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); + if (retval != ERROR_OK) + return retval; + + /* write r1 to memory */ + /* strh r1, [r0], #2 */ + /* strh r1, [r0] */ + retval = arm11_run_instr_no_data1(arm11, + !no_increment ? 0xe0c010b2 : 0xe1c010b0); + if (retval != ERROR_OK) + return retval; } - case 4: { + break; + + case 4: + { /* stream word data through DCC directly to memory */ /* increment: STC p14,c5,[R0],#4 */ /* no increment: STC p14,c5,[R0]*/ @@ -1164,34 +1159,34 @@ static int arm11_examine(struct target *target) /* assume the manufacturer id is ok; check the part # */ switch ((device_id >> 12) & 0xFFFF) { - case 0x7B36: - type = "ARM1136"; - break; - case 0x7B37: - type = "ARM11 MPCore"; - break; - case 0x7B56: - type = "ARM1156"; - break; - case 0x7B76: - arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; - /* NOTE: could default arm11->hardware_step to true */ - type = "ARM1176"; - break; - default: - LOG_ERROR("unexpected ARM11 ID code"); - return ERROR_FAIL; + case 0x7B36: + type = "ARM1136"; + break; + case 0x7B37: + type = "ARM11 MPCore"; + break; + case 0x7B56: + type = "ARM1156"; + break; + case 0x7B76: + arm11->arm.core_type = ARM_CORE_TYPE_SEC_EXT; + /* NOTE: could default arm11->hardware_step to true */ + type = "ARM1176"; + break; + default: + LOG_ERROR("unexpected ARM11 ID code"); + return ERROR_FAIL; } LOG_INFO("found %s", type); /* unlikely this could ever fail, but ... */ switch ((didr >> 16) & 0x0F) { - case ARM11_DEBUG_V6: - case ARM11_DEBUG_V61: /* supports security extensions */ - break; - default: - LOG_ERROR("Only ARM v6 and v6.1 debug supported."); - return ERROR_FAIL; + case ARM11_DEBUG_V6: + case ARM11_DEBUG_V61: /* supports security extensions */ + break; + default: + LOG_ERROR("Only ARM v6 and v6.1 debug supported."); + return ERROR_FAIL; } arm11->brp = ((didr >> 24) & 0x0F) + 1; @@ -1255,16 +1250,16 @@ COMMAND_HANDLER(arm11_handle_vcr) struct arm11_common *arm11 = target_to_arm11(target); switch (CMD_ARGC) { - case 0: - break; - case 1: - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + break; + case 1: + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } - LOG_INFO("VCR 0x%08" PRIx32 "", arm11->vcr); + LOG_INFO("VCR 0x%08" PRIx32, arm11->vcr); return ERROR_OK; } diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index 4c7211365b..4c2fedaeb2 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -85,30 +85,30 @@ static const char *arm11_ir_to_string(uint8_t ir) const char *s = "unknown"; switch (ir) { - case ARM11_EXTEST: - s = "EXTEST"; - break; - case ARM11_SCAN_N: - s = "SCAN_N"; - break; - case ARM11_RESTART: - s = "RESTART"; - break; - case ARM11_HALT: - s = "HALT"; - break; - case ARM11_INTEST: - s = "INTEST"; - break; - case ARM11_ITRSEL: - s = "ITRSEL"; - break; - case ARM11_IDCODE: - s = "IDCODE"; - break; - case ARM11_BYPASS: - s = "BYPASS"; - break; + case ARM11_EXTEST: + s = "EXTEST"; + break; + case ARM11_SCAN_N: + s = "SCAN_N"; + break; + case ARM11_RESTART: + s = "RESTART"; + break; + case ARM11_HALT: + s = "HALT"; + break; + case ARM11_INTEST: + s = "INTEST"; + break; + case ARM11_ITRSEL: + s = "ITRSEL"; + break; + case ARM11_IDCODE: + s = "IDCODE"; + break; + case ARM11_BYPASS: + s = "BYPASS"; + break; } return s; } @@ -1061,17 +1061,17 @@ static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, action[1].value = control; switch (index_t) { - case 0 ... 15: - action[0].address = ARM11_SC7_BVR0 + index_t; - action[1].address = ARM11_SC7_BCR0 + index_t; - break; - case 16 ... 32: - index_t -= 16; - action[0].address = ARM11_SC7_WVR0 + index_t; - action[1].address = ARM11_SC7_WCR0 + index_t; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + action[0].address = ARM11_SC7_BVR0 + index_t; + action[1].address = ARM11_SC7_BCR0 + index_t; + break; + case 16 ... 32: + index_t -= 16; + action[0].address = ARM11_SC7_WVR0 + index_t; + action[1].address = ARM11_SC7_WCR0 + index_t; + break; + default: + return ERROR_FAIL; } arm11->bpwp_n += 2; @@ -1090,15 +1090,15 @@ static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) action[0].value = 0; switch (index_t) { - case 0 ... 15: - action[0].address = ARM11_SC7_BCR0 + index_t; - break; - case 16 ... 32: - index_t -= 16; - action[0].address = ARM11_SC7_WCR0 + index_t; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + action[0].address = ARM11_SC7_BCR0 + index_t; + break; + case 16 ... 32: + index_t -= 16; + action[0].address = ARM11_SC7_WCR0 + index_t; + break; + default: + return ERROR_FAIL; } arm11->bpwp_n += 1; diff --git a/src/target/arm720t.c b/src/target/arm720t.c index d1433dde72..3f7686fb74 100644 --- a/src/target/arm720t.c +++ b/src/target/arm720t.c @@ -14,6 +14,7 @@ #include "arm720t.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -196,11 +197,12 @@ static int arm720t_post_debug_entry(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg); + LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm720t->cp15_control_reg); - arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = arm720t->cp15_control_reg & 0x1U; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = + arm720t->cp15_control_reg & 0x4U; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; /* save i/d fault status and address register */ retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); @@ -226,19 +228,15 @@ static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); - static const char *state[] = { - "disabled", "enabled" - }; - arm_arch_state(target); LOG_USER("MMU: %s, Cache: %s", - state[arm720t->armv4_5_mmu.mmu_enabled], - state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); + str_enabled_disabled(arm720t->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)); return ERROR_OK; } -static int arm720_mmu(struct target *target, int *enabled) +static int arm720_mmu(struct target *target, bool *enabled) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -325,7 +323,7 @@ static int arm720t_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); @@ -354,9 +352,9 @@ static int arm720t_soft_reset_halt(struct target *target) retval = arm720t_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; - arm720t->armv4_5_mmu.mmu_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = false; + arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) @@ -407,7 +405,7 @@ static int arm720t_init_arch_info(struct target *target, arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; arm720t->armv4_5_mmu.has_tiny_pages = 0; - arm720t->armv4_5_mmu.mmu_enabled = 0; + arm720t->armv4_5_mmu.mmu_enabled = false; return ERROR_OK; } diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 5550fb1e24..06e76ac0d2 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -637,13 +637,13 @@ int arm7_9_execute_sys_speed(struct target *target) if ((buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) && (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_SYSCOMP, 1))) break; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); } if (timeout) { - LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32 "", + LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32, buf_get_u32(dbg_stat->value, 0, dbg_stat->size)); return ERROR_TARGET_TIMEOUT; } @@ -1088,7 +1088,7 @@ int arm7_9_soft_reset_halt(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - if (debug_level >= 3) + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) alive_sleep(100); else keep_alive(); @@ -1332,7 +1332,7 @@ static int arm7_9_debug_entry(struct target *target) for (i = 0; i <= 15; i++) { struct reg *r = arm_reg_current(arm, i); - LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, context[i]); + LOG_DEBUG("r%i: 0x%8.8" PRIx32, i, context[i]); buf_set_u32(r->value, 0, 32, context[i]); /* r0 and r15 (pc) have to be restored later */ @@ -1340,7 +1340,7 @@ static int arm7_9_debug_entry(struct target *target) r->valid = true; } - LOG_DEBUG("entered debug state at PC 0x%" PRIx32 "", context[15]); + LOG_DEBUG("entered debug state at PC 0x%" PRIx32, context[15]); /* exceptions other than USR & SYS have a saved program status register */ if (arm->spsr) { @@ -1594,7 +1594,7 @@ static int arm7_9_restore_context(struct target *target) struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg->dirty) && (reg_arch_info->mode != ARM_MODE_ANY)) { - LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32, i, buf_get_u32(reg->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(reg->value, 0, 32), 1); @@ -1744,7 +1744,7 @@ int arm7_9_resume(struct target *target, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -1789,7 +1789,7 @@ int arm7_9_resume(struct target *target, LOG_DEBUG("new PC after step: 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); - LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); + LOG_DEBUG("set breakpoint at 0x%8.8" TARGET_PRIxADDR, breakpoint->address); retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; @@ -1937,7 +1937,7 @@ int arm7_9_step(struct target *target, bool current, target_addr_t address, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -2116,7 +2116,7 @@ int arm7_9_read_memory(struct target *target, int retval; int last_reg = 0; - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -2135,21 +2135,49 @@ int arm7_9_read_memory(struct target *target, reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); - int j = 0; - switch (size) { - case 4: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + case 4: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + if (last_reg <= thisrun_accesses) + last_reg = thisrun_accesses; + + arm7_9->load_word_regs(target, reg_list); + + /* fast memory reads are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) + retval = arm7_9_execute_fast_sys_speed(target); + else + retval = arm7_9_execute_sys_speed(target); + if (retval != ERROR_OK) + return retval; - if (last_reg <= thisrun_accesses) - last_reg = thisrun_accesses; + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); - arm7_9->load_word_regs(target, reg_list); + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 4; + num_accesses += thisrun_accesses; + keep_alive(); + } + break; + case 2: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + arm7_9->load_hword_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ @@ -2160,81 +2188,48 @@ int arm7_9_read_memory(struct target *target, if (retval != ERROR_OK) return retval; - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); - - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 4; - num_accesses += thisrun_accesses; - - if ((j++%1024) == 0) - keep_alive(); } - break; - case 2: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - arm7_9->load_hword_reg(target, i); - /* fast memory reads are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else - retval = arm7_9_execute_sys_speed(target); - if (retval != ERROR_OK) - return retval; - - } - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 2; - num_accesses += thisrun_accesses; + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 2; + num_accesses += thisrun_accesses; - if ((j++%1024) == 0) - keep_alive(); + keep_alive(); + } + break; + case 1: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + arm7_9->load_byte_reg(target, i); + /* fast memory reads are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) + retval = arm7_9_execute_fast_sys_speed(target); + else + retval = arm7_9_execute_sys_speed(target); + if (retval != ERROR_OK) + return retval; } - break; - case 1: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - arm7_9->load_byte_reg(target, i); - /* fast memory reads are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else - retval = arm7_9_execute_sys_speed(target); - if (retval != ERROR_OK) - return retval; - } - arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); + arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); - /* advance buffer, count number of accesses */ - buffer += thisrun_accesses * 1; - num_accesses += thisrun_accesses; + /* advance buffer, count number of accesses */ + buffer += thisrun_accesses * 1; + num_accesses += thisrun_accesses; - if ((j++%1024) == 0) - keep_alive(); - } - break; + keep_alive(); + } + break; } if (!is_arm_mode(arm->core_mode)) @@ -2313,30 +2308,74 @@ int arm7_9_write_memory(struct target *target, embeddedice_store_reg(dbg_ctrl); switch (size) { - case 4: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = target_buffer_get_u32(target, buffer); - buffer += 4; - } + case 4: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = target_buffer_get_u32(target, buffer); + buffer += 4; + } + + arm7_9->write_core_regs(target, reg_list, reg); + + arm7_9->store_word_regs(target, reg_list); + + /* fast memory writes are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) { + retval = arm7_9_execute_fast_sys_speed(target); + } else { + retval = arm7_9_execute_sys_speed(target); + + /* + * if memory writes are made when the clock is running slow + * (i.e. 32 kHz) which is necessary in some scripts to reconfigure + * processor operations after a "reset halt" or "reset init", + * need to immediately stroke the keep alive or will end up with + * gdb "keep alive not sent error message" problem. + */ + + keep_alive(); + } + + if (retval != ERROR_OK) + return retval; + + num_accesses += thisrun_accesses; + } + break; + case 2: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; + buffer += 2; + } - arm7_9->write_core_regs(target, reg_list, reg); + arm7_9->write_core_regs(target, reg_list, reg); - arm7_9->store_word_regs(target, reg_list); + for (i = 1; i <= thisrun_accesses; i++) { + arm7_9->store_hword_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ - if (arm7_9->fast_memory_access) + if (arm7_9->fast_memory_access) { retval = arm7_9_execute_fast_sys_speed(target); - else { + } else { retval = arm7_9_execute_sys_speed(target); /* @@ -2352,99 +2391,55 @@ int arm7_9_write_memory(struct target *target, if (retval != ERROR_OK) return retval; + } - num_accesses += thisrun_accesses; + num_accesses += thisrun_accesses; + } + break; + case 1: + while (num_accesses < count) { + uint32_t reg_list; + thisrun_accesses = + ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); + reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; + + for (i = 1; i <= thisrun_accesses; i++) { + if (i > last_reg) + last_reg = i; + reg[i] = *buffer++ & 0xff; } - break; - case 2: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; - buffer += 2; - } - arm7_9->write_core_regs(target, reg_list, reg); + arm7_9->write_core_regs(target, reg_list, reg); - for (i = 1; i <= thisrun_accesses; i++) { - arm7_9->store_hword_reg(target, i); + for (i = 1; i <= thisrun_accesses; i++) { + arm7_9->store_byte_reg(target, i); + /* fast memory writes are only safe when the target is running + * from a sufficiently high clock (32 kHz is usually too slow) + */ + if (arm7_9->fast_memory_access) { + retval = arm7_9_execute_fast_sys_speed(target); + } else { + retval = arm7_9_execute_sys_speed(target); - /* fast memory writes are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) + /* + * if memory writes are made when the clock is running slow + * (i.e. 32 kHz) which is necessary in some scripts to reconfigure + * processor operations after a "reset halt" or "reset init", + * need to immediately stroke the keep alive or will end up with + * gdb "keep alive not sent error message" problem. */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else { - retval = arm7_9_execute_sys_speed(target); - - /* - * if memory writes are made when the clock is running slow - * (i.e. 32 kHz) which is necessary in some scripts to reconfigure - * processor operations after a "reset halt" or "reset init", - * need to immediately stroke the keep alive or will end up with - * gdb "keep alive not sent error message" problem. - */ - - keep_alive(); - } - - if (retval != ERROR_OK) - return retval; - } - num_accesses += thisrun_accesses; - } - break; - case 1: - while (num_accesses < count) { - uint32_t reg_list; - thisrun_accesses = - ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); - reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; - - for (i = 1; i <= thisrun_accesses; i++) { - if (i > last_reg) - last_reg = i; - reg[i] = *buffer++ & 0xff; + keep_alive(); } - arm7_9->write_core_regs(target, reg_list, reg); - - for (i = 1; i <= thisrun_accesses; i++) { - arm7_9->store_byte_reg(target, i); - /* fast memory writes are only safe when the target is running - * from a sufficiently high clock (32 kHz is usually too slow) - */ - if (arm7_9->fast_memory_access) - retval = arm7_9_execute_fast_sys_speed(target); - else { - retval = arm7_9_execute_sys_speed(target); - - /* - * if memory writes are made when the clock is running slow - * (i.e. 32 kHz) which is necessary in some scripts to reconfigure - * processor operations after a "reset halt" or "reset init", - * need to immediately stroke the keep alive or will end up with - * gdb "keep alive not sent error message" problem. - */ - - keep_alive(); - } - - if (retval != ERROR_OK) - return retval; - - } + if (retval != ERROR_OK) + return retval; - num_accesses += thisrun_accesses; } - break; + + num_accesses += thisrun_accesses; + } + break; } /* Re-Set DBGACK */ @@ -2641,7 +2636,7 @@ int arm7_9_bulk_write_memory(struct target *target, uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32); if (endaddress != (address + count*4)) { LOG_ERROR( - "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32 "", + "DCC write failed, expected end address 0x%08" TARGET_PRIxADDR " got 0x%0" PRIx32, (address + count*4), endaddress); retval = ERROR_FAIL; diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c index 2f59254afd..fea6a3ff2a 100644 --- a/src/target/arm7tdmi.c +++ b/src/target/arm7tdmi.c @@ -327,15 +327,15 @@ static void arm7tdmi_read_core_regs_target_buffer(struct target *target, /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ if (mask & (1 << i)) { switch (size) { - case 4: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 95cfd7ceb2..441e423054 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -12,6 +12,7 @@ #include "arm920t.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -425,12 +426,11 @@ int arm920t_post_debug_entry(struct target *target) &arm920t->armv4_5_mmu.armv4_5_cache); } - arm920t->armv4_5_mmu.mmu_enabled = - (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; + arm920t->armv4_5_mmu.mmu_enabled = arm920t->cp15_control_reg & 0x1U; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = - (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; + arm920t->cp15_control_reg & 0x4U; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = - (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; + arm920t->cp15_control_reg & 0x1000U; /* save i/d fault status and address register * FIXME use opcode macros */ @@ -510,10 +510,6 @@ static int arm920t_verify_pointer(struct command_invocation *cmd, /** Logs summary of ARM920 state for a halted target. */ int arm920t_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct arm920t_common *arm920t = target_to_arm920(target); if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { @@ -523,14 +519,14 @@ int arm920t_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[arm920t->armv4_5_mmu.mmu_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + str_enabled_disabled(arm920t->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)); return ERROR_OK; } -static int arm920_mmu(struct target *target, int *enabled) +static int arm920_mmu(struct target *target, bool *enabled) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -750,7 +746,7 @@ int arm920t_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else @@ -778,9 +774,9 @@ int arm920t_soft_reset_halt(struct target *target) arm->pc->valid = true; arm920t_disable_mmu_caches(target, 1, 1, 1); - arm920t->armv4_5_mmu.mmu_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; + arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -819,7 +815,7 @@ static int arm920t_init_arch_info(struct target *target, arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; - arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c index 0531106562..98fe6bf68d 100644 --- a/src/target/arm926ejs.c +++ b/src/target/arm926ejs.c @@ -14,6 +14,7 @@ #include "arm926ejs.h" #include +#include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" @@ -220,88 +221,88 @@ static int arm926ejs_examine_debug_reason(struct target *target) debug_reason = buf_get_u32(dbg_stat->value, 6, 4); switch (debug_reason) { - case 0: - LOG_DEBUG("no *NEW* debug entry (?missed one?)"); - /* ... since last restart or debug reset ... */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 1: - LOG_DEBUG("breakpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 2: - LOG_DEBUG("breakpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 3: - LOG_DEBUG("soft breakpoint (BKPT instruction)"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 4: - LOG_DEBUG("vector catch breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 5: - LOG_DEBUG("external breakpoint"); - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case 6: - LOG_DEBUG("watchpoint from EICE unit 0"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 7: - LOG_DEBUG("watchpoint from EICE unit 1"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 8: - LOG_DEBUG("external watchpoint"); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case 9: - LOG_DEBUG("internal debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 10: - LOG_DEBUG("external debug request"); - target->debug_reason = DBG_REASON_DBGRQ; - break; - case 11: - LOG_DEBUG("debug re-entry from system speed access"); - /* This is normal when connecting to something that's - * already halted, or in some related code paths, but - * otherwise is surprising (and presumably wrong). - */ - switch (target->debug_reason) { - case DBG_REASON_DBGRQ: - break; - default: - LOG_ERROR("unexpected -- debug re-entry"); - /* FALLTHROUGH */ - case DBG_REASON_UNDEFINED: - target->debug_reason = DBG_REASON_DBGRQ; - break; - } - break; - case 12: - /* FIX!!!! here be dragons!!! We need to fail here so - * the target will interpreted as halted but we won't - * try to talk to it right now... a resume + halt seems - * to sync things up again. Please send an email to - * openocd development mailing list if you have hardware - * to donate to look into this problem.... - */ - LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); - target->debug_reason = DBG_REASON_DBGRQ; + case 0: + LOG_DEBUG("no *NEW* debug entry (?missed one?)"); + /* ... since last restart or debug reset ... */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 1: + LOG_DEBUG("breakpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 2: + LOG_DEBUG("breakpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 3: + LOG_DEBUG("soft breakpoint (BKPT instruction)"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 4: + LOG_DEBUG("vector catch breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 5: + LOG_DEBUG("external breakpoint"); + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case 6: + LOG_DEBUG("watchpoint from EICE unit 0"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 7: + LOG_DEBUG("watchpoint from EICE unit 1"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 8: + LOG_DEBUG("external watchpoint"); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case 9: + LOG_DEBUG("internal debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 10: + LOG_DEBUG("external debug request"); + target->debug_reason = DBG_REASON_DBGRQ; + break; + case 11: + LOG_DEBUG("debug re-entry from system speed access"); + /* This is normal when connecting to something that's + * already halted, or in some related code paths, but + * otherwise is surprising (and presumably wrong). + */ + switch (target->debug_reason) { + case DBG_REASON_DBGRQ: break; default: - LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); - /* Oh agony! should we interpret this as a halt request or - * that the target stopped on it's own accord? - */ + LOG_ERROR("unexpected -- debug re-entry"); + /* FALLTHROUGH */ + case DBG_REASON_UNDEFINED: target->debug_reason = DBG_REASON_DBGRQ; - /* if we fail here, we won't talk to the target and it will - * be reported to be in the halted state */ break; + } + break; + case 12: + /* FIX!!!! here be dragons!!! We need to fail here so + * the target will interpreted as halted but we won't + * try to talk to it right now... a resume + halt seems + * to sync things up again. Please send an email to + * openocd development mailing list if you have hardware + * to donate to look into this problem.... + */ + LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); + target->debug_reason = DBG_REASON_DBGRQ; + break; + default: + LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); + /* Oh agony! should we interpret this as a halt request or + * that the target stopped on it's own accord? + */ + target->debug_reason = DBG_REASON_DBGRQ; + /* if we fail here, we won't talk to the target and it will + * be reported to be in the halted state */ + break; } return ERROR_OK; @@ -426,7 +427,7 @@ static int arm926ejs_post_debug_entry(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; - LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm926ejs->cp15_control_reg); + LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm926ejs->cp15_control_reg); if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; @@ -440,9 +441,11 @@ static int arm926ejs_post_debug_entry(struct target *target) armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); } - arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; + arm926ejs->armv4_5_mmu.mmu_enabled = arm926ejs->cp15_control_reg & 0x1U; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = + arm926ejs->cp15_control_reg & 0x4U; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = + arm926ejs->cp15_control_reg & 0x1000U; /* save i/d fault status and address register */ retval = arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); @@ -455,7 +458,7 @@ static int arm926ejs_post_debug_entry(struct target *target) if (retval != ERROR_OK) return retval; - LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 "", + LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32, arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); uint32_t cache_dbg_ctrl; @@ -503,10 +506,6 @@ static int arm926ejs_verify_pointer(struct command_invocation *cmd, /** Logs summary of ARM926 state for a halted target. */ int arm926ejs_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) { @@ -516,9 +515,9 @@ int arm926ejs_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[arm926ejs->armv4_5_mmu.mmu_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); + str_enabled_disabled(arm926ejs->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled)); return ERROR_OK; } @@ -545,7 +544,7 @@ int arm926ejs_soft_reset_halt(struct target *target) return retval; } else break; - if (debug_level >= 1) { + if (LOG_LEVEL_IS(LOG_LVL_WARNING)) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else @@ -575,9 +574,9 @@ int arm926ejs_soft_reset_halt(struct target *target) retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; - arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; + arm926ejs->armv4_5_mmu.mmu_enabled = false; + arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = false; + arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = false; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -689,7 +688,7 @@ int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; arm926ejs->armv4_5_mmu.has_tiny_pages = 1; - arm926ejs->armv4_5_mmu.mmu_enabled = 0; + arm926ejs->armv4_5_mmu.mmu_enabled = false; arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; @@ -749,7 +748,7 @@ static int arm926ejs_virt2phys(struct target *target, target_addr_t virtual, tar return ERROR_OK; } -static int arm926ejs_mmu(struct target *target, int *enabled) +static int arm926ejs_mmu(struct target *target, bool *enabled) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 8ab12de320..34b4ba2cea 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -398,15 +398,15 @@ static void arm9tdmi_read_core_regs_target_buffer(struct target *target, if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index df897b80ed..67a3fcc577 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -50,8 +50,16 @@ /* * Relevant specifications from ARM include: * - * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031F + * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031G + * https://developer.arm.com/documentation/ihi0031/latest/ + * * ARM(tm) Debug Interface v6 Architecture Specification ARM IHI 0074C + * https://developer.arm.com/documentation/ihi0074/latest/ + * + * Note that diagrams B4-1 to B4-7 in both ADI specifications show + * SWCLK signal mostly in wrong polarity. See detailed SWD timing + * https://developer.arm.com/documentation/dui0499/b/arm-dstream-target-interface-connections/swd-timing-requirements + * * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index b2f78eef78..032e5ac379 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -232,13 +232,13 @@ COMMAND_HANDLER(handle_cti_dump) retval = dap_run(ap->dap); if (retval != ERROR_OK) - return JIM_ERR; + return retval; for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, cti_names[i].label, cti_names[i].offset, values[i]); - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_cti_enable) @@ -434,49 +434,47 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) return JIM_OK; } -static int cti_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_cti_create) { - struct command_context *cmd_ctx; - static struct arm_cti *cti; - Jim_Obj *new_cmd; - Jim_Cmd *cmd; - const char *cp; - int e; - - cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx); - - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); - return JIM_ERR; - } - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); - if (cmd) { - cp = Jim_GetString(new_cmd, NULL); - Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); - return JIM_ERR; + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if the cti name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/cti: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* Create it */ - cti = calloc(1, sizeof(*cti)); - if (!cti) - return JIM_ERR; + struct arm_cti *cti = calloc(1, sizeof(*cti)); + if (!cti) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } adiv5_mem_ap_spot_init(&cti->spot); /* Do the rest as "configure" options */ - goi->is_configure = true; - e = cti_configure(goi, cti); + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + goi.is_configure = 1; + int e = cti_configure(&goi, cti); if (e != JIM_OK) { + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); free(cti); - return e; + return ERROR_COMMAND_ARGUMENT_INVALID; } - cp = Jim_GetString(new_cmd, NULL); - cti->name = strdup(cp); + cti->name = strdup(CMD_ARGV[0]); + if (!cti->name) { + LOG_ERROR("Out of memory"); + free(cti); + return ERROR_FAIL; + } /* now - create the new cti name command */ const struct command_registration cti_subcommands[] = { @@ -487,7 +485,7 @@ static int cti_create(struct jim_getopt_info *goi) }; const struct command_registration cti_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "cti instance command group", .usage = "", @@ -495,31 +493,24 @@ static int cti_create(struct jim_getopt_info *goi) }, COMMAND_REGISTRATION_DONE }; - e = register_commands_with_data(cmd_ctx, NULL, cti_commands, cti); - if (e != ERROR_OK) - return JIM_ERR; + int retval = register_commands_with_data(CMD_CTX, NULL, cti_commands, cti); + if (retval != ERROR_OK) { + free(cti->name); + free(cti); + return retval; + } list_add_tail(&cti->lh, &all_cti); cti->ap = dap_get_ap(cti->spot.dap, cti->spot.ap_num); if (!cti->ap) { - Jim_SetResultString(goi->interp, "Cannot get AP", -1); - return JIM_ERR; + command_print(CMD, "Cannot get AP"); + free(cti->name); + free(cti); + return ERROR_FAIL; } - return JIM_OK; -} - -static int jim_cti_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 2) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - " [ ...]"); - return JIM_ERR; - } - return cti_create(&goi); + return ERROR_OK; } COMMAND_HANDLER(cti_handle_names) @@ -539,7 +530,7 @@ static const struct command_registration cti_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_cti_create, + .handler = handle_cti_create, .usage = "name '-chain-position' name [options ...]", .help = "Creates a new CTI object", }, diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index c5bd6ccd4d..5ba5e1c387 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -333,61 +333,59 @@ static int dap_check_config(struct adiv5_dap *dap) return ERROR_OK; } -static int dap_create(struct jim_getopt_info *goi) +COMMAND_HANDLER(handle_dap_create) { - struct command_context *cmd_ctx; - static struct arm_dap_object *dap; - Jim_Obj *new_cmd; - Jim_Cmd *cmd; - const char *cp; - int e; + if (CMD_ARGC < 3) + return ERROR_COMMAND_SYNTAX_ERROR; - cmd_ctx = current_command_context(goi->interp); - assert(cmd_ctx); + int retval = ERROR_COMMAND_ARGUMENT_INVALID; - if (goi->argc < 3) { - Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ..options..."); - return JIM_ERR; - } - /* COMMAND */ - jim_getopt_obj(goi, &new_cmd); - /* does this command exist? */ - cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE); - if (cmd) { - cp = Jim_GetString(new_cmd, NULL); - Jim_SetResultFormatted(goi->interp, "Command: %s Exists", cp); - return JIM_ERR; + /* check if the dap name clashes with an existing command name */ + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "Command/dap: %s Exists", CMD_ARGV[0]); + return ERROR_FAIL; } /* Create it */ - dap = calloc(1, sizeof(struct arm_dap_object)); - if (!dap) - return JIM_ERR; + struct arm_dap_object *dap = calloc(1, sizeof(struct arm_dap_object)); + if (!dap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } dap_instance_init(&dap->dap); - cp = Jim_GetString(new_cmd, NULL); - dap->name = strdup(cp); + dap->name = strdup(CMD_ARGV[0]); + if (!dap->name) { + LOG_ERROR("Out of memory"); + free(dap); + return ERROR_FAIL; + } - e = dap_configure(goi, dap); - if (e != JIM_OK) + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + int e = dap_configure(&goi, dap); + if (e != JIM_OK) { + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); goto err; + } if (!dap->dap.tap) { - Jim_SetResultString(goi->interp, "-chain-position required when creating DAP", -1); - e = JIM_ERR; + command_print(CMD, "-chain-position required when creating DAP"); goto err; } - e = dap_check_config(&dap->dap); - if (e != ERROR_OK) { - e = JIM_ERR; + retval = dap_check_config(&dap->dap); + if (retval != ERROR_OK) goto err; - } struct command_registration dap_create_commands[] = { { - .name = cp, + .name = CMD_ARGV[0], .mode = COMMAND_ANY, .help = "dap instance command group", .usage = "", @@ -400,32 +398,18 @@ static int dap_create(struct jim_getopt_info *goi) if (transport_is_hla()) dap_create_commands[0].chain = NULL; - e = register_commands_with_data(cmd_ctx, NULL, dap_create_commands, dap); - if (e != ERROR_OK) { - e = JIM_ERR; + retval = register_commands_with_data(CMD_CTX, NULL, dap_create_commands, dap); + if (retval != ERROR_OK) goto err; - } list_add_tail(&dap->lh, &all_dap); - return JIM_OK; + return ERROR_OK; err: free(dap->name); free(dap); - return e; -} - -static int jim_dap_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 2) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - " [ ...]"); - return JIM_ERR; - } - return dap_create(&goi); + return retval; } COMMAND_HANDLER(handle_dap_names) @@ -458,28 +442,28 @@ COMMAND_HANDLER(handle_dap_info_command) } switch (CMD_ARGC) { - case 0: - apsel = dap->apsel; - break; - case 1: - if (!strcmp(CMD_ARGV[0], "root")) { - if (!is_adiv6(dap)) { - command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); - return ERROR_COMMAND_ARGUMENT_INVALID; - } - int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); - if (retval != ERROR_OK) { - command_print(CMD, "Failed reading DAP baseptr"); - return retval; - } - break; + case 0: + apsel = dap->apsel; + break; + case 1: + if (!strcmp(CMD_ARGV[0], "root")) { + if (!is_adiv6(dap)) { + command_print(CMD, "Option \"root\" not allowed with ADIv5 DAP"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + int retval = adiv6_dap_read_baseptr(CMD, dap, &apsel); + if (retval != ERROR_OK) { + command_print(CMD, "Failed reading DAP baseptr"); + return retval; } - COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); - if (!is_ap_num_valid(dap, apsel)) - return ERROR_COMMAND_SYNTAX_ERROR; break; - default: + } + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], apsel); + if (!is_ap_num_valid(dap, apsel)) return ERROR_COMMAND_SYNTAX_ERROR; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } struct adiv5_ap *ap = dap_get_ap(dap, apsel); @@ -496,7 +480,7 @@ static const struct command_registration dap_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_dap_create, + .handler = handle_dap_create, .usage = "name '-chain-position' name", .help = "Creates a new DAP instance", }, diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 8619f8f82e..6dea19f935 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -248,39 +248,39 @@ static int evaluate_srs(uint32_t opcode, const char *mode = ""; switch ((opcode >> 23) & 0x3) { - case 0: - mode = "DA"; - break; - case 1: - /* "IA" is default */ - break; - case 2: - mode = "DB"; - break; - case 3: - mode = "IB"; - break; + case 0: + mode = "DA"; + break; + case 1: + /* "IA" is default */ + break; + case 2: + mode = "DB"; + break; + case 3: + mode = "IB"; + break; } switch (opcode & 0x0e500000) { - case 0x08400000: - snprintf(instruction->text, 128, "0x%8.8" PRIx32 - "\t0x%8.8" PRIx32 - "\tSRS%s\tSP%s, #%" PRIu32, - address, opcode, - mode, wback, - opcode & 0x1f); - break; - case 0x08100000: - snprintf(instruction->text, 128, "0x%8.8" PRIx32 - "\t0x%8.8" PRIx32 - "\tRFE%s\tr%" PRIu32 "%s", - address, opcode, - mode, - (opcode >> 16) & 0xf, wback); - break; - default: - return evaluate_unknown(opcode, address, instruction); + case 0x08400000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tSRS%s\tSP%s, #%" PRIu32, + address, opcode, + mode, wback, + opcode & 0x1f); + break; + case 0x08100000: + snprintf(instruction->text, 128, "0x%8.8" PRIx32 + "\t0x%8.8" PRIx32 + "\tRFE%s\tr%" PRIu32 "%s", + address, opcode, + mode, + (opcode >> 16) & 0xf, wback); + break; + default: + return evaluate_unknown(opcode, address, instruction); } return ERROR_OK; } @@ -324,7 +324,7 @@ static int evaluate_blx_imm(uint32_t opcode, snprintf(instruction->text, 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32, address, opcode, target_address); @@ -596,7 +596,7 @@ static int evaluate_load_store(uint32_t opcode, if (!i) { /* #+- */ uint32_t offset_12 = (opcode & 0xfff); if (offset_12) - snprintf(offset, 32, ", #%s0x%" PRIx32 "", (u) ? "" : "-", offset_12); + snprintf(offset, 32, ", #%s0x%" PRIx32, (u) ? "" : "-", offset_12); else snprintf(offset, 32, "%s", ""); @@ -631,21 +631,21 @@ static int evaluate_load_store(uint32_t opcode, snprintf(offset, 32, ", %sr%i", (u) ? "" : "-", rm); else { /* +-, , # */ switch (shift) { - case 0x0: /* LSL */ - snprintf(offset, 32, ", %sr%i, LSL #0x%x", (u) ? "" : "-", rm, shift_imm); - break; - case 0x1: /* LSR */ - snprintf(offset, 32, ", %sr%i, LSR #0x%x", (u) ? "" : "-", rm, shift_imm); - break; - case 0x2: /* ASR */ - snprintf(offset, 32, ", %sr%i, ASR #0x%x", (u) ? "" : "-", rm, shift_imm); - break; - case 0x3: /* ROR */ - snprintf(offset, 32, ", %sr%i, ROR #0x%x", (u) ? "" : "-", rm, shift_imm); - break; - case 0x4: /* RRX */ - snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); - break; + case 0x0: /* LSL */ + snprintf(offset, 32, ", %sr%i, LSL #0x%x", (u) ? "" : "-", rm, shift_imm); + break; + case 0x1: /* LSR */ + snprintf(offset, 32, ", %sr%i, LSR #0x%x", (u) ? "" : "-", rm, shift_imm); + break; + case 0x2: /* ASR */ + snprintf(offset, 32, ", %sr%i, ASR #0x%x", (u) ? "" : "-", rm, shift_imm); + break; + case 0x3: /* ROR */ + snprintf(offset, 32, ", %sr%i, ROR #0x%x", (u) ? "" : "-", rm, shift_imm); + break; + case 0x4: /* RRX */ + snprintf(offset, 32, ", %sr%i, RRX", (u) ? "" : "-", rm); + break; } } } @@ -707,33 +707,33 @@ static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp) char *type, *rot; switch ((opcode >> 24) & 0x3) { - case 0: - type = "B16"; - break; - case 1: - sprintf(cp, "UNDEFINED"); - return ARM_UNDEFINED_INSTRUCTION; - case 2: - type = "B"; - break; - default: - type = "H"; - break; + case 0: + type = "B16"; + break; + case 1: + sprintf(cp, "UNDEFINED"); + return ARM_UNDEFINED_INSTRUCTION; + case 2: + type = "B"; + break; + default: + type = "H"; + break; } switch ((opcode >> 10) & 0x3) { - case 0: - rot = ""; - break; - case 1: - rot = ", ROR #8"; - break; - case 2: - rot = ", ROR #16"; - break; - default: - rot = ", ROR #24"; - break; + case 0: + rot = ""; + break; + case 1: + rot = ", ROR #8"; + break; + case 2: + rot = ", ROR #16"; + break; + default: + rot = ", ROR #24"; + break; } if (rn == 0xf) { @@ -758,55 +758,55 @@ static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp) int type; switch ((opcode >> 20) & 0x7) { - case 1: - prefix = "S"; - break; - case 2: - prefix = "Q"; - break; - case 3: - prefix = "SH"; - break; - case 5: - prefix = "U"; - break; - case 6: - prefix = "UQ"; - break; - case 7: - prefix = "UH"; - break; - default: - goto undef; + case 1: + prefix = "S"; + break; + case 2: + prefix = "Q"; + break; + case 3: + prefix = "SH"; + break; + case 5: + prefix = "U"; + break; + case 6: + prefix = "UQ"; + break; + case 7: + prefix = "UH"; + break; + default: + goto undef; } switch ((opcode >> 5) & 0x7) { - case 0: - op = "ADD16"; - type = ARM_ADD; - break; - case 1: - op = "ADDSUBX"; - type = ARM_ADD; - break; - case 2: - op = "SUBADDX"; - type = ARM_SUB; - break; - case 3: - op = "SUB16"; - type = ARM_SUB; - break; - case 4: - op = "ADD8"; - type = ARM_ADD; - break; - case 7: - op = "SUB8"; - type = ARM_SUB; - break; - default: - goto undef; + case 0: + op = "ADD16"; + type = ARM_ADD; + break; + case 1: + op = "ADDSUBX"; + type = ARM_ADD; + break; + case 2: + op = "SUBADDX"; + type = ARM_SUB; + break; + case 3: + op = "SUB16"; + type = ARM_SUB; + break; + case 4: + op = "ADD8"; + type = ARM_ADD; + break; + case 7: + op = "SUB8"; + type = ARM_SUB; + break; + default: + goto undef; } sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode), @@ -928,14 +928,14 @@ static int evaluate_media(uint32_t opcode, uint32_t address, unsigned int rn = (opcode >> 12) & 0xf; switch (opcode & 0xc0) { - case 3: - if (rn == 0xf) - goto undef; - /* FALL THROUGH */ - case 0: - break; - default: + case 3: + if (rn == 0xf) goto undef; + /* FALL THROUGH */ + case 0: + break; + default: + goto undef; } if (rn != 0xf) @@ -959,46 +959,46 @@ static int evaluate_media(uint32_t opcode, uint32_t address, /* simple matches against the remaining decode bits */ switch (opcode & 0x01f000f0) { - case 0x00a00030: - case 0x00e00030: - /* parallel halfword saturate */ - sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", - (opcode & (1 << 22)) ? 'U' : 'S', - COND(opcode), - (int) (opcode >> 12) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - return ERROR_OK; - case 0x00b00030: - mnemonic = "REV"; - break; - case 0x00b000b0: - mnemonic = "REV16"; - break; - case 0x00f000b0: - mnemonic = "REVSH"; - break; - case 0x008000b0: - /* select bytes */ - sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), - (int) (opcode >> 12) & 0xf, - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf); - return ERROR_OK; - case 0x01800010: - /* unsigned sum of absolute differences */ - if (((opcode >> 12) & 0xf) == 0xf) - sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, - (int) (opcode >> 8) & 0xf); - else - sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), - (int) (opcode >> 16) & 0xf, - (int) (opcode >> 0) & 0xf, - (int) (opcode >> 8) & 0xf, - (int) (opcode >> 12) & 0xf); - return ERROR_OK; + case 0x00a00030: + case 0x00e00030: + /* parallel halfword saturate */ + sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", + (opcode & (1 << 22)) ? 'U' : 'S', + COND(opcode), + (int)(opcode >> 12) & 0xf, + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf); + return ERROR_OK; + case 0x00b00030: + mnemonic = "REV"; + break; + case 0x00b000b0: + mnemonic = "REV16"; + break; + case 0x00f000b0: + mnemonic = "REVSH"; + break; + case 0x008000b0: + /* select bytes */ + sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), + (int)(opcode >> 12) & 0xf, + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf); + return ERROR_OK; + case 0x01800010: + /* unsigned sum of absolute differences */ + if (((opcode >> 12) & 0xf) == 0xf) + sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf, + (int)(opcode >> 8) & 0xf); + else + sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), + (int)(opcode >> 16) & 0xf, + (int)(opcode >> 0) & 0xf, + (int)(opcode >> 8) & 0xf, + (int)(opcode >> 12) & 0xf); + return ERROR_OK; } if (mnemonic) { unsigned int rm = (opcode >> 0) & 0xf; @@ -1079,7 +1079,7 @@ static int evaluate_misc_load_store(uint32_t opcode, if (i) {/* Immediate offset/index (#+-)*/ uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf); - snprintf(offset, 32, "#%s0x%" PRIx32 "", (u) ? "" : "-", offset_8); + snprintf(offset, 32, "#%s0x%" PRIx32, (u) ? "" : "-", offset_8); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_8; @@ -1280,22 +1280,22 @@ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, s = (opcode & 0x00100000) >> 20; switch ((opcode & 0x00600000) >> 21) { - case 0x0: - instruction->type = ARM_UMULL; - mnemonic = "UMULL"; - break; - case 0x1: - instruction->type = ARM_UMLAL; - mnemonic = "UMLAL"; - break; - case 0x2: - instruction->type = ARM_SMULL; - mnemonic = "SMULL"; - break; - case 0x3: - instruction->type = ARM_SMLAL; - mnemonic = "SMLAL"; - break; + case 0x0: + instruction->type = ARM_UMULL; + mnemonic = "UMULL"; + break; + case 0x1: + instruction->type = ARM_UMLAL; + mnemonic = "UMLAL"; + break; + case 0x2: + instruction->type = ARM_SMULL; + mnemonic = "SMULL"; + break; + case 0x3: + instruction->type = ARM_SMLAL; + mnemonic = "SMLAL"; + break; } snprintf(instruction->text, @@ -1480,22 +1480,22 @@ static int evaluate_misc_instr(uint32_t opcode, rn = (opcode & 0xf0000) >> 16; switch ((opcode & 0x00600000) >> 21) { - case 0x0: - instruction->type = ARM_QADD; - mnemonic = "QADD"; - break; - case 0x1: - instruction->type = ARM_QSUB; - mnemonic = "QSUB"; - break; - case 0x2: - instruction->type = ARM_QDADD; - mnemonic = "QDADD"; - break; - case 0x3: - instruction->type = ARM_QDSUB; - mnemonic = "QDSUB"; - break; + case 0x0: + instruction->type = ARM_QADD; + mnemonic = "QADD"; + break; + case 0x1: + instruction->type = ARM_QSUB; + mnemonic = "QSUB"; + break; + case 0x2: + instruction->type = ARM_QDADD; + mnemonic = "QDADD"; + break; + case 0x3: + instruction->type = ARM_QDSUB; + mnemonic = "QDSUB"; + break; } snprintf(instruction->text, @@ -1527,26 +1527,26 @@ static int evaluate_misc_instr(uint32_t opcode, char *mnemonic = NULL; switch ((opcode & 0x600000) >> 21) { - case 0x1: - instruction->type = ARM_BKPT; - mnemonic = "BRKT"; - immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); - break; - case 0x2: - instruction->type = ARM_HVC; - mnemonic = "HVC"; - immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); - break; - case 0x3: - instruction->type = ARM_SMC; - mnemonic = "SMC"; - immediate = (opcode & 0xf); - break; + case 0x1: + instruction->type = ARM_BKPT; + mnemonic = "BRKT"; + immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); + break; + case 0x2: + instruction->type = ARM_HVC; + mnemonic = "HVC"; + immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); + break; + case 0x3: + instruction->type = ARM_SMC; + mnemonic = "SMC"; + immediate = (opcode & 0xf); + break; } snprintf(instruction->text, 128, - "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32 "", + "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32, address, opcode, mnemonic, @@ -1717,70 +1717,70 @@ static int evaluate_data_proc(uint32_t opcode, instruction->info.data_proc.s = s; switch (op) { - case 0x0: - instruction->type = ARM_AND; - mnemonic = "AND"; - break; - case 0x1: - instruction->type = ARM_EOR; - mnemonic = "EOR"; - break; - case 0x2: - instruction->type = ARM_SUB; - mnemonic = "SUB"; - break; - case 0x3: - instruction->type = ARM_RSB; - mnemonic = "RSB"; - break; - case 0x4: - instruction->type = ARM_ADD; - mnemonic = "ADD"; - break; - case 0x5: - instruction->type = ARM_ADC; - mnemonic = "ADC"; - break; - case 0x6: - instruction->type = ARM_SBC; - mnemonic = "SBC"; - break; - case 0x7: - instruction->type = ARM_RSC; - mnemonic = "RSC"; - break; - case 0x8: - instruction->type = ARM_TST; - mnemonic = "TST"; - break; - case 0x9: - instruction->type = ARM_TEQ; - mnemonic = "TEQ"; - break; - case 0xa: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0xb: - instruction->type = ARM_CMN; - mnemonic = "CMN"; - break; - case 0xc: - instruction->type = ARM_ORR; - mnemonic = "ORR"; - break; - case 0xd: - instruction->type = ARM_MOV; - mnemonic = "MOV"; - break; - case 0xe: - instruction->type = ARM_BIC; - mnemonic = "BIC"; - break; - case 0xf: - instruction->type = ARM_MVN; - mnemonic = "MVN"; - break; + case 0x0: + instruction->type = ARM_AND; + mnemonic = "AND"; + break; + case 0x1: + instruction->type = ARM_EOR; + mnemonic = "EOR"; + break; + case 0x2: + instruction->type = ARM_SUB; + mnemonic = "SUB"; + break; + case 0x3: + instruction->type = ARM_RSB; + mnemonic = "RSB"; + break; + case 0x4: + instruction->type = ARM_ADD; + mnemonic = "ADD"; + break; + case 0x5: + instruction->type = ARM_ADC; + mnemonic = "ADC"; + break; + case 0x6: + instruction->type = ARM_SBC; + mnemonic = "SBC"; + break; + case 0x7: + instruction->type = ARM_RSC; + mnemonic = "RSC"; + break; + case 0x8: + instruction->type = ARM_TST; + mnemonic = "TST"; + break; + case 0x9: + instruction->type = ARM_TEQ; + mnemonic = "TEQ"; + break; + case 0xa: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0xb: + instruction->type = ARM_CMN; + mnemonic = "CMN"; + break; + case 0xc: + instruction->type = ARM_ORR; + mnemonic = "ORR"; + break; + case 0xd: + instruction->type = ARM_MOV; + mnemonic = "MOV"; + break; + case 0xe: + instruction->type = ARM_BIC; + mnemonic = "BIC"; + break; + case 0xf: + instruction->type = ARM_MVN; + mnemonic = "MVN"; + break; } if (i) {/* immediate shifter operand (#)*/ @@ -1790,7 +1790,7 @@ static int evaluate_data_proc(uint32_t opcode, immediate = ror(immed_8, rotate_imm * 2); - snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate); + snprintf(shifter_operand, 32, "#0x%" PRIx32, immediate); instruction->info.data_proc.variant = 0; instruction->info.data_proc.shifter_operand.immediate.immediate = immediate; @@ -2065,28 +2065,28 @@ static int evaluate_b_bl_blx_thumb(uint16_t opcode, target_address = address + 4 + (offset << 1); switch (opc) { - /* unconditional branch */ - case 0: - instruction->type = ARM_B; - mnemonic = "B"; - break; - /* BLX suffix */ - case 1: - instruction->type = ARM_BLX; - mnemonic = "BLX"; - target_address &= 0xfffffffc; - break; - /* BL/BLX prefix */ - case 2: - instruction->type = ARM_UNKNOWN_INSTRUCTION; - mnemonic = "prefix"; - target_address = offset << 12; - break; - /* BL suffix */ - case 3: - instruction->type = ARM_BL; - mnemonic = "BL"; - break; + /* unconditional branch */ + case 0: + instruction->type = ARM_B; + mnemonic = "B"; + break; + /* BLX suffix */ + case 1: + instruction->type = ARM_BLX; + mnemonic = "BLX"; + target_address &= 0xfffffffc; + break; + /* BL/BLX prefix */ + case 2: + instruction->type = ARM_UNKNOWN_INSTRUCTION; + mnemonic = "prefix"; + target_address = offset << 12; + break; + /* BL suffix */ + case 3: + instruction->type = ARM_BL; + mnemonic = "BL"; + break; } /* TODO: deal correctly with dual opcode (prefixed) BL/BLX; @@ -2158,21 +2158,21 @@ static int evaluate_shift_imm_thumb(uint16_t opcode, char *mnemonic = NULL; switch (opc) { - case 0: - instruction->type = ARM_MOV; - mnemonic = "LSLS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; - break; - case 1: - instruction->type = ARM_MOV; - mnemonic = "LSRS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; - break; - case 2: - instruction->type = ARM_MOV; - mnemonic = "ASRS"; - instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; - break; + case 0: + instruction->type = ARM_MOV; + mnemonic = "LSLS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; + break; + case 1: + instruction->type = ARM_MOV; + mnemonic = "LSRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; + break; + case 2: + instruction->type = ARM_MOV; + mnemonic = "ASRS"; + instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; + break; } if ((imm == 0) && (opc != 0)) @@ -2208,24 +2208,24 @@ static int evaluate_data_proc_imm_thumb(uint16_t opcode, instruction->info.data_proc.shifter_operand.immediate.immediate = imm; switch (opc) { - case 0: - instruction->type = ARM_MOV; - mnemonic = "MOVS"; - instruction->info.data_proc.rn = -1; - break; - case 1: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - instruction->info.data_proc.rd = -1; - break; - case 2: - instruction->type = ARM_ADD; - mnemonic = "ADDS"; - break; - case 3: - instruction->type = ARM_SUB; - mnemonic = "SUBS"; - break; + case 0: + instruction->type = ARM_MOV; + mnemonic = "MOVS"; + instruction->info.data_proc.rn = -1; + break; + case 1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + instruction->info.data_proc.rd = -1; + break; + case 2: + instruction->type = ARM_ADD; + mnemonic = "ADDS"; + break; + case 3: + instruction->type = ARM_SUB; + mnemonic = "SUBS"; + break; } snprintf(instruction->text, 128, @@ -2262,131 +2262,131 @@ static int evaluate_data_proc_thumb(uint16_t opcode, op >>= 2; switch (op) { - case 0x0: - instruction->type = ARM_ADD; - mnemonic = "ADD"; - break; - case 0x1: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0x2: - instruction->type = ARM_MOV; - mnemonic = "MOV"; - if (rd == rm) - nop = true; - break; - case 0x3: - if ((opcode & 0x7) == 0x0) { - instruction->info.b_bl_bx_blx.reg_operand = rm; - if (h1) { - instruction->type = ARM_BLX; - snprintf(instruction->text, 128, - "0x%8.8" PRIx32 - " 0x%4.4x \tBLX\tr%i", - address, opcode, rm); - } else { - instruction->type = ARM_BX; - snprintf(instruction->text, 128, - "0x%8.8" PRIx32 - " 0x%4.4x \tBX\tr%i", - address, opcode, rm); - } + case 0x0: + instruction->type = ARM_ADD; + mnemonic = "ADD"; + break; + case 0x1: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0x2: + instruction->type = ARM_MOV; + mnemonic = "MOV"; + if (rd == rm) + nop = true; + break; + case 0x3: + if ((opcode & 0x7) == 0x0) { + instruction->info.b_bl_bx_blx.reg_operand = rm; + if (h1) { + instruction->type = ARM_BLX; + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 + " 0x%4.4x \tBLX\tr%i", + address, opcode, rm); } else { - instruction->type = ARM_UNDEFINED_INSTRUCTION; + instruction->type = ARM_BX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 - " 0x%4.4x \t" - "UNDEFINED INSTRUCTION", - address, opcode); + " 0x%4.4x \tBX\tr%i", + address, opcode, rm); } - return ERROR_OK; + } else { + instruction->type = ARM_UNDEFINED_INSTRUCTION; + snprintf(instruction->text, 128, + "0x%8.8" PRIx32 + " 0x%4.4x \t" + "UNDEFINED INSTRUCTION", + address, opcode); + } + return ERROR_OK; } } else { switch (op) { - case 0x0: - instruction->type = ARM_AND; - mnemonic = "ANDS"; - break; - case 0x1: - instruction->type = ARM_EOR; - mnemonic = "EORS"; - break; - case 0x2: - instruction->type = ARM_MOV; - mnemonic = "LSLS"; - instruction->info.data_proc.variant = 2 /*register shift*/; - instruction->info.data_proc.shifter_operand.register_shift.shift = 0; - instruction->info.data_proc.shifter_operand.register_shift.rm = rd; - instruction->info.data_proc.shifter_operand.register_shift.rs = rm; - break; - case 0x3: - instruction->type = ARM_MOV; - mnemonic = "LSRS"; - instruction->info.data_proc.variant = 2 /*register shift*/; - instruction->info.data_proc.shifter_operand.register_shift.shift = 1; - instruction->info.data_proc.shifter_operand.register_shift.rm = rd; - instruction->info.data_proc.shifter_operand.register_shift.rs = rm; - break; - case 0x4: - instruction->type = ARM_MOV; - mnemonic = "ASRS"; - instruction->info.data_proc.variant = 2 /*register shift*/; - instruction->info.data_proc.shifter_operand.register_shift.shift = 2; - instruction->info.data_proc.shifter_operand.register_shift.rm = rd; - instruction->info.data_proc.shifter_operand.register_shift.rs = rm; - break; - case 0x5: - instruction->type = ARM_ADC; - mnemonic = "ADCS"; - break; - case 0x6: - instruction->type = ARM_SBC; - mnemonic = "SBCS"; - break; - case 0x7: - instruction->type = ARM_MOV; - mnemonic = "RORS"; - instruction->info.data_proc.variant = 2 /*register shift*/; - instruction->info.data_proc.shifter_operand.register_shift.shift = 3; - instruction->info.data_proc.shifter_operand.register_shift.rm = rd; - instruction->info.data_proc.shifter_operand.register_shift.rs = rm; - break; - case 0x8: - instruction->type = ARM_TST; - mnemonic = "TST"; - break; - case 0x9: - instruction->type = ARM_RSB; - mnemonic = "RSBS"; - instruction->info.data_proc.variant = 0 /*immediate*/; - instruction->info.data_proc.shifter_operand.immediate.immediate = 0; - instruction->info.data_proc.rn = rm; - break; - case 0xA: - instruction->type = ARM_CMP; - mnemonic = "CMP"; - break; - case 0xB: - instruction->type = ARM_CMN; - mnemonic = "CMN"; - break; - case 0xC: - instruction->type = ARM_ORR; - mnemonic = "ORRS"; - break; - case 0xD: - instruction->type = ARM_MUL; - mnemonic = "MULS"; - break; - case 0xE: - instruction->type = ARM_BIC; - mnemonic = "BICS"; - break; - case 0xF: - instruction->type = ARM_MVN; - mnemonic = "MVNS"; - break; + case 0x0: + instruction->type = ARM_AND; + mnemonic = "ANDS"; + break; + case 0x1: + instruction->type = ARM_EOR; + mnemonic = "EORS"; + break; + case 0x2: + instruction->type = ARM_MOV; + mnemonic = "LSLS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 0; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; + break; + case 0x3: + instruction->type = ARM_MOV; + mnemonic = "LSRS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 1; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; + break; + case 0x4: + instruction->type = ARM_MOV; + mnemonic = "ASRS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 2; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; + break; + case 0x5: + instruction->type = ARM_ADC; + mnemonic = "ADCS"; + break; + case 0x6: + instruction->type = ARM_SBC; + mnemonic = "SBCS"; + break; + case 0x7: + instruction->type = ARM_MOV; + mnemonic = "RORS"; + instruction->info.data_proc.variant = 2 /*register shift*/; + instruction->info.data_proc.shifter_operand.register_shift.shift = 3; + instruction->info.data_proc.shifter_operand.register_shift.rm = rd; + instruction->info.data_proc.shifter_operand.register_shift.rs = rm; + break; + case 0x8: + instruction->type = ARM_TST; + mnemonic = "TST"; + break; + case 0x9: + instruction->type = ARM_RSB; + mnemonic = "RSBS"; + instruction->info.data_proc.variant = 0 /*immediate*/; + instruction->info.data_proc.shifter_operand.immediate.immediate = 0; + instruction->info.data_proc.rn = rm; + break; + case 0xA: + instruction->type = ARM_CMP; + mnemonic = "CMP"; + break; + case 0xB: + instruction->type = ARM_CMN; + mnemonic = "CMN"; + break; + case 0xC: + instruction->type = ARM_ORR; + mnemonic = "ORRS"; + break; + case 0xD: + instruction->type = ARM_MUL; + mnemonic = "MULS"; + break; + case 0xE: + instruction->type = ARM_BIC; + mnemonic = "BICS"; + break; + case 0xF: + instruction->type = ARM_MVN; + mnemonic = "MVNS"; + break; } } @@ -2444,38 +2444,38 @@ static int evaluate_load_store_reg_thumb(uint16_t opcode, char *mnemonic = NULL; switch (opc) { - case 0: - instruction->type = ARM_STR; - mnemonic = "STR"; - break; - case 1: - instruction->type = ARM_STRH; - mnemonic = "STRH"; - break; - case 2: - instruction->type = ARM_STRB; - mnemonic = "STRB"; - break; - case 3: - instruction->type = ARM_LDRSB; - mnemonic = "LDRSB"; - break; - case 4: - instruction->type = ARM_LDR; - mnemonic = "LDR"; - break; - case 5: - instruction->type = ARM_LDRH; - mnemonic = "LDRH"; - break; - case 6: - instruction->type = ARM_LDRB; - mnemonic = "LDRB"; - break; - case 7: - instruction->type = ARM_LDRSH; - mnemonic = "LDRSH"; - break; + case 0: + instruction->type = ARM_STR; + mnemonic = "STR"; + break; + case 1: + instruction->type = ARM_STRH; + mnemonic = "STRH"; + break; + case 2: + instruction->type = ARM_STRB; + mnemonic = "STRB"; + break; + case 3: + instruction->type = ARM_LDRSB; + mnemonic = "LDRSB"; + break; + case 4: + instruction->type = ARM_LDR; + mnemonic = "LDR"; + break; + case 5: + instruction->type = ARM_LDRH; + mnemonic = "LDRH"; + break; + case 6: + instruction->type = ARM_LDRB; + mnemonic = "LDRB"; + break; + case 7: + instruction->type = ARM_LDRSH; + mnemonic = "LDRSH"; + break; } snprintf(instruction->text, 128, @@ -2628,7 +2628,7 @@ static int evaluate_breakpoint_thumb(uint16_t opcode, instruction->type = ARM_BKPT; snprintf(instruction->text, 128, - "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "", + "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32, address, opcode, imm); return ERROR_OK; @@ -2804,15 +2804,15 @@ static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address, /* added in ARMv6 */ switch ((opcode >> 6) & 3) { - case 0: - suffix = ""; - break; - case 1: - suffix = "16"; - break; - default: - suffix = "SH"; - break; + case 0: + suffix = ""; + break; + case 1: + suffix = "16"; + break; + default: + suffix = "SH"; + break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d", @@ -2828,24 +2828,24 @@ static int evaluate_hint_thumb(uint16_t opcode, uint32_t address, char *hint; switch ((opcode >> 4) & 0x0f) { - case 0: - hint = "NOP"; - break; - case 1: - hint = "YIELD"; - break; - case 2: - hint = "WFE"; - break; - case 3: - hint = "WFI"; - break; - case 4: - hint = "SEV"; - break; - default: - hint = "HINT (UNRECOGNIZED)"; - break; + case 0: + hint = "NOP"; + break; + case 1: + hint = "YIELD"; + break; + case 2: + hint = "WFE"; + break; + case 3: + hint = "WFI"; + break; + case 4: + hint = "SEV"; + break; + default: + hint = "HINT (UNRECOGNIZED)"; + break; } snprintf(instruction->text, 128, @@ -2928,36 +2928,36 @@ int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruct /* Misc */ if ((opcode & 0xf000) == 0xb000) { switch ((opcode >> 8) & 0x0f) { - case 0x0: - return evaluate_adjust_stack_thumb(opcode, address, instruction); - case 0x1: - case 0x3: - case 0x9: - case 0xb: - return evaluate_cb_thumb(opcode, address, instruction); - case 0x2: - return evaluate_extend_thumb(opcode, address, instruction); - case 0x4: - case 0x5: - case 0xc: - case 0xd: - return evaluate_load_store_multiple_thumb(opcode, address, - instruction); - case 0x6: - return evaluate_cps_thumb(opcode, address, instruction); - case 0xa: - if ((opcode & 0x00c0) == 0x0080) - break; - return evaluate_byterev_thumb(opcode, address, instruction); - case 0xe: - return evaluate_breakpoint_thumb(opcode, address, instruction); - case 0xf: - if (opcode & 0x000f) - return evaluate_ifthen_thumb(opcode, address, - instruction); - else - return evaluate_hint_thumb(opcode, address, - instruction); + case 0x0: + return evaluate_adjust_stack_thumb(opcode, address, instruction); + case 0x1: + case 0x3: + case 0x9: + case 0xb: + return evaluate_cb_thumb(opcode, address, instruction); + case 0x2: + return evaluate_extend_thumb(opcode, address, instruction); + case 0x4: + case 0x5: + case 0xc: + case 0xd: + return evaluate_load_store_multiple_thumb(opcode, address, + instruction); + case 0x6: + return evaluate_cps_thumb(opcode, address, instruction); + case 0xa: + if ((opcode & 0x00c0) == 0x0080) + break; + return evaluate_byterev_thumb(opcode, address, instruction); + case 0xe: + return evaluate_breakpoint_thumb(opcode, address, instruction); + case 0xf: + if (opcode & 0x000f) + return evaluate_ifthen_thumb(opcode, address, + instruction); + else + return evaluate_hint_thumb(opcode, address, + instruction); } instruction->type = ARM_UNDEFINED_INSTRUCTION; diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 0b2db77c5c..26e32591a9 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -50,9 +50,8 @@ static int dpm_mrc(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) crn, - (int) crm, (int) op2); + LOG_TARGET_DEBUG(target, "MRC p%d, %" PRId32 ", r0, c%" PRId32 ", c%" PRId32 ", %" PRId32, + cpnum, op1, crn, crm, op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, @@ -74,8 +73,8 @@ static int dpm_mrrc(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, - (int)op, (int)crm); + LOG_TARGET_DEBUG(target, "MRRC p%d, %" PRId32 ", r0, r1, c%" PRId32, + cpnum, op, crm); /* read coprocessor register into R0, R1; return via DCC */ retval = dpm->instr_read_data_r0_r1(dpm, @@ -98,9 +97,8 @@ static int dpm_mcr(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, - (int) op1, (int) crn, - (int) crm, (int) op2); + LOG_TARGET_DEBUG(target, "MCR p%d, %" PRId32 ", r0, c%" PRId32 ", c%" PRId32 ", %" PRId32, + cpnum, op1, crn, crm, op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, @@ -122,8 +120,8 @@ static int dpm_mcrr(struct target *target, int cpnum, if (retval != ERROR_OK) return retval; - LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, - (int)op, (int)crm); + LOG_TARGET_DEBUG(target, "MCRR p%d, %" PRId32 ", r0, r1, c%" PRId32, + cpnum, op, crm); /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ retval = dpm->instr_write_data_r0_r1(dpm, @@ -173,24 +171,23 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int reg uint32_t value_r0, value_r1; switch (regnum) { - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - /* move from double word register to r0:r1: "vmov r0, r1, vm" - * then read r0 via dcc - */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), - ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); - if (retval != ERROR_OK) - break; - - /* read r1 via dcc */ - retval = dpm->instr_read_data_dcc(dpm, - ARMV4_5_MCR(14, 0, 1, 0, 5, 0), - &value_r1); + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* move from double word register to r0:r1: "vmov r0, r1, vm" + * then read r0 via dcc + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0); + if (retval != ERROR_OK) break; - default: - break; + /* read r1 via dcc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 1, 0, 5, 0), + &value_r1); + break; + default: + break; } if (retval == ERROR_OK) { @@ -198,7 +195,8 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int reg buf_set_u32(r->value + 4, 0, 32, value_r1); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); + LOG_TARGET_DEBUG(dpm->arm->target, "READ: %s, %8.8" PRIx32 ", %8.8" PRIx32, + r->name, value_r0, value_r1); } return retval; @@ -211,61 +209,62 @@ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) int retval; switch (regnum) { - case 0 ... 14: - /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ - retval = dpm->instr_read_data_dcc(dpm, - ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), - &value); + case 0 ... 14: + /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), + &value); + break; + case 15:/* PC + * "MOV r0, pc"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); + + /* NOTE: this seems like a slightly awkward place to update + * this value ... but if the PC gets written (the only way + * to change what we compute), the arch spec says subsequent + * reads return values which are "unpredictable". So this + * is always right except in those broken-by-intent cases. + */ + switch (dpm->arm->core_state) { + case ARM_STATE_ARM: + value -= 8; break; - case 15:/* PC - * "MOV r0, pc"; then return via DCC */ - retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); - - /* NOTE: this seems like a slightly awkward place to update - * this value ... but if the PC gets written (the only way - * to change what we compute), the arch spec says subsequent - * reads return values which are "unpredictable". So this - * is always right except in those broken-by-intent cases. - */ - switch (dpm->arm->core_state) { - case ARM_STATE_ARM: - value -= 8; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - value -= 4; - break; - case ARM_STATE_JAZELLE: - /* core-specific ... ? */ - LOG_WARNING("Jazelle PC adjustment unknown"); - break; - default: - LOG_WARNING("unknown core state"); - break; - } + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + value -= 4; break; - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - return dpm_read_reg_u64(dpm, r, regnum); - case ARM_VFP_V3_FPSCR: - /* "VMRS r0, FPSCR"; then return via DCC */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_VMRS(0), &value); + case ARM_STATE_JAZELLE: + /* core-specific ... ? */ + LOG_TARGET_WARNING(dpm->arm->target, "Jazelle PC adjustment unknown"); break; default: - /* 16: "MRS r0, CPSR"; then return via DCC - * 17: "MRS r0, SPSR"; then return via DCC - */ - retval = dpm->instr_read_data_r0(dpm, - ARMV4_5_MRS(0, regnum & 1), - &value); + LOG_TARGET_WARNING(dpm->arm->target, "unknown core state"); break; + } + break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_read_reg_u64(dpm, r, regnum); + case ARM_VFP_V3_FPSCR: + /* "VMRS r0, FPSCR"; then return via DCC */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_VMRS(0), &value); + break; + default: + /* 16: "MRS r0, CPSR"; then return via DCC + * 17: "MRS r0, SPSR"; then return via DCC + */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRS(0, regnum & 1), + &value); + break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8" PRIx32, r->name, value); + LOG_TARGET_DEBUG(dpm->arm->target, "READ: %s, %8.8" PRIx32, r->name, + value); } return retval; @@ -279,29 +278,29 @@ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int re uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32); switch (regnum) { - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - /* write value_r1 to r1 via dcc */ - retval = dpm->instr_write_data_dcc(dpm, - ARMV4_5_MRC(14, 0, 1, 0, 5, 0), - value_r1); - if (retval != ERROR_OK) - break; - - /* write value_r0 to r0 via dcc then, - * move to double word register from r0:r1: "vmov vm, r0, r1" - */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), - ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + /* write value_r1 to r1 via dcc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 1, 0, 5, 0), + value_r1); + if (retval != ERROR_OK) break; - default: - break; + /* write value_r0 to r0 via dcc then, + * move to double word register from r0:r1: "vmov vm, r0, r1" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4), + ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0); + break; + default: + break; } if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); + LOG_TARGET_DEBUG(dpm->arm->target, "WRITE: %s, %8.8" PRIx32 ", %8.8" PRIx32, + r->name, value_r0, value_r1); } return retval; @@ -314,42 +313,43 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum uint32_t value = buf_get_u32(r->value, 0, 32); switch (regnum) { - case 0 ... 14: - /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ - retval = dpm->instr_write_data_dcc(dpm, - ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), - value); - break; - case 15:/* PC - * read r0 from DCC; then "MOV pc, r0" */ - retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); - break; - case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: - return dpm_write_reg_u64(dpm, r, regnum); - case ARM_VFP_V3_FPSCR: - /* move to r0 from DCC, then "VMSR FPSCR, r0" */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_VMSR(0), value); - break; - default: - /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" - * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" - */ - retval = dpm->instr_write_data_r0(dpm, - ARMV4_5_MSR_GP(0, 0xf, regnum & 1), - value); - if (retval != ERROR_OK) - return retval; + case 0 ... 14: + /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), + value); + break; + case 15:/* PC + * read r0 from DCC; then "MOV pc, r0" */ + retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); + break; + case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31: + return dpm_write_reg_u64(dpm, r, regnum); + case ARM_VFP_V3_FPSCR: + /* move to r0 from DCC, then "VMSR FPSCR, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_VMSR(0), value); + break; + default: + /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" + * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MSR_GP(0, 0xf, regnum & 1), + value); + if (retval != ERROR_OK) + return retval; - if (regnum == 16 && dpm->instr_cpsr_sync) - retval = dpm->instr_cpsr_sync(dpm); + if (regnum == 16 && dpm->instr_cpsr_sync) + retval = dpm->instr_cpsr_sync(dpm); - break; + break; } if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8" PRIx32, r->name, value); + LOG_TARGET_DEBUG(dpm->arm->target, "WRITE: %s, %8.8" PRIx32, r->name, + value); } return retval; @@ -463,9 +463,8 @@ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, xp->address, xp->control); if (retval != ERROR_OK) - LOG_ERROR("%s: can't %s HW %spoint %d", + LOG_TARGET_ERROR(dpm->arm->target, "can't %s HW %spoint %d", disable ? "disable" : "enable", - target_name(dpm->arm->target), (xp->number < 16) ? "break" : "watch", xp->number & 0xf); done: @@ -654,24 +653,24 @@ static enum arm_mode dpm_mapmode(struct arm *arm, return ARM_MODE_ANY; switch (num) { - /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ - case 0 ... 7: - case 15: - case 16: - break; - /* r8..r12 aren't shadowed for anything except FIQ */ - case 8 ... 12: - if (mode == ARM_MODE_FIQ) - return mode; - break; - /* r13/sp, and r14/lr are always shadowed */ - case 13: - case 14: - case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: + /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ + case 0 ... 7: + case 15: + case 16: + break; + /* r8..r12 aren't shadowed for anything except FIQ */ + case 8 ... 12: + if (mode == ARM_MODE_FIQ) return mode; - default: - LOG_WARNING("invalid register #%u", num); - break; + break; + /* r13/sp, and r14/lr are always shadowed */ + case 13: + case 14: + case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR: + return mode; + default: + LOG_TARGET_WARNING(arm->target, "invalid register #%u", num); + break; } return ARM_MODE_ANY; } @@ -867,26 +866,26 @@ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, * v7 hardware, unaligned 4-byte ones too. */ switch (length) { - case 1: - control |= (1 << (addr & 3)) << 5; + case 1: + control |= (1 << (addr & 3)) << 5; + break; + case 2: + /* require 2-byte alignment */ + if (!(addr & 1)) { + control |= (3 << (addr & 2)) << 5; break; - case 2: - /* require 2-byte alignment */ - if (!(addr & 1)) { - control |= (3 << (addr & 2)) << 5; - break; - } - /* FALL THROUGH */ - case 4: - /* require 4-byte alignment */ - if (!(addr & 3)) { - control |= 0xf << 5; - break; - } - /* FALL THROUGH */ - default: - LOG_ERROR("unsupported {break,watch}point length/alignment"); - return ERROR_COMMAND_SYNTAX_ERROR; + } + /* FALL THROUGH */ + case 4: + /* require 4-byte alignment */ + if (!(addr & 3)) { + control |= 0xf << 5; + break; + } + /* FALL THROUGH */ + default: + LOG_TARGET_ERROR(dpm->arm->target, "unsupported {break,watch}point length/alignment"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: @@ -899,7 +898,7 @@ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, xp->control = control; xp->dirty = true; - LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", + LOG_TARGET_DEBUG(dpm->arm->target, "BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", xp->address, control, xp->number); /* hardware is updated in write_dirty_registers() */ @@ -919,7 +918,7 @@ static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) - LOG_DEBUG("using HW bkpt, not SW..."); + LOG_TARGET_DEBUG(dpm->arm->target, "using HW breakpoint instead of SW"); for (unsigned int i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { @@ -963,7 +962,7 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, /* this hardware doesn't support data value matching or masking */ if (wp->mask != WATCHPOINT_IGNORE_DATA_VALUE_MASK) { - LOG_DEBUG("watchpoint values and masking not supported"); + LOG_TARGET_ERROR(dpm->arm->target, "watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -973,15 +972,15 @@ static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, control = dwp->bpwp.control; switch (wp->rw) { - case WPT_READ: - control |= 1 << 3; - break; - case WPT_WRITE: - control |= 2 << 3; - break; - case WPT_ACCESS: - control |= 3 << 3; - break; + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; } dwp->bpwp.control = control; @@ -1031,17 +1030,17 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) { switch (dpm->arm->core_state) { - case ARM_STATE_ARM: - addr -= 8; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - addr -= 4; - break; - case ARM_STATE_JAZELLE: - case ARM_STATE_AARCH64: - /* ?? */ - break; + case ARM_STATE_ARM: + addr -= 8; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + addr -= 4; + break; + case ARM_STATE_JAZELLE: + case ARM_STATE_AARCH64: + /* ?? */ + break; } dpm->wp_addr = addr; } @@ -1060,21 +1059,21 @@ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ - case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ - case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ - case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - default: - target->debug_reason = DBG_REASON_UNDEFINED; - break; + case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */ + case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */ + case DSCR_ENTRY_BKPT_INSTR: /* vector catch */ + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */ + case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */ + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + default: + target->debug_reason = DBG_REASON_UNDEFINED; + break; } } @@ -1143,8 +1142,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) return ERROR_FAIL; } - LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", - target_name(target), dpm->nbp, dpm->nwp); + LOG_TARGET_INFO(target, "hardware has %d breakpoints, %d watchpoints", + dpm->nbp, dpm->nwp); /* REVISIT ... and some of those breakpoints could match * execution context IDs... @@ -1172,8 +1171,7 @@ int arm_dpm_initialize(struct arm_dpm *dpm) (void) dpm->bpwp_disable(dpm, 16 + i); } } else - LOG_WARNING("%s: can't disable breakpoints and watchpoints", - target_name(dpm->arm->target)); + LOG_TARGET_WARNING(dpm->arm->target, "can't disable breakpoints and watchpoints"); return ERROR_OK; } diff --git a/src/target/arm_simulator.c b/src/target/arm_simulator.c index 058e3d38b8..e9f6671166 100644 --- a/src/target/arm_simulator.c +++ b/src/target/arm_simulator.c @@ -130,86 +130,85 @@ static uint32_t arm_shifter_operand(struct arm_sim_interface *sim, static int pass_condition(uint32_t cpsr, uint32_t opcode) { switch ((opcode & 0xf0000000) >> 28) { - case 0x0: /* EQ */ - if (cpsr & 0x40000000) - return 1; - else - return 0; - case 0x1: /* NE */ - if (!(cpsr & 0x40000000)) - return 1; - else - return 0; - case 0x2: /* CS */ - if (cpsr & 0x20000000) - return 1; - else - return 0; - case 0x3: /* CC */ - if (!(cpsr & 0x20000000)) - return 1; - else - return 0; - case 0x4: /* MI */ - if (cpsr & 0x80000000) - return 1; - else - return 0; - case 0x5: /* PL */ - if (!(cpsr & 0x80000000)) - return 1; - else - return 0; - case 0x6: /* VS */ - if (cpsr & 0x10000000) - return 1; - else - return 0; - case 0x7: /* VC */ - if (!(cpsr & 0x10000000)) - return 1; - else - return 0; - case 0x8: /* HI */ - if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) - return 1; - else - return 0; - case 0x9: /* LS */ - if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) - return 1; - else - return 0; - case 0xa: /* GE */ - if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xb: /* LT */ - if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xc: /* GT */ - if (!(cpsr & 0x40000000) && - (((cpsr & 0x80000000) && (cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) - return 1; - else - return 0; - case 0xd: /* LE */ - if ((cpsr & 0x40000000) || - ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) - || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) - return 1; - else - return 0; - case 0xe: - case 0xf: + case 0x0: /* EQ */ + if (cpsr & 0x40000000) return 1; - + else + return 0; + case 0x1: /* NE */ + if (!(cpsr & 0x40000000)) + return 1; + else + return 0; + case 0x2: /* CS */ + if (cpsr & 0x20000000) + return 1; + else + return 0; + case 0x3: /* CC */ + if (!(cpsr & 0x20000000)) + return 1; + else + return 0; + case 0x4: /* MI */ + if (cpsr & 0x80000000) + return 1; + else + return 0; + case 0x5: /* PL */ + if (!(cpsr & 0x80000000)) + return 1; + else + return 0; + case 0x6: /* VS */ + if (cpsr & 0x10000000) + return 1; + else + return 0; + case 0x7: /* VC */ + if (!(cpsr & 0x10000000)) + return 1; + else + return 0; + case 0x8: /* HI */ + if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) + return 1; + else + return 0; + case 0x9: /* LS */ + if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) + return 1; + else + return 0; + case 0xa: /* GE */ + if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xb: /* LT */ + if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xc: /* GT */ + if (!(cpsr & 0x40000000) && + (((cpsr & 0x80000000) && (cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) + return 1; + else + return 0; + case 0xd: /* LE */ + if ((cpsr & 0x40000000) || + ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) + || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) + return 1; + else + return 0; + case 0xe: + case 0xf: + return 1; } LOG_ERROR("BUG: should never get here"); @@ -510,18 +509,18 @@ static int arm_simulate_step_core(struct target *target, } switch (instruction.info.load_store_multiple.addressing_mode) { - case 0: /* Increment after */ - /* rn = rn; */ - break; - case 1: /* Increment before */ - rn = rn + 4; - break; - case 2: /* Decrement after */ - rn = rn - (bits_set * 4) + 4; - break; - case 3: /* Decrement before */ - rn = rn - (bits_set * 4); - break; + case 0: /* Increment after */ + /* rn = rn; */ + break; + case 1: /* Increment before */ + rn = rn + 4; + break; + case 2: /* Decrement after */ + rn = rn - (bits_set * 4) + 4; + break; + case 3: /* Decrement before */ + rn = rn - (bits_set * 4); + break; } for (i = 0; i < 16; i++) { @@ -590,18 +589,18 @@ static int arm_simulate_step_core(struct target *target, } switch (instruction.info.load_store_multiple.addressing_mode) { - case 0: /* Increment after */ - /* rn = rn; */ - break; - case 1: /* Increment before */ - rn = rn + 4; - break; - case 2: /* Decrement after */ - rn = rn - (bits_set * 4) + 4; - break; - case 3: /* Decrement before */ - rn = rn - (bits_set * 4); - break; + case 0: /* Increment after */ + /* rn = rn; */ + break; + case 1: /* Increment before */ + rn = rn + 4; + break; + case 2: /* Decrement after */ + rn = rn - (bits_set * 4) + 4; + break; + case 3: /* Decrement before */ + rn = rn - (bits_set * 4); + break; } for (i = 0; i < 16; i++) { diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index e20cd59272..afdd8ce919 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -554,20 +554,28 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s return JIM_ERR; } -static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(handle_arm_tpiu_swo_configure) { - struct command *c = jim_to_command(interp); + struct arm_tpiu_swo_object *obj = CMD_DATA; + + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC, CMD_JIMTCL_ARGV); + goi.is_configure = !strcmp(CMD_NAME, "configure"); - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.is_configure = !strcmp(c->name, "configure"); - if (goi.argc < 1) { - Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - "missing: -option ..."); - return JIM_ERR; - } - struct arm_tpiu_swo_object *obj = c->jim_handler_data; - return arm_tpiu_swo_configure(&goi, obj); + int e = arm_tpiu_swo_configure(&goi, obj); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + + if (e != JIM_OK) + return ERROR_FAIL; + + return ERROR_OK; } static int wrap_write_u32(struct target *target, struct adiv5_ap *tpiu_ap, @@ -872,14 +880,14 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[ { .name = "configure", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_configure, + .handler = handle_arm_tpiu_swo_configure, .help = "configure a new TPIU/SWO for use", .usage = "[attribute value ...]", }, { .name = "cget", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_configure, + .handler = handle_arm_tpiu_swo_configure, .help = "returns the specified TPIU/SWO attribute", .usage = "attribute", }, @@ -907,56 +915,25 @@ static const struct command_registration arm_tpiu_swo_instance_command_handlers[ COMMAND_REGISTRATION_DONE }; -static int arm_tpiu_swo_create(Jim_Interp *interp, struct arm_tpiu_swo_object *obj) +COMMAND_HANDLER(handle_arm_tpiu_swo_create) { - struct command_context *cmd_ctx; - Jim_Cmd *cmd; - int e; + int retval = ERROR_FAIL; - cmd_ctx = current_command_context(interp); - assert(cmd_ctx); + if (!CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; /* does this command exist? */ - cmd = Jim_GetCommand(interp, Jim_NewStringObj(interp, obj->name, -1), JIM_NONE); - if (cmd) { - Jim_SetResultFormatted(interp, "cannot create TPIU object because a command with name '%s' already exists", - obj->name); - return JIM_ERR; - } - - /* now - create the new tpiu/swo name command */ - const struct command_registration obj_commands[] = { - { - .name = obj->name, - .mode = COMMAND_ANY, - .help = "tpiu/swo instance command group", - .usage = "", - .chain = arm_tpiu_swo_instance_command_handlers, - }, - COMMAND_REGISTRATION_DONE - }; - e = register_commands_with_data(cmd_ctx, NULL, obj_commands, obj); - if (e != ERROR_OK) - return JIM_ERR; - - list_add_tail(&obj->lh, &all_tpiu_swo); - - return JIM_OK; -} - -static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 1) { - Jim_WrongNumArgs(interp, 1, argv, "name ?option option ...?"); - return JIM_ERR; + Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], JIM_NONE); + if (jimcmd) { + command_print(CMD, "cannot create TPIU object because a command with name '%s' already exists", + CMD_ARGV[0]); + return ERROR_FAIL; } struct arm_tpiu_swo_object *obj = calloc(1, sizeof(struct arm_tpiu_swo_object)); if (!obj) { LOG_ERROR("Out of memory"); - return JIM_ERR; + return ERROR_FAIL; } INIT_LIST_HEAD(&obj->connections); adiv5_mem_ap_spot_init(&obj->spot); @@ -968,36 +945,55 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const goto err_exit; } - Jim_Obj *n; - jim_getopt_obj(&goi, &n); - obj->name = strdup(Jim_GetString(n, NULL)); + obj->name = strdup(CMD_ARGV[0]); if (!obj->name) { LOG_ERROR("Out of memory"); goto err_exit; } /* Do the rest as "configure" options */ - goi.is_configure = true; + struct jim_getopt_info goi; + jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 1, CMD_JIMTCL_ARGV + 1); + goi.is_configure = 1; int e = arm_tpiu_swo_configure(&goi, obj); + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + if (e != JIM_OK) goto err_exit; if (!obj->spot.dap || obj->spot.ap_num == DP_APSEL_INVALID) { - Jim_SetResultString(goi.interp, "-dap and -ap-num required when creating TPIU", -1); + command_print(CMD, "-dap and -ap-num required when creating TPIU"); goto err_exit; } - e = arm_tpiu_swo_create(goi.interp, obj); - if (e != JIM_OK) + /* now - create the new tpiu/swo name command */ + const struct command_registration obj_commands[] = { + { + .name = obj->name, + .mode = COMMAND_ANY, + .help = "tpiu/swo instance command group", + .usage = "", + .chain = arm_tpiu_swo_instance_command_handlers, + }, + COMMAND_REGISTRATION_DONE + }; + retval = register_commands_with_data(CMD_CTX, NULL, obj_commands, obj); + if (retval != ERROR_OK) goto err_exit; - return JIM_OK; + list_add_tail(&obj->lh, &all_tpiu_swo); + + return ERROR_OK; err_exit: free(obj->name); free(obj->out_filename); free(obj); - return JIM_ERR; + return retval; } COMMAND_HANDLER(handle_arm_tpiu_swo_names) @@ -1192,7 +1188,7 @@ static const struct command_registration arm_tpiu_swo_subcommand_handlers[] = { { .name = "create", .mode = COMMAND_ANY, - .jim_handler = jim_arm_tpiu_swo_create, + .handler = handle_arm_tpiu_swo_create, .usage = "name [-dap dap] [-ap-num num] [-baseaddr baseaddr]", .help = "Creates a new TPIU or SWO object", }, diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 597dc8990c..8e03184d3e 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -192,30 +192,30 @@ bool is_arm_mode(unsigned int psr_mode) int arm_mode_to_number(enum arm_mode mode) { switch (mode) { - case ARM_MODE_ANY: - /* map MODE_ANY to user mode */ - case ARM_MODE_USR: - return 0; - case ARM_MODE_FIQ: - return 1; - case ARM_MODE_IRQ: - return 2; - case ARM_MODE_SVC: - return 3; - case ARM_MODE_ABT: - return 4; - case ARM_MODE_UND: - return 5; - case ARM_MODE_SYS: - return 6; - case ARM_MODE_MON: - case ARM_MODE_1176_MON: - return 7; - case ARM_MODE_HYP: - return 8; - default: - LOG_ERROR("invalid mode value encountered %d", mode); - return -1; + case ARM_MODE_ANY: + /* map MODE_ANY to user mode */ + case ARM_MODE_USR: + return 0; + case ARM_MODE_FIQ: + return 1; + case ARM_MODE_IRQ: + return 2; + case ARM_MODE_SVC: + return 3; + case ARM_MODE_ABT: + return 4; + case ARM_MODE_UND: + return 5; + case ARM_MODE_SYS: + return 6; + case ARM_MODE_MON: + case ARM_MODE_1176_MON: + return 7; + case ARM_MODE_HYP: + return 8; + default: + LOG_ERROR("invalid mode value encountered %d", mode); + return -1; } } @@ -223,27 +223,27 @@ int arm_mode_to_number(enum arm_mode mode) enum arm_mode armv4_5_number_to_mode(int number) { switch (number) { - case 0: - return ARM_MODE_USR; - case 1: - return ARM_MODE_FIQ; - case 2: - return ARM_MODE_IRQ; - case 3: - return ARM_MODE_SVC; - case 4: - return ARM_MODE_ABT; - case 5: - return ARM_MODE_UND; - case 6: - return ARM_MODE_SYS; - case 7: - return ARM_MODE_MON; - case 8: - return ARM_MODE_HYP; - default: - LOG_ERROR("mode index out of bounds %d", number); - return ARM_MODE_ANY; + case 0: + return ARM_MODE_USR; + case 1: + return ARM_MODE_FIQ; + case 2: + return ARM_MODE_IRQ; + case 3: + return ARM_MODE_SVC; + case 4: + return ARM_MODE_ABT; + case 5: + return ARM_MODE_UND; + case 6: + return ARM_MODE_SYS; + case 7: + return ARM_MODE_MON; + case 8: + return ARM_MODE_HYP; + default: + LOG_ERROR("mode index out of bounds %d", number); + return ARM_MODE_ANY; } } @@ -437,7 +437,7 @@ const int armv4_5_core_reg_map[9][17] = { static const char *arm_core_state_string(struct arm *arm) { if (arm->core_state > ARRAY_SIZE(arm_state_strings)) { - LOG_ERROR("core_state exceeds table size"); + LOG_TARGET_ERROR(arm->target, "core_state exceeds table size"); return "Unknown"; } @@ -483,20 +483,20 @@ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 24)) { /* J */ - LOG_WARNING("ThumbEE -- incomplete support"); + LOG_TARGET_WARNING(arm->target, "ThumbEE -- incomplete support"); state = ARM_STATE_THUMB_EE; } else state = ARM_STATE_THUMB; } else { if (cpsr & (1 << 24)) { /* J */ - LOG_ERROR("Jazelle state handling is BROKEN!"); + LOG_TARGET_ERROR(arm->target, "Jazelle state handling is broken"); state = ARM_STATE_JAZELLE; } else state = ARM_STATE_ARM; } arm->core_state = state; - LOG_DEBUG("set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, + LOG_TARGET_DEBUG(arm->target, "set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, arm_mode_name(mode), arm_core_state_string(arm)); } @@ -521,7 +521,7 @@ struct reg *arm_reg_current(struct arm *arm, unsigned int regnum) return NULL; if (!arm->map) { - LOG_ERROR("Register map is not available yet, the target is not fully initialised"); + LOG_TARGET_ERROR(arm->target, "Register map is not available yet, the target is not fully initialised"); r = arm->core_cache->reg_list + regnum; } else r = arm->core_cache->reg_list + arm->map[regnum]; @@ -530,7 +530,7 @@ struct reg *arm_reg_current(struct arm *arm, unsigned int regnum) * that doesn't support it... */ if (!r) { - LOG_ERROR("Invalid CPSR mode"); + LOG_TARGET_ERROR(arm->target, "Invalid CPSR mode"); r = arm->core_cache->reg_list + regnum; } @@ -631,7 +631,7 @@ static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) */ if (armv4_5_target->core_mode != (enum arm_mode)(value & 0x1f)) { - LOG_DEBUG("changing ARM core mode to '%s'", + LOG_TARGET_DEBUG(target, "changing ARM core mode to '%s'", arm_mode_name(value & 0x1f)); value &= ~((1 << 24) | (1 << 5)); uint8_t t[4]; @@ -798,7 +798,7 @@ int arm_arch_state(struct target *target) struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { - LOG_ERROR("BUG: called for a non-ARM target"); + LOG_TARGET_ERROR(target, "BUG: called for a non-ARM target"); return ERROR_FAIL; } @@ -806,7 +806,7 @@ int arm_arch_state(struct target *target) if (target->semihosting && target->semihosting->hit_fileio) return ERROR_OK; - LOG_USER("target halted in %s state due to %s, current mode: %s\n" + LOG_TARGET_USER(target, "target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s%s", arm_core_state_string(arm), debug_reason_name(target), @@ -842,7 +842,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) } if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + command_print(CMD, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } @@ -864,26 +864,26 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { - case ARM_MODE_SYS: + case ARM_MODE_SYS: + continue; + case ARM_MODE_USR: + name = "System and User"; + sep = ""; + break; + case ARM_MODE_HYP: + if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) continue; - case ARM_MODE_USR: - name = "System and User"; - sep = ""; - break; - case ARM_MODE_HYP: - if (arm->core_type != ARM_CORE_TYPE_VIRT_EXT) - continue; - /* FALLTHROUGH */ - case ARM_MODE_MON: - case ARM_MODE_1176_MON: - if (arm->core_type != ARM_CORE_TYPE_SEC_EXT - && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) - continue; - /* FALLTHROUGH */ - default: - name = arm_mode_data[mode].name; - shadow = "shadow "; - break; + /* FALLTHROUGH */ + case ARM_MODE_MON: + case ARM_MODE_1176_MON: + if (arm->core_type != ARM_CORE_TYPE_SEC_EXT + && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) + continue; + /* FALLTHROUGH */ + default: + name = arm_mode_data[mode].name; + shadow = "shadow "; + break; } command_print(CMD, "%s%s mode %sregisters", sep, name, shadow); @@ -954,7 +954,7 @@ COMMAND_HANDLER(handle_arm_disassemble_command) struct target *target = get_current_target(CMD_CTX); if (!target) { - LOG_ERROR("No target selected"); + command_print(CMD, "No target selected"); return ERROR_FAIL; } @@ -974,26 +974,26 @@ COMMAND_HANDLER(handle_arm_disassemble_command) } switch (CMD_ARGC) { - case 3: - if (strcmp(CMD_ARGV[2], "thumb") != 0) - return ERROR_COMMAND_SYNTAX_ERROR; - thumb = true; - /* FALL THROUGH */ - case 2: - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); - /* FALL THROUGH */ - case 1: - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - if (address & 0x01) { - if (!thumb) { - command_print(CMD, "Disassemble as Thumb"); - thumb = true; - } - address &= ~1; - } - break; - default: + case 3: + if (strcmp(CMD_ARGV[2], "thumb") != 0) return ERROR_COMMAND_SYNTAX_ERROR; + thumb = true; + /* FALL THROUGH */ + case 2: + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); + /* FALL THROUGH */ + case 1: + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + if (address & 0x01) { + if (!thumb) { + command_print(CMD, "Disassemble as Thumb"); + thumb = true; + } + address &= ~1; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return arm_disassemble(CMD, target, address, count, thumb); @@ -1291,7 +1291,7 @@ int arm_get_gdb_reg_list(struct target *target, unsigned int i; if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + LOG_TARGET_ERROR(target, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } @@ -1314,14 +1314,14 @@ int arm_get_gdb_reg_list(struct target *target, case REG_CLASS_ALL: switch (arm->core_type) { - case ARM_CORE_TYPE_SEC_EXT: - *reg_list_size = 51; - break; - case ARM_CORE_TYPE_VIRT_EXT: - *reg_list_size = 53; - break; - default: - *reg_list_size = 48; + case ARM_CORE_TYPE_SEC_EXT: + *reg_list_size = 51; + break; + case ARM_CORE_TYPE_VIRT_EXT: + *reg_list_size = 53; + break; + default: + *reg_list_size = 48; } unsigned int list_size_core = *reg_list_size; if (arm->arm_vfp_version == ARM_VFP_V3) @@ -1362,7 +1362,7 @@ int arm_get_gdb_reg_list(struct target *target, return ERROR_OK; default: - LOG_ERROR("not a valid register class type in query."); + LOG_TARGET_ERROR(target, "not a valid register class type in query"); return ERROR_FAIL; } } @@ -1391,8 +1391,7 @@ static int armv4_5_run_algorithm_completion(struct target *target, /* fast exit: ARMv5+ code can use BKPT */ if (exit_point && buf_get_u32(arm->pc->value, 0, 32) != exit_point) { - LOG_WARNING( - "target reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32 "", + LOG_TARGET_ERROR(target, "reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); return ERROR_TARGET_TIMEOUT; } @@ -1417,10 +1416,10 @@ int armv4_5_run_algorithm_inner(struct target *target, int i; int retval = ERROR_OK; - LOG_DEBUG("Running algorithm"); + LOG_TARGET_DEBUG(target, "Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { - LOG_ERROR("current target isn't an ARMV4/5 target"); + LOG_TARGET_ERROR(target, "current target isn't an ARMV4/5 target"); return ERROR_TARGET_INVALID; } @@ -1430,13 +1429,13 @@ int armv4_5_run_algorithm_inner(struct target *target, } if (!is_arm_mode(arm->core_mode)) { - LOG_ERROR("not a valid arm core mode - communication failure?"); + LOG_TARGET_ERROR(target, "not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->arch == ARM_ARCH_V4) { - LOG_ERROR("ARMv4 target needs HW breakpoint location"); + LOG_TARGET_ERROR(target, "ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } @@ -1470,12 +1469,12 @@ int armv4_5_run_algorithm_inner(struct target *target, struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, false); if (!reg) { - LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { - LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1491,12 +1490,12 @@ int armv4_5_run_algorithm_inner(struct target *target, else if (arm->core_state == ARM_STATE_THUMB) exit_breakpoint_size = 2; else { - LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); + LOG_TARGET_ERROR(target, "BUG: can't execute algorithms when not in ARM or Thumb state"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { - LOG_DEBUG("setting core_mode: 0x%2.2x", + LOG_TARGET_DEBUG(target, "setting core_mode: 0x%2.2x", arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, arm_algorithm_info->core_mode); @@ -1509,7 +1508,7 @@ int armv4_5_run_algorithm_inner(struct target *target, retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD); if (retval != ERROR_OK) { - LOG_ERROR("can't add HW breakpoint to terminate algorithm"); + LOG_TARGET_ERROR(target, "can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } @@ -1542,13 +1541,13 @@ int armv4_5_run_algorithm_inner(struct target *target, reg_params[i].reg_name, false); if (!reg) { - LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { - LOG_ERROR( + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; @@ -1565,7 +1564,7 @@ int armv4_5_run_algorithm_inner(struct target *target, regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32); if (regvalue != context[i]) { - LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", + LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, @@ -1667,7 +1666,7 @@ int arm_checksum_memory(struct target *target, if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else - LOG_ERROR("error executing ARM crc algorithm"); + LOG_TARGET_ERROR(target, "error executing ARM CRC algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -1702,7 +1701,7 @@ int arm_blank_check_memory(struct target *target, assert(sizeof(check_code_le) % 4 == 0); if (erased_value != 0xff) { - LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets", + LOG_TARGET_ERROR(target, "Erase value 0x%02" PRIx8 " not yet supported for ARMv4/v5 targets", erased_value); return ERROR_FAIL; } @@ -1781,7 +1780,7 @@ static int arm_default_mrc(struct target *target, int cpnum, uint32_t crn, uint32_t crm, uint32_t *value) { - LOG_ERROR("%s doesn't implement MRC", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MRC", target_type_name(target)); return ERROR_FAIL; } @@ -1789,7 +1788,7 @@ static int arm_default_mrrc(struct target *target, int cpnum, uint32_t op, uint32_t crm, uint64_t *value) { - LOG_ERROR("%s doesn't implement MRRC", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MRRC", target_type_name(target)); return ERROR_FAIL; } @@ -1798,7 +1797,7 @@ static int arm_default_mcr(struct target *target, int cpnum, uint32_t crn, uint32_t crm, uint32_t value) { - LOG_ERROR("%s doesn't implement MCR", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MCR", target_type_name(target)); return ERROR_FAIL; } @@ -1806,7 +1805,7 @@ static int arm_default_mcrr(struct target *target, int cpnum, uint32_t op, uint32_t crm, uint64_t value) { - LOG_ERROR("%s doesn't implement MCRR", target_type_name(target)); + LOG_TARGET_ERROR(target, "%s doesn't implement MCRR", target_type_name(target)); return ERROR_FAIL; } diff --git a/src/target/armv4_5_cache.h b/src/target/armv4_5_cache.h index 3659941e52..63fbdff33a 100644 --- a/src/target/armv4_5_cache.h +++ b/src/target/armv4_5_cache.h @@ -24,8 +24,8 @@ struct armv4_5_cache_common { int separate; /* separate caches or unified cache */ struct armv4_5_cachesize d_u_size; /* data cache */ struct armv4_5_cachesize i_size; /* instruction cache */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; }; int armv4_5_identify_cache(uint32_t cache_type_reg, diff --git a/src/target/armv4_5_mmu.c b/src/target/armv4_5_mmu.c index 0c09cb4ca7..4337bfb8fa 100644 --- a/src/target/armv4_5_mmu.c +++ b/src/target/armv4_5_mmu.c @@ -31,7 +31,7 @@ int armv4_5_mmu_translate_va(struct target *target, return retval; first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor); - 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) { LOG_ERROR("Address translation failure"); @@ -68,7 +68,7 @@ int armv4_5_mmu_translate_va(struct target *target, second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor); - 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) { LOG_ERROR("Address translation failure"); diff --git a/src/target/armv4_5_mmu.h b/src/target/armv4_5_mmu.h index 774f1056eb..bb30e807f4 100644 --- a/src/target/armv4_5_mmu.h +++ b/src/target/armv4_5_mmu.h @@ -21,7 +21,7 @@ struct armv4_5_mmu_common { int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); struct armv4_5_cache_common armv4_5_cache; int has_tiny_pages; - int mmu_enabled; + bool mmu_enabled; }; int armv4_5_mmu_translate_va(struct target *target, diff --git a/src/target/armv7a.c b/src/target/armv7a.c index c14155e013..9cde67788f 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -18,6 +18,7 @@ #include "register.h" #include +#include #include #include @@ -68,9 +69,9 @@ static void armv7a_show_fault_registers(struct target *target) if (retval != ERROR_OK) goto done; - LOG_USER("Data fault registers DFSR: %8.8" PRIx32 + LOG_TARGET_USER(target, "Data fault registers DFSR: %8.8" PRIx32 ", DFAR: %8.8" PRIx32, dfsr, dfar); - LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 + LOG_TARGET_USER(target, "Instruction fault registers IFSR: %8.8" PRIx32 ", IFAR: %8.8" PRIx32, ifsr, ifar); done: @@ -134,11 +135,11 @@ int armv7a_read_ttbcr(struct target *target) if (retval != ERROR_OK) goto done; - LOG_DEBUG("ttbcr %" PRIx32, ttbcr); + LOG_TARGET_DEBUG(target, "ttbcr %" PRIx32, ttbcr); ttbcr_n = ttbcr & 0x7; armv7a->armv7a_mmu.ttbcr = ttbcr; - armv7a->armv7a_mmu.cached = 1; + armv7a->armv7a_mmu.cached = true; for (ttbidx = 0; ttbidx < 2; ttbidx++) { /* MRC p15,0,,c2,c0,ttbidx */ @@ -157,7 +158,7 @@ int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbr_range[1] = 0xffffffff; armv7a->armv7a_mmu.ttbr_mask[0] = 0xffffffff << (14 - ttbcr_n); armv7a->armv7a_mmu.ttbr_mask[1] = 0xffffffff << 14; - armv7a->armv7a_mmu.cached = 1; + armv7a->armv7a_mmu.cached = true; retval = armv7a_read_midr(target); if (retval != ERROR_OK) @@ -169,7 +170,7 @@ int armv7a_read_ttbcr(struct target *target) armv7a->armv7a_mmu.ttbr_mask[0] = 7 << (32 - ttbcr_n); } - LOG_DEBUG("ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, + LOG_TARGET_DEBUG(target, "ttbr1 %s, ttbr0_mask %" PRIx32 " ttbr1_mask %" PRIx32, (ttbcr_n != 0) ? "used" : "not used", armv7a->armv7a_mmu.ttbr_mask[0], armv7a->armv7a_mmu.ttbr_mask[1]); @@ -179,63 +180,14 @@ int armv7a_read_ttbcr(struct target *target) return retval; } -/* FIXME: remove it */ -static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) -{ - struct armv7a_l2x_cache *l2x_cache; - struct target_list *head; - - struct armv7a_common *armv7a = target_to_armv7a(target); - l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); - l2x_cache->base = base; - l2x_cache->way = way; - /*LOG_INFO("cache l2 initialized base %x way %d", - l2x_cache->base,l2x_cache->way);*/ - if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) - LOG_INFO("outer cache already initialized\n"); - armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; - /* initialize all target in this cluster (smp target) - * l2 cache must be configured after smp declaration */ - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - if (curr != target) { - armv7a = target_to_armv7a(curr); - if (armv7a->armv7a_mmu.armv7a_cache.outer_cache) - LOG_ERROR("smp target : outer cache already initialized\n"); - armv7a->armv7a_mmu.armv7a_cache.outer_cache = l2x_cache; - } - } - return JIM_OK; -} - -/* FIXME: remove it */ -COMMAND_HANDLER(handle_cache_l2x) -{ - struct target *target = get_current_target(CMD_CTX); - uint32_t base, way; - - if (CMD_ARGC != 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - /* command_print(CMD, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */ - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way); - - /* AP address is in bits 31:24 of DP_SELECT */ - armv7a_l2x_cache_init(target, base, way); - - return ERROR_OK; -} - int armv7a_handle_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache) { - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a_cache->outer_cache); + struct armv7a_l2x_cache *l2x_cache = armv7a_cache->outer_cache; int cl; - if (armv7a_cache->info == -1) { + if (!armv7a_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -297,14 +249,13 @@ static int armv7a_read_mpidr(struct target *target) /* Is register in Multiprocessing Extensions register format? */ if (mpidr & MPIDR_MP_EXT) { - LOG_DEBUG("%s: MPIDR 0x%" PRIx32, target_name(target), mpidr); + LOG_TARGET_DEBUG(target, "%s: MPIDR 0x%" PRIx32, target_name(target), mpidr); armv7a->multi_processor_system = (mpidr >> 30) & 1; armv7a->multi_threading_processor = (mpidr >> 24) & 1; armv7a->level2_id = (mpidr >> 16) & 0xf; armv7a->cluster_id = (mpidr >> 8) & 0xf; armv7a->cpu_id = mpidr & 0xf; - LOG_INFO("%s: MPIDR level2 %x, cluster %x, core %x, %s, %s", - target_name(target), + LOG_TARGET_INFO(target, "MPIDR level2 %x, cluster %x, core %x, %s, %s", armv7a->level2_id, armv7a->cluster_id, armv7a->cpu_id, @@ -312,7 +263,7 @@ static int armv7a_read_mpidr(struct target *target) armv7a->multi_threading_processor == 1 ? "SMT" : "no SMT"); } else - LOG_ERROR("MPIDR not in multiprocessor format"); + LOG_TARGET_DEBUG(target, "MPIDR not in multiprocessor format"); done: dpm->finish(dpm); @@ -387,7 +338,7 @@ int armv7a_identify_cache(struct target *target) cache->iminline = 4UL << (ctr & 0xf); cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); - LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, + LOG_TARGET_DEBUG(target, "ctr %" PRIx32 " ctr.iminline %" PRIu32 " ctr.dminline %" PRIu32, ctr, cache->iminline, cache->dminline); /* retrieve CLIDR @@ -399,7 +350,7 @@ int armv7a_identify_cache(struct target *target) goto done; cache->loc = (clidr & 0x7000000) >> 24; - LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); + LOG_TARGET_DEBUG(target, "Number of cache levels to PoC %" PRId32, cache->loc); /* retrieve selected cache for later restore * MRC p15, 2,, c0, c0, 0; Read CSSELR */ @@ -427,13 +378,13 @@ int armv7a_identify_cache(struct target *target) goto done; cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); - LOG_DEBUG("data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + LOG_TARGET_DEBUG(target, "data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].d_u_size.index, cache->arch[cl].d_u_size.index_shift, cache->arch[cl].d_u_size.way, cache->arch[cl].d_u_size.way_shift); - LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + LOG_TARGET_DEBUG(target, "cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].d_u_size.linelen, cache->arch[cl].d_u_size.cachesize, cache->arch[cl].d_u_size.associativity); @@ -447,13 +398,13 @@ int armv7a_identify_cache(struct target *target) goto done; cache->arch[cl].i_size = decode_cache_reg(cache_reg); - LOG_DEBUG("instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + LOG_TARGET_DEBUG(target, "instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, cache->arch[cl].i_size.index, cache->arch[cl].i_size.index_shift, cache->arch[cl].i_size.way, cache->arch[cl].i_size.way_shift); - LOG_DEBUG("cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + LOG_TARGET_DEBUG(target, "cacheline %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", cache->arch[cl].i_size.linelen, cache->arch[cl].i_size.cachesize, cache->arch[cl].i_size.associativity); @@ -476,7 +427,7 @@ int armv7a_identify_cache(struct target *target) armv7a_cache_flush_all_data; } - armv7a->armv7a_mmu.armv7a_cache.info = 1; + armv7a->armv7a_mmu.armv7a_cache.info_valid = true; done: dpm->finish(dpm); armv7a_read_mpidr(target); @@ -494,7 +445,7 @@ static int armv7a_setup_semihosting(struct target *target, int enable) armv7a->debug_base + CPUDBG_VCR, &vcr); if (ret < 0) { - LOG_ERROR("Failed to read VCR register\n"); + LOG_TARGET_ERROR(target, "Failed to read VCR register"); return ret; } @@ -507,7 +458,7 @@ static int armv7a_setup_semihosting(struct target *target, int enable) armv7a->debug_base + CPUDBG_VCR, vcr); if (ret < 0) - LOG_ERROR("Failed to write VCR register\n"); + LOG_TARGET_ERROR(target, "Failed to write VCR register"); return ret; } @@ -522,7 +473,7 @@ int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) armv7a->arm.target = target; armv7a->arm.common_magic = ARM_COMMON_MAGIC; armv7a->common_magic = ARMV7_COMMON_MAGIC; - armv7a->armv7a_mmu.armv7a_cache.info = -1; + armv7a->armv7a_mmu.armv7a_cache.info_valid = false; armv7a->armv7a_mmu.armv7a_cache.outer_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL; return ERROR_OK; @@ -530,29 +481,25 @@ int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) int armv7a_arch_state(struct target *target) { - static const char *state[] = { - "disabled", "enabled" - }; - struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; if (armv7a->common_magic != ARMV7_COMMON_MAGIC) { - LOG_ERROR("BUG: called for a non-ARMv7A target"); + LOG_TARGET_ERROR(target, "BUG: called for a non-ARMv7A target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); if (armv7a->is_armv7r) { - LOG_USER("D-Cache: %s, I-Cache: %s", - state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); + LOG_TARGET_USER(target, "D-Cache: %s, I-Cache: %s", + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled)); } else { - LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[armv7a->armv7a_mmu.mmu_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], - state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); + LOG_TARGET_USER(target, "MMU: %s, D-Cache: %s, I-Cache: %s", + str_enabled_disabled(armv7a->armv7a_mmu.mmu_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled), + str_enabled_disabled(armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled)); } if (arm->core_mode == ARM_MODE_ABT) @@ -561,33 +508,7 @@ int armv7a_arch_state(struct target *target) return ERROR_OK; } -static const struct command_registration l2_cache_commands[] = { - { - .name = "l2x", - .handler = handle_cache_l2x, - .mode = COMMAND_EXEC, - .help = "configure l2x cache", - .usage = "[base_addr] [number_of_way]", - }, - COMMAND_REGISTRATION_DONE - -}; - -static const struct command_registration l2x_cache_command_handlers[] = { - { - .name = "cache_config", - .mode = COMMAND_EXEC, - .help = "cache configuration for a target", - .usage = "", - .chain = l2_cache_commands, - }, - COMMAND_REGISTRATION_DONE -}; - const struct command_registration armv7a_command_handlers[] = { - { - .chain = l2x_cache_command_handlers, - }, { .chain = arm7a_cache_command_handlers, }, diff --git a/src/target/armv7a.h b/src/target/armv7a.h index 8943f1c697..ae2ccbe2a6 100644 --- a/src/target/armv7a.h +++ b/src/target/armv7a.h @@ -58,21 +58,21 @@ struct armv7a_arch_cache { /* common cache information */ struct armv7a_cache_common { - int info; /* -1 invalid, else valid */ + bool info_valid; int loc; /* level of coherency */ uint32_t dminline; /* minimum d-cache linelen */ uint32_t iminline; /* minimum i-cache linelen */ struct armv7a_arch_cache arch[6]; /* cache info, L1 - L7 */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; /* outer unified cache if some */ - void *outer_cache; + struct armv7a_l2x_cache *outer_cache; int (*flush_all_data_cache)(struct target *target); }; struct armv7a_mmu_common { /* following field mmu working way */ - int32_t cached; /* 0: not initialized, 1: initialized */ + bool cached; uint32_t ttbcr; /* cache for ttbcr register */ uint32_t ttbr[2]; uint32_t ttbr_mask[2]; @@ -81,7 +81,7 @@ struct armv7a_mmu_common { int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv7a_cache_common armv7a_cache; - uint32_t mmu_enabled; + bool mmu_enabled; }; struct armv7a_common { diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index f2f1097c5a..5eb31d8c08 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -151,9 +151,8 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -185,8 +184,7 @@ int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, } while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); @@ -215,9 +213,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -229,8 +226,7 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCCMVAC - Data Cache Clean by MVA to PoC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 10, 1), va_line); @@ -259,9 +255,8 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_d_cache_sanity_check(target); + int retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -273,8 +268,7 @@ int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); @@ -341,9 +335,8 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->iminline; uint32_t va_line, va_end; - int retval, i = 0; - retval = armv7a_l1_i_cache_sanity_check(target); + int retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; @@ -355,8 +348,7 @@ int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, va_end = virt + size; while (va_line < va_end) { - if ((i++ & 0x3f) == 0) - keep_alive(); + keep_alive(); /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); diff --git a/src/target/armv7a_cache_l2x.c b/src/target/armv7a_cache_l2x.c index 39c503f096..bdcf8cbbee 100644 --- a/src/target/armv7a_cache_l2x.c +++ b/src/target/armv7a_cache_l2x.c @@ -21,8 +21,8 @@ static int arm7a_l2x_sanity_check(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a->armv7a_mmu.armv7a_cache.outer_cache); + struct armv7a_l2x_cache *l2x_cache = + armv7a->armv7a_mmu.armv7a_cache.outer_cache; if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); @@ -42,8 +42,8 @@ static int arm7a_l2x_sanity_check(struct target *target) int arm7a_l2x_flush_all_data(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a->armv7a_mmu.armv7a_cache.outer_cache); + struct armv7a_l2x_cache *l2x_cache = + armv7a->armv7a_mmu.armv7a_cache.outer_cache; uint32_t l2_way_val; int retval; @@ -62,8 +62,8 @@ int armv7a_l2x_cache_flush_virt(struct target *target, target_addr_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a->armv7a_mmu.armv7a_cache.outer_cache); + struct armv7a_l2x_cache *l2x_cache = + armv7a->armv7a_mmu.armv7a_cache.outer_cache; /* FIXME: different controllers have different linelen? */ uint32_t i, linelen = 32; int retval; @@ -97,8 +97,8 @@ static int armv7a_l2x_cache_inval_virt(struct target *target, target_addr_t virt uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a->armv7a_mmu.armv7a_cache.outer_cache); + struct armv7a_l2x_cache *l2x_cache = + armv7a->armv7a_mmu.armv7a_cache.outer_cache; /* FIXME: different controllers have different linelen */ uint32_t i, linelen = 32; int retval; @@ -132,8 +132,8 @@ static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a->armv7a_mmu.armv7a_cache.outer_cache); + struct armv7a_l2x_cache *l2x_cache = + armv7a->armv7a_mmu.armv7a_cache.outer_cache; /* FIXME: different controllers have different linelen */ uint32_t i, linelen = 32; int retval; @@ -166,10 +166,9 @@ static int armv7a_l2x_cache_clean_virt(struct target *target, target_addr_t virt static int arm7a_handle_l2x_cache_info_command(struct command_invocation *cmd, struct armv7a_cache_common *armv7a_cache) { - struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) - (armv7a_cache->outer_cache); + struct armv7a_l2x_cache *l2x_cache = armv7a_cache->outer_cache; - if (armv7a_cache->info == -1) { + if (!armv7a_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index 43b5dae8ef..371e646586 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -73,40 +73,40 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, NS == 1 ? "not" : "", SS == 0 ? "not" : ""); switch (OUTER) { - case 0: - LOG_INFO("outer: Non-Cacheable"); - break; - case 1: - LOG_INFO("outer: Write-Back, Write-Allocate"); - break; - case 2: - LOG_INFO("outer: Write-Through, No Write-Allocate"); - break; - case 3: - LOG_INFO("outer: Write-Back, no Write-Allocate"); - break; + case 0: + LOG_INFO("outer: Non-Cacheable"); + break; + case 1: + LOG_INFO("outer: Write-Back, Write-Allocate"); + break; + case 2: + LOG_INFO("outer: Write-Through, No Write-Allocate"); + break; + case 3: + LOG_INFO("outer: Write-Back, no Write-Allocate"); + break; } switch (INNER) { - case 0: - LOG_INFO("inner: Non-Cacheable"); - break; - case 1: - LOG_INFO("inner: Strongly-ordered"); - break; - case 3: - LOG_INFO("inner: Device"); - break; - case 5: - LOG_INFO("inner: Write-Back, Write-Allocate"); - break; - case 6: - LOG_INFO("inner: Write-Through"); - break; - case 7: - LOG_INFO("inner: Write-Back, no Write-Allocate"); - break; - default: - LOG_INFO("inner: %" PRIx32 " ???", INNER); + case 0: + LOG_INFO("inner: Non-Cacheable"); + break; + case 1: + LOG_INFO("inner: Strongly-ordered"); + break; + case 3: + LOG_INFO("inner: Device"); + break; + case 5: + LOG_INFO("inner: Write-Back, Write-Allocate"); + break; + case 6: + LOG_INFO("inner: Write-Through"); + break; + case 7: + LOG_INFO("inner: Write-Back, no Write-Allocate"); + break; + default: + LOG_INFO("inner: %" PRIx32 " ???", INNER); } } @@ -214,7 +214,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) max_pt_idx -= 1; } } else { - if (mmu->cached != 1) { + if (!mmu->cached) { LOG_ERROR("TTB not cached!"); return ERROR_FAIL; } diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 86c45f7f26..942e22584d 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -15,6 +15,7 @@ #define OPENOCD_TARGET_ARMV7M_H #include "arm.h" +#include "armv7m_cache.h" #include "armv7m_trace.h" struct adiv5_ap; @@ -239,6 +240,8 @@ struct armv7m_common { /* hla_target uses a high level adapter that does not support all functions */ bool is_hla_target; + struct armv7m_cache_common armv7m_cache; + struct armv7m_trace_config trace_config; /* Direct processor core register read and writes */ diff --git a/src/target/armv7m_cache.c b/src/target/armv7m_cache.c new file mode 100644 index 0000000000..cc0c9d1404 --- /dev/null +++ b/src/target/armv7m_cache.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2025 by STMicroelectronics + * Copyright (C) 2025 by Antonio Borneo + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int get_cache_info(struct adiv5_ap *ap, unsigned int cl, + unsigned int ind, uint32_t *ccsidr) +{ + uint32_t csselr = FIELD_PREP(CSSELR_LEVEL_MASK, cl) + | FIELD_PREP(CSSELR_IND_MASK, ind); + + int retval = mem_ap_write_u32(ap, CSSELR, csselr); + if (retval != ERROR_OK) + return retval; + + return mem_ap_read_u32(ap, CCSIDR, ccsidr); +} + +static int get_d_u_cache_info(struct adiv5_ap *ap, unsigned int cl, + uint32_t *ccsidr) +{ + return get_cache_info(ap, cl, CSSELR_IND_DATA_OR_UNIFIED_CACHE, ccsidr); +} + +static int get_i_cache_info(struct adiv5_ap *ap, unsigned int cl, + uint32_t *ccsidr) +{ + return get_cache_info(ap, cl, CSSELR_IND_INSTRUCTION_CACHE, ccsidr); +} + +static struct armv7m_cache_size decode_ccsidr(uint32_t ccsidr) +{ + struct armv7m_cache_size size; + + size.line_len = 16 << FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr); + size.associativity = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr) + 1; + size.num_sets = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr) + 1; + size.cache_size = size.line_len * size.associativity * size.num_sets / 1024; + + // compute info for set way operation on cache + size.index_shift = FIELD_GET(CCSIDR_LINESIZE_MASK, ccsidr) + 2; + size.index = FIELD_GET(CCSIDR_NUMSETS_MASK, ccsidr); + size.way = FIELD_GET(CCSIDR_ASSOCIATIVITY_MASK, ccsidr); + + unsigned int i = 0; + while (((size.way << i) & 0x80000000) == 0) + i++; + size.way_shift = i; + + return size; +} + +int armv7m_identify_cache(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + uint32_t clidr; + int retval = mem_ap_read_u32(armv7m->debug_ap, CLIDR, &clidr); + if (retval != ERROR_OK) + return retval; + + uint32_t ctr; + retval = mem_ap_read_u32(armv7m->debug_ap, CTR, &ctr); + if (retval != ERROR_OK) + return retval; + + // retrieve selected cache for later restore + uint32_t csselr; + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, CSSELR, &csselr); + if (retval != ERROR_OK) + return retval; + + if (clidr == 0) { + LOG_TARGET_DEBUG(target, "No cache detected"); + return ERROR_OK; + } + + if (FIELD_GET(CTR_FORMAT_MASK, ctr) != CTR_FORMAT_PROVIDED) { + LOG_ERROR("Wrong value in CTR register"); + return ERROR_FAIL; + } + + cache->i_min_line_len = 4UL << FIELD_GET(CTR_IMINLINE_MASK, ctr); + cache->d_min_line_len = 4UL << FIELD_GET(CTR_DMINLINE_MASK, ctr); + LOG_TARGET_DEBUG(target, + "ctr=0x%" PRIx32 " ctr.i_min_line_len=%" PRIu32 " ctr.d_min_line_len=%" PRIu32, + ctr, cache->i_min_line_len, cache->d_min_line_len); + + cache->loc = FIELD_GET(CLIDR_LOC_MASK, clidr); + LOG_TARGET_DEBUG(target, + "clidr=0x%" PRIx32 " Number of cache levels to PoC=%" PRIu32, + clidr, cache->loc); + + // retrieve all available inner caches + uint32_t d_u_ccsidr[8] = {0}, i_ccsidr[8] = {0}; + for (unsigned int cl = 0; cl < cache->loc; cl++) { + unsigned int ctype = FIELD_GET(CLIDR_CTYPE_MASK(cl + 1), clidr); + + // skip reserved values + if (ctype > CLIDR_CTYPE_UNIFIED_CACHE) + continue; + + cache->arch[cl].ctype = ctype; + + // separate d or unified d/i cache at this level ? + if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) { + // retrieve d-cache info + retval = get_d_u_cache_info(armv7m->debug_ap, cl, &d_u_ccsidr[cl]); + if (retval != ERROR_OK) + break; + } + + if (ctype & CLIDR_CTYPE_I_CACHE) { + // retrieve i-cache info + retval = get_i_cache_info(armv7m->debug_ap, cl, &i_ccsidr[cl]); + if (retval != ERROR_OK) + break; + } + } + + // restore selected cache + int retval1 = mem_ap_write_atomic_u32(armv7m->debug_ap, CSSELR, csselr); + + if (retval != ERROR_OK) + return retval; + if (retval1 != ERROR_OK) + return retval1; + + for (unsigned int cl = 0; cl < cache->loc; cl++) { + unsigned int ctype = cache->arch[cl].ctype; + + // separate d or unified d/i cache at this level ? + if (ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) { + cache->has_d_u_cache = true; + cache->arch[cl].d_u_size = decode_ccsidr(d_u_ccsidr[cl]); + + LOG_TARGET_DEBUG(target, + "data/unified cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + cache->arch[cl].d_u_size.index, + cache->arch[cl].d_u_size.index_shift, + cache->arch[cl].d_u_size.way, + cache->arch[cl].d_u_size.way_shift); + + LOG_TARGET_DEBUG(target, + "cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + cache->arch[cl].d_u_size.line_len, + cache->arch[cl].d_u_size.cache_size, + cache->arch[cl].d_u_size.associativity); + } + + if (ctype & CLIDR_CTYPE_I_CACHE) { + cache->has_i_cache = true; + cache->arch[cl].i_size = decode_ccsidr(i_ccsidr[cl]); + + LOG_TARGET_DEBUG(target, + "instruction cache index %" PRIu32 " << %" PRIu32 ", way %" PRIu32 " << %" PRIu32, + cache->arch[cl].i_size.index, + cache->arch[cl].i_size.index_shift, + cache->arch[cl].i_size.way, + cache->arch[cl].i_size.way_shift); + + LOG_TARGET_DEBUG(target, + "cache line %" PRIu32 " bytes %" PRIu32 " KBytes asso %" PRIu32 " ways", + cache->arch[cl].i_size.line_len, + cache->arch[cl].i_size.cache_size, + cache->arch[cl].i_size.associativity); + } + } + + cache->info_valid = true; + + return ERROR_OK; +} + +int armv7m_d_cache_flush(struct target *target, uint32_t address, + unsigned int length) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!cache->info_valid || !cache->has_d_u_cache) + return ERROR_OK; + + uint32_t line_len = cache->d_min_line_len; + uint32_t addr_line = ALIGN_DOWN(address, line_len); + uint32_t addr_end = address + length; + + while (addr_line < addr_end) { + int retval = mem_ap_write_u32(armv7m->debug_ap, DCCIMVAC, addr_line); + if (retval != ERROR_OK) + return retval; + addr_line += line_len; + keep_alive(); + } + + return dap_run(armv7m->debug_ap->dap); +} + +int armv7m_i_cache_inval(struct target *target, uint32_t address, + unsigned int length) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!cache->info_valid || !cache->has_i_cache) + return ERROR_OK; + + uint32_t line_len = cache->i_min_line_len; + uint32_t addr_line = ALIGN_DOWN(address, line_len); + uint32_t addr_end = address + length; + + while (addr_line < addr_end) { + int retval = mem_ap_write_u32(armv7m->debug_ap, ICIMVAU, addr_line); + if (retval != ERROR_OK) + return retval; + addr_line += line_len; + keep_alive(); + } + + return dap_run(armv7m->debug_ap->dap); +} + +int armv7m_handle_cache_info_command(struct command_invocation *cmd, + struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_cache_common *cache = &armv7m->armv7m_cache; + + if (!target_was_examined(target)) { + command_print(cmd, "Target not examined yet"); + return ERROR_FAIL; + } + + if (!cache->info_valid) { + command_print(cmd, "No cache detected"); + return ERROR_OK; + } + + for (unsigned int cl = 0; cl < cache->loc; cl++) { + struct armv7m_arch_cache *arch = &cache->arch[cl]; + + if (arch->ctype & CLIDR_CTYPE_I_CACHE) + command_print(cmd, + "L%d I-Cache: line length %" PRIu32 ", associativity %" PRIu32 + ", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes", + cl + 1, + arch->i_size.line_len, + arch->i_size.associativity, + arch->i_size.num_sets, + arch->i_size.cache_size); + + if (arch->ctype & (CLIDR_CTYPE_UNIFIED_CACHE | CLIDR_CTYPE_D_CACHE)) + command_print(cmd, + "L%d %c-Cache: line length %" PRIu32 ", associativity %" PRIu32 + ", num sets %" PRIu32 ", cache size %" PRIu32 " KBytes", + cl + 1, + (arch->ctype & CLIDR_CTYPE_D_CACHE) ? 'D' : 'U', + arch->d_u_size.line_len, + arch->d_u_size.associativity, + arch->d_u_size.num_sets, + arch->d_u_size.cache_size); + } + + return ERROR_OK; +} diff --git a/src/target/armv7m_cache.h b/src/target/armv7m_cache.h new file mode 100644 index 0000000000..576bff8d6b --- /dev/null +++ b/src/target/armv7m_cache.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2025 by STMicroelectronics + * Copyright (C) 2025 by Antonio Borneo + */ + +#ifndef OPENOCD_TARGET_ARMV7M_CACHE_H +#define OPENOCD_TARGET_ARMV7M_CACHE_H + +#include +#include + +#include + +struct target; + +struct armv7m_cache_size { + // cache dimensioning + uint32_t line_len; + uint32_t associativity; + uint32_t num_sets; + uint32_t cache_size; + // info for set way operation on cache + uint32_t index; + uint32_t index_shift; + uint32_t way; + uint32_t way_shift; +}; + +// information about one architecture cache at any level +struct armv7m_arch_cache { + unsigned int ctype; // cache type, CLIDR encoding + struct armv7m_cache_size d_u_size; // data cache + struct armv7m_cache_size i_size; // instruction cache +}; + +// common cache information +struct armv7m_cache_common { + bool info_valid; + bool has_i_cache; + bool has_d_u_cache; + unsigned int loc; // level of coherency + uint32_t d_min_line_len; // minimum d-cache line_len + uint32_t i_min_line_len; // minimum i-cache line_len + struct armv7m_arch_cache arch[6]; // cache info, L1 - L7 +}; + +int armv7m_identify_cache(struct target *target); +int armv7m_d_cache_flush(struct target *target, uint32_t address, + unsigned int length); +int armv7m_i_cache_inval(struct target *target, uint32_t address, + unsigned int length); +int armv7m_handle_cache_info_command(struct command_invocation *cmd, + struct target *target); + +#endif /* OPENOCD_TARGET_ARMV7M_CACHE_H */ diff --git a/src/target/armv8.c b/src/target/armv8.c index 40390731e8..47a380c9d5 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -18,6 +18,7 @@ #include "register.h" #include +#include #include #include @@ -119,27 +120,27 @@ static uint8_t armv8_pa_size(uint32_t ps) { uint8_t ret = 0; switch (ps) { - case 0: - ret = 32; - break; - case 1: - ret = 36; - break; - case 2: - ret = 40; - break; - case 3: - ret = 42; - break; - case 4: - ret = 44; - break; - case 5: - ret = 48; - break; - default: - LOG_INFO("Unknown physical address size"); - break; + case 0: + ret = 32; + break; + case 1: + ret = 36; + break; + case 2: + ret = 40; + break; + case 3: + ret = 42; + break; + case 4: + ret = 44; + break; + case 5: + ret = 48; + break; + default: + LOG_INFO("Unknown physical address size"); + break; } return ret; } @@ -883,12 +884,27 @@ int armv8_read_mpidr(struct armv8_common *armv8) int retval = ERROR_FAIL; struct arm *arm = &armv8->arm; struct arm_dpm *dpm = armv8->arm.dpm; - uint32_t mpidr; + uint64_t mpidr; + uint8_t multi_processor_system; + uint8_t aff3; + uint8_t aff2; + uint8_t aff1; + uint8_t aff0; + uint8_t mt; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; + /* + * TODO: BUG - routine armv8_dpm_modeswitch() doesn't re-evaluate 'arm->dpm->core_state'. + * If the core is halted in EL0 AArch32 while EL1 is in AArch64, the modeswitch moves the core + * to EL1, but there is no re-evaluation of dpm->arm->core_state. As a result, while the core + * is in AArch64, the code considers the system still in AArch32. The read of MPIDR would + * select the instruction based on the old core_state. The call to 'armv8_dpm_get_core_state()' + * below could also potentially return the incorrect execution state for the current EL. + */ + /* check if we're in an unprivileged mode */ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) { retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); @@ -896,17 +912,39 @@ int armv8_read_mpidr(struct armv8_common *armv8) return retval; } - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); + retval = dpm->instr_read_data_r0_64(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); if (retval != ERROR_OK) goto done; if (mpidr & 1U<<31) { - armv8->multi_processor_system = (mpidr >> 30) & 1; - armv8->cluster_id = (mpidr >> 8) & 0xf; - armv8->cpu_id = mpidr & 0x3; - LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), - armv8->cluster_id, - armv8->cpu_id, - armv8->multi_processor_system == 0 ? "multi core" : "single core"); + multi_processor_system = (mpidr >> 30) & 1; + aff3 = (mpidr >> 32) & 0xff; + aff2 = (mpidr >> 16) & 0xff; + aff1 = (mpidr >> 8) & 0xff; + aff0 = mpidr & 0xff; + mt = (mpidr >> 24) & 0x1; + if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) { + if (mt) + LOG_INFO("%s socket %" PRIu32 " cluster %" PRIu32 " core %" PRIu32 " thread %" PRIu32 " %s", + target_name(armv8->arm.target), + aff3, aff2, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + else + LOG_INFO("%s socket %" PRIu32 " cluster %" PRIu32 " core %" PRIu32 " %s", + target_name(armv8->arm.target), + aff3, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + } else { + if (mt) + LOG_INFO("%s cluster %" PRIu32 " core %" PRIu32 " thread %" PRIu32 " %s", + target_name(armv8->arm.target), + aff2, aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + else + LOG_INFO("%s cluster %" PRIu32 " core %" PRIu32 " %s", + target_name(armv8->arm.target), + aff1, aff0, + multi_processor_system == 0 ? "multi core" : "single core"); + } } else LOG_ERROR("mpidr not in multiprocessor format"); @@ -1032,18 +1070,18 @@ static void armv8_decode_cacheability(int attr) return; } switch (attr & 0xC) { - case 0: - LOG_USER_N("Write-Through Transient"); - break; - case 0x4: - LOG_USER_N("Write-Back Transient"); - break; - case 0x8: - LOG_USER_N("Write-Through Non-transient"); - break; - case 0xC: - LOG_USER_N("Write-Back Non-transient"); - break; + case 0: + LOG_USER_N("Write-Through Transient"); + break; + case 0x4: + LOG_USER_N("Write-Back Transient"); + break; + case 0x8: + LOG_USER_N("Write-Through Non-transient"); + break; + case 0xC: + LOG_USER_N("Write-Back Non-transient"); + break; } if (attr & 2) LOG_USER_N(" Read-Allocate"); @@ -1070,18 +1108,18 @@ static void armv8_decode_memory_attr(int attr) "Non-transient"); } else if ((attr & 0xF0) == 0) { switch (attr & 0xC) { - case 0: - LOG_USER_N("Device-nGnRnE Memory"); - break; - case 0x4: - LOG_USER_N("Device-nGnRE Memory"); - break; - case 0x8: - LOG_USER_N("Device-nGRE Memory"); - break; - case 0xC: - LOG_USER_N("Device-GRE Memory"); - break; + case 0: + LOG_USER_N("Device-nGnRnE Memory"); + break; + case 0x4: + LOG_USER_N("Device-nGnRE Memory"); + break; + case 0x8: + LOG_USER_N("Device-nGRE Memory"); + break; + case 0xC: + LOG_USER_N("Device-GRE Memory"); + break; } if (attr & 1) LOG_USER(", XS=0"); @@ -1265,7 +1303,7 @@ COMMAND_HANDLER(armv8_pauth_command) int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache) { - if (armv8_cache->info == -1) { + if (!armv8_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -1292,7 +1330,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) armv8->common_magic = ARMV8_COMMON_MAGIC; armv8->armv8_mmu.armv8_cache.l2_cache = NULL; - armv8->armv8_mmu.armv8_cache.info = -1; + armv8->armv8_mmu.armv8_cache.info_valid = false; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; armv8->armv8_mmu.armv8_cache.display_cache_info = NULL; return ERROR_OK; @@ -1322,10 +1360,6 @@ static int armv8_aarch64_state(struct target *target) int armv8_arch_state(struct target *target) { - static const char * const state[] = { - "disabled", "enabled" - }; - struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; @@ -1340,9 +1374,9 @@ int armv8_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", - state[armv8->armv8_mmu.mmu_enabled], - state[armv8->armv8_mmu.armv8_cache.d_u_cache_enabled], - state[armv8->armv8_mmu.armv8_cache.i_cache_enabled]); + str_enabled_disabled(armv8->armv8_mmu.mmu_enabled), + str_enabled_disabled(armv8->armv8_mmu.armv8_cache.d_u_cache_enabled), + str_enabled_disabled(armv8->armv8_mmu.armv8_cache.i_cache_enabled)); if (arm->core_mode == ARM_MODE_ABT) armv8_show_fault_registers(target); diff --git a/src/target/armv8.h b/src/target/armv8.h index dba12f9666..5bc1719df7 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -151,13 +151,13 @@ struct armv8_arch_cache { }; struct armv8_cache_common { - int info; + bool info_valid; int loc; uint32_t iminline; uint32_t dminline; struct armv8_arch_cache arch[6]; /* cache info, L1 - L7 */ - int i_cache_enabled; - int d_u_cache_enabled; + bool i_cache_enabled; + bool d_u_cache_enabled; /* l2 external unified cache if some */ void *l2_cache; @@ -179,7 +179,7 @@ struct armv8_mmu_common { int (*read_physical_memory)(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv8_cache_common armv8_cache; - uint32_t mmu_enabled; + bool mmu_enabled; }; struct armv8_common { @@ -195,11 +195,6 @@ struct armv8_common { const uint32_t *opcodes; - /* mdir */ - uint8_t multi_processor_system; - uint8_t cluster_id; - uint8_t cpu_id; - /* armv8 aarch64 need below information for page translation */ uint8_t va_size; uint8_t pa_size; diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 1c251beb99..7bf4dcd47b 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -214,7 +214,7 @@ static int armv8_handle_inner_cache_info_command(struct command_invocation *cmd, { int cl; - if (armv8_cache->info == -1) { + if (!armv8_cache->info_valid) { command_print(cmd, "cache not yet identified"); return ERROR_OK; } @@ -262,7 +262,7 @@ static int armv8_flush_all_data(struct target *target) int retval = ERROR_FAIL; /* check that armv8_cache is correctly identify */ struct armv8_common *armv8 = target_to_armv8(target); - if (armv8->armv8_mmu.armv8_cache.info == -1) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { LOG_ERROR("trying to flush un-identified cache"); return retval; } @@ -288,7 +288,7 @@ static int armv8_flush_all_instruction(struct target *target) int retval = ERROR_FAIL; /* check that armv8_cache is correctly identify */ struct armv8_common *armv8 = target_to_armv8(target); - if (armv8->armv8_mmu.armv8_cache.info == -1) { + if (!armv8->armv8_mmu.armv8_cache.info_valid) { LOG_ERROR("trying to flush un-identified cache"); return retval; } @@ -459,7 +459,7 @@ int armv8_identify_cache(struct armv8_common *armv8) if (retval != ERROR_OK) goto done; - armv8->armv8_mmu.armv8_cache.info = 1; + armv8->armv8_mmu.armv8_cache.info_valid = true; /* if no l2 cache initialize l1 data cache flush function function */ if (!armv8->armv8_mmu.armv8_cache.flush_all_data_cache) { diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index d1cee8a10c..508ec973e3 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -426,17 +426,17 @@ static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, int retval; switch (index_t) { - case 0 ... 15: /* breakpoints */ - vr += CPUV8_DBG_BVR_BASE; - cr += CPUV8_DBG_BCR_BASE; - break; - case 16 ... 31: /* watchpoints */ - vr += CPUV8_DBG_WVR_BASE; - cr += CPUV8_DBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: /* breakpoints */ + vr += CPUV8_DBG_BVR_BASE; + cr += CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: /* watchpoints */ + vr += CPUV8_DBG_WVR_BASE; + cr += CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } vr += 16 * index_t; cr += 16 * index_t; @@ -456,15 +456,15 @@ static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) uint32_t cr; switch (index_t) { - case 0 ... 15: - cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; - break; - case 16 ... 31: - cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + cr = armv8->debug_base + CPUV8_DBG_BCR_BASE; + break; + case 16 ... 31: + cr = armv8->debug_base + CPUV8_DBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } cr += 16 * index_t; @@ -542,6 +542,8 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) unsigned int target_el; enum arm_state core_state; uint32_t cpsr; + uint32_t rw = (dpm->dscr >> 10) & 0xF; + uint32_t ns = (dpm->dscr >> 18) & 0x1; /* restore previous mode */ if (mode == ARM_MODE_ANY) { @@ -564,7 +566,11 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) case ARM_MODE_IRQ: case ARM_MODE_FIQ: case ARM_MODE_SYS: - target_el = 1; + /* For Secure, EL1 if EL3 is aarch64, EL3 if EL3 is aarch32 */ + if (ns || (rw & (1 << 3))) + target_el = 1; + else + target_el = 3; break; /* * TODO: handle ARM_MODE_HYP @@ -598,8 +604,8 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) } else { core_state = armv8_dpm_get_core_state(dpm); if (core_state != ARM_STATE_AARCH64) { - /* cannot do DRPS/ERET when already in EL0 */ - if (dpm->last_el != 0) { + /* cannot do DRPS/ERET when in EL0 or in SYS mode */ + if (dpm->last_el != 0 && dpm->arm->core_mode != ARM_MODE_SYS) { /* load SPSR with the desired mode and execute DRPS */ LOG_DEBUG("SPSR = 0x%08"PRIx32, cpsr); retval = dpm->instr_write_data_r0(dpm, @@ -1121,26 +1127,26 @@ static int dpmv8_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, * v7 hardware, unaligned 4-byte ones too. */ switch (length) { - case 1: - control |= (1 << (addr & 3)) << 5; + case 1: + control |= (1 << (addr & 3)) << 5; + break; + case 2: + /* require 2-byte alignment */ + if (!(addr & 1)) { + control |= (3 << (addr & 2)) << 5; break; - case 2: - /* require 2-byte alignment */ - if (!(addr & 1)) { - control |= (3 << (addr & 2)) << 5; - break; - } - /* FALL THROUGH */ - case 4: - /* require 4-byte alignment */ - if (!(addr & 3)) { - control |= 0xf << 5; - break; - } - /* FALL THROUGH */ - default: - LOG_ERROR("unsupported {break,watch}point length/alignment"); - return ERROR_COMMAND_SYNTAX_ERROR; + } + /* FALL THROUGH */ + case 4: + /* require 4-byte alignment */ + if (!(addr & 3)) { + control |= 0xf << 5; + break; + } + /* FALL THROUGH */ + default: + LOG_ERROR("unsupported {break,watch}point length/alignment"); + return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: @@ -1227,15 +1233,15 @@ static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, control = dwp->bpwp.control; switch (wp->rw) { - case WPT_READ: - control |= 1 << 3; - break; - case WPT_WRITE: - control |= 2 << 3; - break; - case WPT_ACCESS: - control |= 3 << 3; - break; + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; } dwp->bpwp.control = control; @@ -1357,31 +1363,31 @@ void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { - /* FALL THROUGH -- assume a v6 core in abort mode */ - case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ - target->debug_reason = DBG_REASON_DBGRQ; - break; - case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ - case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ - case DSCRV8_ENTRY_HALT_STEP: - target->debug_reason = DBG_REASON_SINGLESTEP; - break; - case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ - case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ - case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ - case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ - case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ - target->debug_reason = DBG_REASON_BREAKPOINT; - break; - case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ - target->debug_reason = DBG_REASON_EXC_CATCH; - break; - default: - target->debug_reason = DBG_REASON_UNDEFINED; - break; + /* FALL THROUGH -- assume a v6 core in abort mode */ + case DSCRV8_ENTRY_EXT_DEBUG: /* EDBGRQ */ + target->debug_reason = DBG_REASON_DBGRQ; + break; + case DSCRV8_ENTRY_HALT_STEP_EXECLU: /* HALT step */ + case DSCRV8_ENTRY_HALT_STEP_NORMAL: /* Halt step*/ + case DSCRV8_ENTRY_HALT_STEP: + target->debug_reason = DBG_REASON_SINGLESTEP; + break; + case DSCRV8_ENTRY_HLT: /* HLT instruction (software breakpoint) */ + case DSCRV8_ENTRY_BKPT: /* SW BKPT (?) */ + case DSCRV8_ENTRY_RESET_CATCH: /* Reset catch */ + case DSCRV8_ENTRY_OS_UNLOCK: /*OS unlock catch*/ + case DSCRV8_ENTRY_SW_ACCESS_DBG: /*SW access dbg register*/ + target->debug_reason = DBG_REASON_BREAKPOINT; + break; + case DSCRV8_ENTRY_WATCHPOINT: /* asynch watchpoint */ + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + case DSCRV8_ENTRY_EXCEPTION_CATCH: /*exception catch*/ + target->debug_reason = DBG_REASON_EXC_CATCH; + break; + default: + target->debug_reason = DBG_REASON_UNDEFINED; + break; } } diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index 94962c2055..a2da146c95 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -117,7 +117,7 @@ static int avr32_write_core_reg(struct target *target, int num) reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32); ap7k->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx32, num, reg_value); ap7k->core_cache->reg_list[num].valid = true; ap7k->core_cache->reg_list[num].dirty = false; @@ -337,7 +337,7 @@ static int avr32_ap7k_resume(struct target *target, bool current, /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR "", breakpoint->address); + LOG_DEBUG("unset breakpoint at 0x%8.8" TARGET_PRIxADDR, breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); @@ -372,11 +372,11 @@ static int avr32_ap7k_resume(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target resumed at 0x%" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -425,7 +425,7 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -443,18 +443,18 @@ static int avr32_ap7k_read_memory(struct target *target, target_addr_t address, return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { - case 4: - return avr32_jtag_read_memory32(&ap7k->jtag, address, count, - (uint32_t *)(void *)buffer); - break; - case 2: - return avr32_jtag_read_memory16(&ap7k->jtag, address, count, - (uint16_t *)(void *)buffer); - break; - case 1: - return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); - default: - break; + case 4: + return avr32_jtag_read_memory32(&ap7k->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return avr32_jtag_read_memory16(&ap7k->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); + default: + break; } return ERROR_OK; @@ -465,7 +465,7 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); @@ -483,18 +483,18 @@ static int avr32_ap7k_write_memory(struct target *target, target_addr_t address, return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { - case 4: - return avr32_jtag_write_memory32(&ap7k->jtag, address, count, - (uint32_t *)(void *)buffer); - break; - case 2: - return avr32_jtag_write_memory16(&ap7k->jtag, address, count, - (uint16_t *)(void *)buffer); - break; - case 1: - return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); - default: - break; + case 4: + return avr32_jtag_write_memory32(&ap7k->jtag, address, count, + (uint32_t *)(void *)buffer); + break; + case 2: + return avr32_jtag_write_memory16(&ap7k->jtag, address, count, + (uint16_t *)(void *)buffer); + break; + case 1: + return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); + default: + break; } return ERROR_OK; @@ -548,7 +548,7 @@ static int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); - LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32, debug_reason_name(target), ap7k->jtag.dpc); return ERROR_OK; diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 0e9ae6e3ae..97b44e7c10 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -73,22 +73,22 @@ static int breakpoint_add_internal(struct target *target, retval = target_add_breakpoint(target, *breakpoint_p); switch (retval) { - case ERROR_OK: - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - reason = "resource not available"; - goto fail; - case ERROR_TARGET_NOT_HALTED: - reason = "target not halted"; - goto fail; - default: - reason = "unknown reason"; + case ERROR_OK: + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + reason = "resource not available"; + goto fail; + case ERROR_TARGET_NOT_HALTED: + reason = "target not halted"; + goto fail; + default: + reason = "unknown reason"; fail: - LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason); - free((*breakpoint_p)->orig_instr); - free(*breakpoint_p); - *breakpoint_p = NULL; - return retval; + LOG_TARGET_ERROR(target, "can't add breakpoint: %s", reason); + free((*breakpoint_p)->orig_instr); + free(*breakpoint_p); + *breakpoint_p = NULL; + return retval; } LOG_TARGET_DEBUG(target, "added %s breakpoint at " TARGET_ADDR_FMT @@ -453,6 +453,8 @@ static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_ static int watchpoint_remove_all_internal(struct target *target) { + LOG_TARGET_DEBUG(target, "Delete all watchpoints"); + struct watchpoint *watchpoint = target->watchpoints; int retval = ERROR_OK; @@ -506,27 +508,6 @@ int watchpoint_remove_all(struct target *target) return breakpoint_watchpoint_remove_all(target, WATCHPOINT); } -int breakpoint_clear_target(struct target *target) -{ - int retval = ERROR_OK; - - if (target->smp) { - struct target_list *head; - - foreach_smp_target(head, target->smp_targets) { - struct target *curr = head->target; - int status = breakpoint_remove_all_internal(curr); - - if (status != ERROR_OK) - retval = status; - } - } else { - retval = breakpoint_remove_all_internal(target); - } - - return retval; -} - struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) { struct breakpoint *breakpoint = target->breakpoints; @@ -578,23 +559,23 @@ static int watchpoint_add_internal(struct target *target, target_addr_t address, retval = target_add_watchpoint(target, *watchpoint_p); switch (retval) { - case ERROR_OK: - break; - case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: - reason = "resource not available"; - goto bye; - case ERROR_TARGET_NOT_HALTED: - reason = "target not halted"; - goto bye; - default: - reason = "unrecognized error"; + case ERROR_OK: + break; + case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: + reason = "resource not available"; + goto bye; + case ERROR_TARGET_NOT_HALTED: + reason = "target not halted"; + goto bye; + default: + reason = "unrecognized error"; bye: - LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", - watchpoint_rw_strings[(*watchpoint_p)->rw], - address, reason); - free(*watchpoint_p); - *watchpoint_p = NULL; - return retval; + LOG_TARGET_ERROR(target, "can't add %s watchpoint at " TARGET_ADDR_FMT ", %s", + watchpoint_rw_strings[(*watchpoint_p)->rw], + address, reason); + free(*watchpoint_p); + *watchpoint_p = NULL; + return retval; } LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT @@ -685,23 +666,6 @@ int watchpoint_remove(struct target *target, target_addr_t address) return retval; } -int watchpoint_clear_target(struct target *target) -{ - LOG_TARGET_DEBUG(target, "Delete all watchpoints"); - - struct watchpoint *watchpoint = target->watchpoints; - int retval = ERROR_OK; - - while (watchpoint) { - struct watchpoint *tmp = watchpoint; - watchpoint = watchpoint->next; - int status = watchpoint_free(target, tmp); - if (status != ERROR_OK) - retval = status; - } - return retval; -} - int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, target_addr_t *address) { diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index ac5d7016d2..89572ffc5d 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -50,7 +50,6 @@ struct watchpoint { uint32_t unique_id; }; -int breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, target_addr_t address, unsigned int length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, @@ -69,7 +68,6 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int breakpoint->number = hw_number; } -int watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index ee27e1b217..bc7550509c 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -68,8 +68,8 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, uint32_t value, uint32_t *dscr); -static int cortex_a_mmu(struct target *target, int *enabled); -static int cortex_a_mmu_modify(struct target *target, int enable); +static int cortex_a_mmu(struct target *target, bool *enabled); +static int cortex_a_mmu_modify(struct target *target, bool enable); static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys); static int cortex_a_read_cpu_memory(struct target *target, @@ -109,17 +109,17 @@ static int cortex_a_restore_cp15_control_reg(struct target *target) * If !phys_access, switch to SVC mode and make sure MMU is on * If phys_access, switch off mmu */ -static int cortex_a_prep_memaccess(struct target *target, int phys_access) +static int cortex_a_prep_memaccess(struct target *target, bool phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - int mmu_enabled = 0; + bool mmu_enabled = false; - if (phys_access == 0) { + if (!phys_access) { arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 1); + cortex_a_mmu_modify(target, true); if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* overwrite DACR to all-manager */ armv7a->arm.mcr(target, 15, @@ -129,7 +129,7 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) } else { cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 0); + cortex_a_mmu_modify(target, false); } return ERROR_OK; } @@ -139,12 +139,12 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) * If !phys_access, switch to previous mode * If phys_access, restore MMU setting */ -static int cortex_a_post_memaccess(struct target *target, int phys_access) +static int cortex_a_post_memaccess(struct target *target, bool phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - if (phys_access == 0) { + if (!phys_access) { if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { /* restore */ armv7a->arm.mcr(target, 15, @@ -153,10 +153,10 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) } arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); } else { - int mmu_enabled = 0; + bool mmu_enabled = false; cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) - cortex_a_mmu_modify(target, 1); + cortex_a_mmu_modify(target, true); } return ERROR_OK; } @@ -165,12 +165,12 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) /* modify cp15_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ -static int cortex_a_mmu_modify(struct target *target, int enable) +static int cortex_a_mmu_modify(struct target *target, bool enable) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); int retval = ERROR_OK; - int need_write = 0; + bool need_write = false; if (enable) { /* if mmu enabled at target stop and mmu not enable */ @@ -180,12 +180,12 @@ static int cortex_a_mmu_modify(struct target *target, int enable) } if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0) { cortex_a->cp15_control_reg_curr |= 0x1U; - need_write = 1; + need_write = true; } } else { if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0x1U) { cortex_a->cp15_control_reg_curr &= ~0x1U; - need_write = 1; + need_write = true; } } @@ -580,17 +580,17 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, int retval; switch (index_t) { - case 0 ... 15: /* breakpoints */ - vr += CPUDBG_BVR_BASE; - cr += CPUDBG_BCR_BASE; - break; - case 16 ... 31: /* watchpoints */ - vr += CPUDBG_WVR_BASE; - cr += CPUDBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: /* breakpoints */ + vr += CPUDBG_BVR_BASE; + cr += CPUDBG_BCR_BASE; + break; + case 16 ... 31: /* watchpoints */ + vr += CPUDBG_WVR_BASE; + cr += CPUDBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } vr += 4 * index_t; cr += 4 * index_t; @@ -612,15 +612,15 @@ static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) uint32_t cr; switch (index_t) { - case 0 ... 15: - cr = a->armv7a_common.debug_base + CPUDBG_BCR_BASE; - break; - case 16 ... 31: - cr = a->armv7a_common.debug_base + CPUDBG_WCR_BASE; - index_t -= 16; - break; - default: - return ERROR_FAIL; + case 0 ... 15: + cr = a->armv7a_common.debug_base + CPUDBG_BCR_BASE; + break; + case 16 ... 31: + cr = a->armv7a_common.debug_base + CPUDBG_WCR_BASE; + index_t -= 16; + break; + default: + return ERROR_FAIL; } cr += 4 * index_t; @@ -860,22 +860,22 @@ static int cortex_a_internal_restore(struct target *target, bool current, * kill the return address */ switch (arm->core_state) { - case ARM_STATE_ARM: - resume_pc &= 0xFFFFFFFC; - break; - case ARM_STATE_THUMB: - case ARM_STATE_THUMB_EE: - /* When the return address is loaded into PC - * bit 0 must be 1 to stay in Thumb state - */ - resume_pc |= 0x1; - break; - case ARM_STATE_JAZELLE: - LOG_ERROR("How do I resume into Jazelle state??"); - return ERROR_FAIL; - case ARM_STATE_AARCH64: - LOG_ERROR("Shouldn't be in AARCH64 state"); - return ERROR_FAIL; + case ARM_STATE_ARM: + resume_pc &= 0xFFFFFFFC; + break; + case ARM_STATE_THUMB: + case ARM_STATE_THUMB_EE: + /* When the return address is loaded into PC + * bit 0 must be 1 to stay in Thumb state + */ + resume_pc |= 0x1; + break; + case ARM_STATE_JAZELLE: + LOG_ERROR("How do I resume into Jazelle state??"); + return ERROR_FAIL; + case ARM_STATE_AARCH64: + LOG_ERROR("Shouldn't be in AARCH64 state"); + return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); @@ -1118,19 +1118,18 @@ static int cortex_a_post_debug_entry(struct target *target) if (!armv7a->is_armv7r) armv7a_read_ttbcr(target); - if (armv7a->armv7a_mmu.armv7a_cache.info == -1) + if (!armv7a->armv7a_mmu.armv7a_cache.info_valid) armv7a_identify_cache(target); if (armv7a->is_armv7r) { - armv7a->armv7a_mmu.mmu_enabled = 0; + armv7a->armv7a_mmu.mmu_enabled = false; } else { - armv7a->armv7a_mmu.mmu_enabled = - (cortex_a->cp15_control_reg & 0x1U) ? 1 : 0; + armv7a->armv7a_mmu.mmu_enabled = cortex_a->cp15_control_reg & 0x1U; } armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled = - (cortex_a->cp15_control_reg & 0x4U) ? 1 : 0; + cortex_a->cp15_control_reg & 0x4U; armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled = - (cortex_a->cp15_control_reg & 0x1000U) ? 1 : 0; + cortex_a->cp15_control_reg & 0x1000U; cortex_a->curr_mode = armv7a->arm.core_mode; /* switch to SVC mode to read DACR */ @@ -1169,6 +1168,29 @@ static int cortex_a_set_dscr_bits(struct target *target, return retval; } +/* + * Single-step on ARMv7a/r is implemented through a HW breakpoint that hits + * every instruction at any address except the address of the current + * instruction. + * Such HW breakpoint is never hit in case of a single instruction that jumps + * on itself (infinite loop), or a WFI or a WFE. In this case, halt the CPU + * after a timeout. + * The jump on itself would be executed several times before the timeout forces + * the halt, but this is not an issue. In ARMv7a/r there are few "pathological" + * instructions, listed below, that jumps on itself and that can have side + * effects if executed more than once; but they are not considered as real use + * cases generated by a compiler. + * Some example: + * - 'pop {pc}' or multi register 'pop' including PC, when the new PC value is + * the same value of current PC. The single step will not stop at the first + * 'pop' and will continue taking values from the stack, modifying SP at each + * iteration. + * - 'rfeda', 'rfedb', 'rfeia', 'rfeib', when the new PC value is the same + * value of current PC. The register provided to the instruction (usually SP) + * will be incremented or decremented at each iteration. + * + * TODO: fix exit in case of error, cleaning HW breakpoints. + */ static int cortex_a_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints) { @@ -1227,15 +1249,34 @@ static int cortex_a_step(struct target *target, bool current, target_addr_t addr if (retval != ERROR_OK) return retval; - int64_t then = timeval_ms(); + // poll at least once before starting the timeout + retval = cortex_a_poll(target); + if (retval != ERROR_OK) + return retval; + + int64_t then = timeval_ms() + 100; while (target->state != TARGET_HALTED) { + if (timeval_ms() > then) + break; + retval = cortex_a_poll(target); if (retval != ERROR_OK) return retval; - if (target->state == TARGET_HALTED) - break; - if (timeval_ms() > then + 1000) { - LOG_ERROR("timeout waiting for target halt"); + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_DEBUG(target, "timeout waiting for target halt, try halt"); + + retval = cortex_a_halt(target); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_poll(target); + if (retval != ERROR_OK) + return retval; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "timeout waiting for target halt"); return ERROR_FAIL; } } @@ -1255,9 +1296,6 @@ static int cortex_a_step(struct target *target, bool current, target_addr_t addr if (breakpoint) cortex_a_set_breakpoint(target, breakpoint, 0); - if (target->state != TARGET_HALTED) - LOG_DEBUG("target stepped"); - return ERROR_OK; } @@ -1341,6 +1379,19 @@ static int cortex_a_set_breakpoint(struct target *target, buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); } + /* + * ARMv7-A/R fetches instructions in little-endian on both LE and BE CPUs. + * But Cortex-R4 and Cortex-R5 big-endian require BE instructions. + * https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness + * https://developer.arm.com/documentation/den0013/d/Porting/Endianness + */ + if ((((cortex_a->cpuid & CPUDBG_CPUID_MASK) == CPUDBG_CPUID_CORTEX_R4) || + ((cortex_a->cpuid & CPUDBG_CPUID_MASK) == CPUDBG_CPUID_CORTEX_R5)) && + target->endianness == TARGET_BIG_ENDIAN) { + // In place swapping is allowed + buf_bswap32(code, code, 4); + } + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, @@ -2299,19 +2350,20 @@ static int cortex_a_write_cpu_memory(struct target *target, } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { - case 1: - case 3: - count *= size; - size = 1; - break; - case 2: - if (size == 4) { - count *= 2; - size = 2; - } - case 0: - default: - break; + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; } retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2616,20 +2668,20 @@ static int cortex_a_read_cpu_memory(struct target *target, } else { /* Use slow path. Adjust size for aligned accesses */ switch (address % 4) { - case 1: - case 3: - count *= size; - size = 1; - break; - case 2: - if (size == 4) { - count *= 2; - size = 2; - } - break; - case 0: - default: - break; + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; } retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } @@ -2719,9 +2771,9 @@ static int cortex_a_read_phys_memory(struct target *target, address, size, count); /* read memory through the CPU */ - cortex_a_prep_memaccess(target, 1); + cortex_a_prep_memaccess(target, true); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 1); + cortex_a_post_memaccess(target, true); return retval; } @@ -2735,9 +2787,9 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address, LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - cortex_a_prep_memaccess(target, 0); + cortex_a_prep_memaccess(target, false); retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 0); + cortex_a_post_memaccess(target, false); return retval; } @@ -2755,9 +2807,9 @@ static int cortex_a_write_phys_memory(struct target *target, address, size, count); /* write memory through the CPU */ - cortex_a_prep_memaccess(target, 1); + cortex_a_prep_memaccess(target, true); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 1); + cortex_a_post_memaccess(target, true); return retval; } @@ -2771,9 +2823,9 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address, LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - cortex_a_prep_memaccess(target, 0); + cortex_a_prep_memaccess(target, false); retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); - cortex_a_post_memaccess(target, 0); + cortex_a_post_memaccess(target, false); return retval; } @@ -3198,7 +3250,7 @@ static void cortex_a_deinit_target(struct target *target) free(cortex_a); } -static int cortex_a_mmu(struct target *target, int *enabled) +static int cortex_a_mmu(struct target *target, bool *enabled) { struct armv7a_common *armv7a = target_to_armv7a(target); @@ -3208,7 +3260,7 @@ static int cortex_a_mmu(struct target *target, int *enabled) } if (armv7a->is_armv7r) - *enabled = 0; + *enabled = false; else *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled; @@ -3219,7 +3271,7 @@ static int cortex_a_virt2phys(struct target *target, target_addr_t virt, target_addr_t *phys) { int retval; - int mmu_enabled = 0; + bool mmu_enabled = false; /* * If the MMU was not enabled at debug entry, there is no @@ -3234,7 +3286,7 @@ static int cortex_a_virt2phys(struct target *target, } /* mmu must be enable in order to get a correct translation */ - retval = cortex_a_mmu_modify(target, 1); + retval = cortex_a_mmu_modify(target, true); if (retval != ERROR_OK) return retval; return armv7a_mmu_translate_va_pa(target, (uint32_t)virt, diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h index 37fba1a885..8e438fd958 100644 --- a/src/target/cortex_a.h +++ b/src/target/cortex_a.h @@ -30,6 +30,9 @@ #define CORTEX_A_MIDR_PARTNUM_SHIFT 4 #define CPUDBG_CPUID 0xD00 +#define CPUDBG_CPUID_MASK 0xff00fff0 +#define CPUDBG_CPUID_CORTEX_R4 0x4100c140 +#define CPUDBG_CPUID_CORTEX_R5 0x4100c150 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C #define CPUDBG_LOCKACCESS 0xFB0 diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index ba9d83d79f..42e9572602 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -21,6 +21,7 @@ #include "jtag/interface.h" #include "breakpoints.h" #include "cortex_m.h" +#include "armv7m_cache.h" #include "target_request.h" #include "target_type.h" #include "arm_adi_v5.h" @@ -30,6 +31,7 @@ #include "arm_semihosting.h" #include "smp.h" #include +#include #include #include @@ -472,22 +474,22 @@ static int cortex_m_set_maskints_for_halt(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); switch (cortex_m->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* interrupts taken at resume, whether for step or run -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> mask now if MASKINTS - * erratum, otherwise only mask before stepping */ - return cortex_m_set_maskints(target, cortex_m->maskints_erratum); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask now if MASKINTS + * erratum, otherwise only mask before stepping */ + return cortex_m_set_maskints(target, cortex_m->maskints_erratum); } return ERROR_OK; } @@ -495,21 +497,21 @@ static int cortex_m_set_maskints_for_halt(struct target *target) static int cortex_m_set_maskints_for_run(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* interrupts taken at resume, whether for step or run -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_AUTO: + /* interrupts taken at resume, whether for step or run -> no mask */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> no mask */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> no mask */ + return cortex_m_set_maskints(target, false); } return ERROR_OK; } @@ -517,21 +519,21 @@ static int cortex_m_set_maskints_for_run(struct target *target) static int cortex_m_set_maskints_for_step(struct target *target) { switch (target_to_cm(target)->isrmasking_mode) { - case CORTEX_M_ISRMASK_AUTO: - /* the auto-interrupt should already be done -> mask */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_AUTO: + /* the auto-interrupt should already be done -> mask */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_OFF: - /* interrupts never masked */ - return cortex_m_set_maskints(target, false); + case CORTEX_M_ISRMASK_OFF: + /* interrupts never masked */ + return cortex_m_set_maskints(target, false); - case CORTEX_M_ISRMASK_ON: - /* interrupts always masked */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_ON: + /* interrupts always masked */ + return cortex_m_set_maskints(target, true); - case CORTEX_M_ISRMASK_STEPONLY: - /* interrupts masked for single step only -> mask */ - return cortex_m_set_maskints(target, true); + case CORTEX_M_ISRMASK_STEPONLY: + /* interrupts masked for single step only -> mask */ + return cortex_m_set_maskints(target, true); } return ERROR_OK; } @@ -554,7 +556,7 @@ static int cortex_m_clear_halt(struct target *target) retval = mem_ap_write_atomic_u32(armv7m->debug_ap, NVIC_DFSR, cortex_m->nvic_dfsr); if (retval != ERROR_OK) return retval; - LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32 "", cortex_m->nvic_dfsr); + LOG_TARGET_DEBUG(target, "NVIC_DFSR 0x%" PRIx32, cortex_m->nvic_dfsr); return ERROR_OK; } @@ -616,7 +618,7 @@ static int cortex_m_endreset_event(struct target *target) retval = mem_ap_read_atomic_u32(armv7m->debug_ap, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; - LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); + LOG_TARGET_DEBUG(target, "DCB_DEMCR = 0x%8.8" PRIx32, dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); @@ -739,61 +741,61 @@ static int cortex_m_examine_exception_reason(struct target *target) if (retval != ERROR_OK) return retval; switch (armv7m->exception_number) { - case 2: /* NMI */ - break; - case 3: /* Hard Fault */ - retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - if (except_sr & 0x40000000) { - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr); - if (retval != ERROR_OK) - return retval; - } - break; - case 4: /* Memory Management */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 5: /* Bus Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 6: /* Usage Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - break; - case 7: /* Secure Fault */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); - if (retval != ERROR_OK) - return retval; - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); - if (retval != ERROR_OK) - return retval; - break; - case 11: /* SVCall */ - break; - case 12: /* Debug Monitor */ - retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr); + case 2: /* NMI */ + break; + case 3: /* Hard Fault */ + retval = mem_ap_read_atomic_u32(armv7m->debug_ap, NVIC_HFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + if (except_sr & 0x40000000) { + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &cfsr); if (retval != ERROR_OK) return retval; - break; - case 14: /* PendSV */ - break; - case 15: /* SysTick */ - break; - default: - except_sr = 0; - break; + } + break; + case 4: /* Memory Management */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_MMFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 5: /* Bus Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_BFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 6: /* Usage Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_CFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + break; + case 7: /* Secure Fault */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_SFAR, &except_ar); + if (retval != ERROR_OK) + return retval; + break; + case 11: /* SVCall */ + break; + case 12: /* Debug Monitor */ + retval = mem_ap_read_u32(armv7m->debug_ap, NVIC_DFSR, &except_sr); + if (retval != ERROR_OK) + return retval; + break; + case 14: /* PendSV */ + break; + case 15: /* SysTick */ + break; + default: + except_sr = 0; + break; } retval = dap_run(swjdp); if (retval == ERROR_OK) @@ -873,6 +875,14 @@ static int cortex_m_debug_entry(struct target *target) return retval; } + // read caches state + uint32_t ccr = 0; + if (armv7m->armv7m_cache.info_valid) { + retval = mem_ap_read_u32(armv7m->debug_ap, CCR, &ccr); + if (retval != ERROR_OK) + return retval; + } + /* Load all registers to arm.core_cache */ if (!cortex_m->slow_register_read) { retval = cortex_m_fast_read_all_regs(target); @@ -926,6 +936,11 @@ static int cortex_m_debug_entry(struct target *target) secure_state ? "Secure" : "Non-Secure", target_state_name(target)); + if (armv7m->armv7m_cache.info_valid) + LOG_TARGET_DEBUG(target, "D-Cache %s, I-Cache %s", + str_enabled_disabled(ccr & CCR_DC_MASK), + str_enabled_disabled(ccr & CCR_IC_MASK)); + /* Errata 3092511 workaround * Cortex-M7 can halt in an incorrect address when breakpoint * and exception occurs simultaneously */ @@ -1779,6 +1794,7 @@ static int cortex_m_assert_reset(struct target *target) int retval2; retval2 = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); + target->debug_reason = DBG_REASON_DBGRQ; if (retval != ERROR_OK || retval2 != ERROR_OK) LOG_TARGET_INFO(target, "AP write error, reset will not halt"); } @@ -1910,7 +1926,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint comparator_list[fp_num].fpcr_value = fpcr_value; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); - LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32 "", + LOG_TARGET_DEBUG(target, "fpc_num %i fpcr_value 0x%" PRIx32, fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m->fpb_enabled) { @@ -1937,12 +1953,25 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint breakpoint->orig_instr); if (retval != ERROR_OK) return retval; + // make sure data cache is cleaned & invalidated down to PoC + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; + // update i-cache at breakpoint location + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + breakpoint->is_set = true; } @@ -1985,12 +2014,25 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); } else { + // make sure data cache is cleaned & invalidated down to PoC + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + /* restore original instruction (kept in target endianness) */ retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; + + // update i-cache at breakpoint location + retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; + retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length); + if (retval != ERROR_OK) + return retval; } breakpoint->is_set = false; @@ -1999,6 +2041,15 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { + /* + * GDB packets Z0 and z0 provide the 'kind' parameter that is target-specific + * and typically indicates the size in bytes of the breakpoint. + * But for 32-bit Thumb mode (Thumb-2) breakpoint, GDB provides 'kind = 3' to + * be used to derive the length information. See: + * https://sourceware.org/gdb/current/onlinedocs/gdb.html/ARM-Breakpoint-Kinds.html + * Since there isn't a four byte Thumb-2 breakpoint instruction, always use + * the two bytes breakpoint instruction. + */ if (breakpoint->length == 3) { LOG_TARGET_DEBUG(target, "Using a two byte breakpoint for 32bit Thumb-2 request"); breakpoint->length = 2; @@ -2562,6 +2613,112 @@ static bool cortex_m_has_tz(struct target *target) return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0; } +int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec) +{ + if (ssec) { + ssec->dscsr_dirty = false; + ssec->sau_ctrl_dirty = false; + ssec->mpu_ctrl_dirty = false; + } + + if (!cortex_m_has_tz(target)) + return ERROR_OK; + + uint32_t dscsr; + int retval = target_read_u32(target, DCB_DSCSR, &dscsr); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR read failed"); + return retval; + } + if (!(dscsr & DSCSR_CDS)) { + if (ssec) { + ssec->dscsr_dirty = true; + ssec->dscsr = dscsr; + } + LOG_TARGET_DEBUG(target, "Setting Current Domain Secure in DSCSR"); + retval = target_write_u32(target, DCB_DSCSR, DSCSR_CDS); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed"); + return retval; + } + } + + uint32_t sau_ctrl; + retval = target_read_u32(target, SAU_CTRL, &sau_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL read failed"); + return retval; + } + if (sau_ctrl & SAU_CTRL_ENABLE) { + if (ssec) { + ssec->sau_ctrl_dirty = true; + ssec->sau_ctrl = sau_ctrl; + } + retval = target_write_u32(target, SAU_CTRL, sau_ctrl & ~SAU_CTRL_ENABLE); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: SAU_CTRL write failed"); + return retval; + } + } + + uint32_t mpu_ctrl; + retval = target_read_u32(target, MPU_CTRL, &mpu_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL read failed"); + return retval; + } + if (mpu_ctrl & MPU_CTRL_ENABLE) { + if (ssec) { + ssec->mpu_ctrl_dirty = true; + ssec->mpu_ctrl = mpu_ctrl; + } + retval = target_write_u32(target, MPU_CTRL, mpu_ctrl & ~MPU_CTRL_ENABLE); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: MPU_CTRL write failed"); + return retval; + } + } + return ERROR_OK; +} + +int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec) +{ + int retval; + if (!cortex_m_has_tz(target)) + return ERROR_OK; + + if (!ssec) + return ERROR_OK; + + if (ssec->mpu_ctrl_dirty) { + retval = target_write_u32(target, MPU_CTRL, ssec->mpu_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M security restore: MPU_CTRL write failed"); + return retval; + } + ssec->mpu_ctrl_dirty = false; + } + + if (ssec->sau_ctrl_dirty) { + retval = target_write_u32(target, SAU_CTRL, ssec->sau_ctrl); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M security restore: SAU_CTRL write failed"); + return retval; + } + ssec->sau_ctrl_dirty = false; + } + + if (ssec->dscsr_dirty) { + LOG_TARGET_DEBUG(target, "Restoring Current Domain Security in DSCSR"); + retval = target_write_u32(target, DCB_DSCSR, ssec->dscsr & ~DSCSR_CDSKEY); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "ARMv8M set secure: DSCSR write failed"); + return retval; + } + ssec->dscsr_dirty = false; + } + return ERROR_OK; +} #define MVFR0 0xE000EF40 #define MVFR0_SP_MASK 0x000000F0 @@ -2666,7 +2823,7 @@ int cortex_m_examine(struct target *target) else LOG_TARGET_INFO(target, "The erratum 3092511 workaround will resume after an incorrect halt"); } - LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); + LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32, cpuid); if (cortex_m->core_info->flags & CORTEX_M_F_HAS_FPV4) { uint32_t mvfr0; @@ -2799,6 +2956,12 @@ int cortex_m_examine(struct target *target) LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints", cortex_m->fp_num_code, cortex_m->dwt_num_comp); + + retval = armv7m_identify_cache(target); + if (retval != ERROR_OK) { + LOG_ERROR("Cannot detect cache"); + return retval; + } } return ERROR_OK; @@ -3087,29 +3250,15 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m_common *cortex_m = target_to_cm(target); - int retval; - char *reset_config; - retval = cortex_m_verify_pointer(CMD, cortex_m); + int retval = cortex_m_verify_pointer(CMD, cortex_m); if (retval != ERROR_OK) return retval; - if (CMD_ARGC > 0) { - if (strcmp(*CMD_ARGV, "sysresetreq") == 0) - cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; - - else if (strcmp(*CMD_ARGV, "vectreset") == 0) { - if (target_was_examined(target) - && !cortex_m->vectreset_supported) - LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core!"); - else - cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; + if (!CMD_ARGC) { + char *reset_config; - } else - return ERROR_COMMAND_SYNTAX_ERROR; - } - - switch (cortex_m->soft_reset_config) { + switch (cortex_m->soft_reset_config) { case CORTEX_M_RESET_SYSRESETREQ: reset_config = "sysresetreq"; break; @@ -3121,13 +3270,40 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command) default: reset_config = "unknown"; break; + } + + command_print(CMD, "%s", reset_config); + return ERROR_OK; + } else if (CMD_ARGC != 1) { + return ERROR_COMMAND_SYNTAX_ERROR; } - command_print(CMD, "cortex_m reset_config %s", reset_config); + if (!strcmp(CMD_ARGV[0], "sysresetreq")) { + cortex_m->soft_reset_config = CORTEX_M_RESET_SYSRESETREQ; + } else if (!strcmp(CMD_ARGV[0], "vectreset")) { + if (target_was_examined(target) + && !cortex_m->vectreset_supported) + LOG_TARGET_WARNING(target, "VECTRESET is not supported on your Cortex-M core"); + else + cortex_m->soft_reset_config = CORTEX_M_RESET_VECTRESET; + } else { + command_print(CMD, "invalid reset config '%s'", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } return ERROR_OK; } +COMMAND_HANDLER(handle_cortex_m_cache_info_command) +{ + if (CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + return armv7m_handle_cache_info_command(CMD, target); +} + static const struct command_registration cortex_m_exec_command_handlers[] = { { .name = "maskisr", @@ -3150,6 +3326,13 @@ static const struct command_registration cortex_m_exec_command_handlers[] = { .help = "configure software reset handling", .usage = "['sysresetreq'|'vectreset']", }, + { + .name = "cache_info", + .handler = handle_cortex_m_cache_info_command, + .mode = COMMAND_EXEC, + .help = "display information about target caches", + .usage = "", + }, { .chain = smp_command_handlers, }, diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 144f24560c..e0a4e8552a 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -15,6 +15,7 @@ #define OPENOCD_TARGET_CORTEX_M_H #include "armv7m.h" +#include "helper/bitfield.h" #include "helper/bits.h" #define CORTEX_M_COMMON_MAGIC 0x1A451A45U @@ -114,6 +115,45 @@ struct cortex_m_part_info { #define FPU_FPCAR 0xE000EF38 #define FPU_FPDSCR 0xE000EF3C +// Cache +#define CCR 0xE000ED14 +#define CLIDR 0xE000ED78 +#define CTR 0xE000ED7C +#define CCSIDR 0xE000ED80 +#define CSSELR 0xE000ED84 +#define ICIMVAU 0xE000EF58 +#define DCCIMVAC 0xE000EF70 + +#define CCR_IC_MASK BIT(17) +#define CCR_DC_MASK BIT(16) + +#define CLIDR_ICB_MASK GENMASK(31, 30) +#define CLIDR_LOUU_MASK GENMASK(29, 27) +#define CLIDR_LOC_MASK GENMASK(26, 24) +#define CLIDR_LOUIS_MASK GENMASK(23, 21) +#define CLIDR_CTYPE_MASK(i) (GENMASK(2, 0) << (3 * (i) - 3)) + +#define CLIDR_CTYPE_I_CACHE BIT(0) +#define CLIDR_CTYPE_D_CACHE BIT(1) +#define CLIDR_CTYPE_UNIFIED_CACHE BIT(2) + +#define CTR_FORMAT_MASK GENMASK(31, 29) +#define CTR_CWG_MASK GENMASK(27, 24) +#define CTR_ERG_MASK GENMASK(23, 20) +#define CTR_DMINLINE_MASK GENMASK(19, 16) +#define CTR_IMINLINE_MASK GENMASK(3, 0) + +#define CTR_FORMAT_PROVIDED 0x04 + +#define CCSIDR_NUMSETS_MASK GENMASK(27, 13) +#define CCSIDR_ASSOCIATIVITY_MASK GENMASK(12, 3) +#define CCSIDR_LINESIZE_MASK GENMASK(2, 0) + +#define CSSELR_LEVEL_MASK GENMASK(3, 1) +#define CSSELR_IND_MASK BIT(0) +#define CSSELR_IND_DATA_OR_UNIFIED_CACHE 0 +#define CSSELR_IND_INSTRUCTION_CACHE 1 + #define TPIU_SSPSR 0xE0040000 #define TPIU_CSPSR 0xE0040004 #define TPIU_ACPR 0xE0040010 @@ -167,6 +207,8 @@ struct cortex_m_part_info { #define NVIC_DFSR 0xE000ED30 #define NVIC_MMFAR 0xE000ED34 #define NVIC_BFAR 0xE000ED38 +#define MPU_CTRL 0xE000ED94 +#define SAU_CTRL 0xE000EDD0 #define NVIC_SFSR 0xE000EDE4 #define NVIC_SFAR 0xE000EDE8 @@ -184,6 +226,9 @@ struct cortex_m_part_info { #define DFSR_VCATCH 8 #define DFSR_EXTERNAL 16 +#define MPU_CTRL_ENABLE BIT(0) +#define SAU_CTRL_ENABLE BIT(0) + #define FPCR_CODE 0 #define FPCR_LITERAL 1 #define FPCR_REPLACE_REMAP (0ul << 30) @@ -264,6 +309,15 @@ struct cortex_m_common { bool incorrect_halt_erratum; }; +struct cortex_m_saved_security { + bool dscsr_dirty; + uint32_t dscsr; + bool sau_ctrl_dirty; + uint32_t sau_ctrl; + bool mpu_ctrl_dirty; + uint32_t mpu_ctrl; +}; + static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) { return cortex_m->common_magic == CORTEX_M_COMMON_MAGIC; @@ -341,4 +395,17 @@ void cortex_m_deinit_target(struct target *target); int cortex_m_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); +/** + * Forces Cortex-M core to the basic secure context with SAU and MPU off + * @param ssec pointer to save previous security state or NULL + * @returns error code or ERROR_OK if secure mode was set or is not applicable + * (not ARMv8M with security extension) + */ +int cortex_m_set_secure(struct target *target, struct cortex_m_saved_security *ssec); + +/** + * Restores saved security context to MPU_CTRL, SAU_CTRL and DSCSR + */ +int cortex_m_security_restore(struct target *target, struct cortex_m_saved_security *ssec); + #endif /* OPENOCD_TARGET_CORTEX_M_H */ diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 8198438230..a989c331ba 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -741,37 +741,37 @@ static int dsp563xx_read_register(struct target *target, int num, int force) arch_info = dsp563xx->core_cache->reg_list[num].arch_info; switch (arch_info->num) { - case DSP563XX_REG_IDX_SSH: - err = dsp563xx_reg_ssh_read(target); - break; - case DSP563XX_REG_IDX_SSL: - err = dsp563xx_reg_ssl_read(target); - break; - case DSP563XX_REG_IDX_PC: - err = dsp563xx_reg_pc_read(target); - break; - case DSP563XX_REG_IDX_IPRC: - case DSP563XX_REG_IDX_IPRP: - case DSP563XX_REG_IDX_BCR: - case DSP563XX_REG_IDX_DCR: - case DSP563XX_REG_IDX_AAR0: - case DSP563XX_REG_IDX_AAR1: - case DSP563XX_REG_IDX_AAR2: - case DSP563XX_REG_IDX_AAR3: - err = dsp563xx_reg_read_high_io(target, - arch_info->instr_mask, &data); - if (err == ERROR_OK) { - dsp563xx->core_regs[num] = data; - dsp563xx->read_core_reg(target, num); - } - break; - default: - err = dsp563xx_reg_read(target, arch_info->eame, &data); - if (err == ERROR_OK) { - dsp563xx->core_regs[num] = data; - dsp563xx->read_core_reg(target, num); - } - break; + case DSP563XX_REG_IDX_SSH: + err = dsp563xx_reg_ssh_read(target); + break; + case DSP563XX_REG_IDX_SSL: + err = dsp563xx_reg_ssl_read(target); + break; + case DSP563XX_REG_IDX_PC: + err = dsp563xx_reg_pc_read(target); + break; + case DSP563XX_REG_IDX_IPRC: + case DSP563XX_REG_IDX_IPRP: + case DSP563XX_REG_IDX_BCR: + case DSP563XX_REG_IDX_DCR: + case DSP563XX_REG_IDX_AAR0: + case DSP563XX_REG_IDX_AAR1: + case DSP563XX_REG_IDX_AAR2: + case DSP563XX_REG_IDX_AAR3: + err = dsp563xx_reg_read_high_io(target, + arch_info->instr_mask, &data); + if (err == ERROR_OK) { + dsp563xx->core_regs[num] = data; + dsp563xx->read_core_reg(target, num); + } + break; + default: + err = dsp563xx_reg_read(target, arch_info->eame, &data); + if (err == ERROR_OK) { + dsp563xx->core_regs[num] = data; + dsp563xx->read_core_reg(target, num); + } + break; } } @@ -793,37 +793,34 @@ static int dsp563xx_write_register(struct target *target, int num, int force) dsp563xx->write_core_reg(target, num); switch (arch_info->num) { - case DSP563XX_REG_IDX_SSH: - err = dsp563xx_reg_ssh_write(target); - break; - case DSP563XX_REG_IDX_PC: - /* pc is updated on resume, no need to write it here */ - break; - case DSP563XX_REG_IDX_IPRC: - case DSP563XX_REG_IDX_IPRP: - case DSP563XX_REG_IDX_BCR: - case DSP563XX_REG_IDX_DCR: - case DSP563XX_REG_IDX_AAR0: - case DSP563XX_REG_IDX_AAR1: - case DSP563XX_REG_IDX_AAR2: - case DSP563XX_REG_IDX_AAR3: - err = dsp563xx_reg_write_high_io(target, - arch_info->instr_mask, - dsp563xx->core_regs[num]); - break; - default: - err = dsp563xx_reg_write(target, - arch_info->instr_mask, - dsp563xx->core_regs[num]); - - if ((err == ERROR_OK) && (arch_info->num == DSP563XX_REG_IDX_SP)) { - dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = - 0; - dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = - 0; - } - - break; + case DSP563XX_REG_IDX_SSH: + err = dsp563xx_reg_ssh_write(target); + break; + case DSP563XX_REG_IDX_PC: + /* pc is updated on resume, no need to write it here */ + break; + case DSP563XX_REG_IDX_IPRC: + case DSP563XX_REG_IDX_IPRP: + case DSP563XX_REG_IDX_BCR: + case DSP563XX_REG_IDX_DCR: + case DSP563XX_REG_IDX_AAR0: + case DSP563XX_REG_IDX_AAR1: + case DSP563XX_REG_IDX_AAR2: + case DSP563XX_REG_IDX_AAR3: + err = dsp563xx_reg_write_high_io(target, + arch_info->instr_mask, + dsp563xx->core_regs[num]); + break; + default: + err = dsp563xx_reg_write(target, + arch_info->instr_mask, + dsp563xx->core_regs[num]); + + if (err == ERROR_OK && arch_info->num == DSP563XX_REG_IDX_SP) { + dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = 0; + dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = 0; + } + break; } } @@ -1490,14 +1487,14 @@ static int dsp563xx_get_default_memory(void) return MEM_P; switch (c[0]) { - case '1': - return MEM_X; - case '2': - return MEM_Y; - case '3': - return MEM_L; - default: - break; + case '1': + return MEM_X; + case '2': + return MEM_Y; + case '3': + return MEM_L; + default: + break; } return MEM_P; @@ -1517,7 +1514,7 @@ static int dsp563xx_read_memory_core(struct target *target, uint8_t *b; LOG_DEBUG( - "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, mem_type, address, size, @@ -1529,18 +1526,18 @@ static int dsp563xx_read_memory_core(struct target *target, } switch (mem_type) { - case MEM_X: - /* TODO: mark effected queued registers */ - move_cmd = 0x61d800; - break; - case MEM_Y: - move_cmd = 0x69d800; - break; - case MEM_P: - move_cmd = 0x07d891; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case MEM_X: + /* TODO: mark effected queued registers */ + move_cmd = 0x61d800; + break; + case MEM_Y: + move_cmd = 0x69d800; + break; + case MEM_P: + move_cmd = 0x07d891; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ @@ -1698,7 +1695,7 @@ static int dsp563xx_write_memory_core(struct target *target, const uint8_t *b; LOG_DEBUG( - "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + "memtype: %d address: 0x%8.8" TARGET_PRIxADDR ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, mem_type, address, size, @@ -1710,19 +1707,19 @@ static int dsp563xx_write_memory_core(struct target *target, } switch (mem_type) { - case MEM_X: - /* invalidate affected x registers */ - dsp563xx_invalidate_x_context(target, address, address + count - 1); - move_cmd = 0x615800; - break; - case MEM_Y: - move_cmd = 0x695800; - break; - case MEM_P: - move_cmd = 0x075891; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case MEM_X: + /* invalidate affected x registers */ + dsp563xx_invalidate_x_context(target, address, address + count - 1); + move_cmd = 0x615800; + break; + case MEM_Y: + move_cmd = 0x695800; + break; + case MEM_P: + move_cmd = 0x075891; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ @@ -1896,55 +1893,55 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres if (err == ERROR_OK) { obcr_value |= OBCR_B0_OR_B1; switch (mem_type) { - case MEM_X: - obcr_value |= OBCR_BP_MEM_X; - break; - case MEM_Y: - obcr_value |= OBCR_BP_MEM_Y; - break; - case MEM_P: - obcr_value |= OBCR_BP_MEM_P; - break; - default: - LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); - err = ERROR_TARGET_INVALID; + case MEM_X: + obcr_value |= OBCR_BP_MEM_X; + break; + case MEM_Y: + obcr_value |= OBCR_BP_MEM_Y; + break; + case MEM_P: + obcr_value |= OBCR_BP_MEM_P; + break; + default: + LOG_ERROR("Unknown mem_type parameter (%" PRIu32 ")", mem_type); + err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (rw) { - case WPT_READ: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ); - break; - case WPT_WRITE: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE); - break; - case WPT_ACCESS: - obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ|OBCR_BP_ON_WRITE); - break; - default: - LOG_ERROR("Unsupported write mode (%d)", rw); - err = ERROR_TARGET_INVALID; + case WPT_READ: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ); + break; + case WPT_WRITE: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_WRITE); + break; + case WPT_ACCESS: + obcr_value |= OBCR_BP_0(OBCR_BP_ON_READ | OBCR_BP_ON_WRITE); + break; + default: + LOG_ERROR("Unsupported write mode (%d)", rw); + err = ERROR_TARGET_INVALID; } } if (err == ERROR_OK) { switch (cond) { - case EQUAL: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL); - break; - case NOT_EQUAL: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL); - break; - case LESS_THAN: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN); - break; - case GREATER: - obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN); - break; - default: - LOG_ERROR("Unsupported condition code (%d)", cond); - err = ERROR_TARGET_INVALID; + case EQUAL: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_EQUAL); + break; + case NOT_EQUAL: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_NOT_EQUAL); + break; + case LESS_THAN: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_LESS_THAN); + break; + case GREATER: + obcr_value |= OBCR_BP_0(OBCR_BP_CC_GREATER_THAN); + break; + default: + LOG_ERROR("Unsupported condition code (%d)", cond); + err = ERROR_TARGET_INVALID; } } @@ -2006,17 +2003,17 @@ COMMAND_HANDLER(dsp563xx_add_watchpoint_command) uint32_t mem_type = 0; switch (CMD_NAME[2]) { - case 'x': - mem_type = MEM_X; - break; - case 'y': - mem_type = MEM_Y; - break; - case 'p': - mem_type = MEM_P; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'x': + mem_type = MEM_X; + break; + case 'y': + mem_type = MEM_Y; + break; + case 'p': + mem_type = MEM_P; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC < 2) @@ -2028,35 +2025,35 @@ COMMAND_HANDLER(dsp563xx_add_watchpoint_command) enum watchpoint_condition cond; switch (CMD_ARGV[0][0]) { - case '>': - cond = GREATER; - break; - case '<': - cond = LESS_THAN; - break; - case '=': - cond = EQUAL; - break; - case '!': - cond = NOT_EQUAL; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case '>': + cond = GREATER; + break; + case '<': + cond = LESS_THAN; + break; + case '=': + cond = EQUAL; + break; + case '!': + cond = NOT_EQUAL; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } enum watchpoint_rw rw; switch (CMD_ARGV[1][0]) { - case 'r': - rw = WPT_READ; - break; - case 'w': - rw = WPT_WRITE; - break; - case 'a': - rw = WPT_ACCESS; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'r': + rw = WPT_READ; + break; + case 'w': + rw = WPT_WRITE; + break; + case 'a': + rw = WPT_ACCESS; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } err = dsp563xx_add_custom_watchpoint(target, address, mem_type, rw, cond); @@ -2097,28 +2094,28 @@ COMMAND_HANDLER(dsp563xx_mem_command) uint8_t *buffer, *b; switch (CMD_NAME[1]) { - case 'w': - read_mem = 0; - break; - case 'd': - read_mem = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + read_mem = 0; + break; + case 'd': + read_mem = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } switch (CMD_NAME[3]) { - case 'x': - mem_type = MEM_X; - break; - case 'y': - mem_type = MEM_Y; - break; - case 'p': - mem_type = MEM_P; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'x': + mem_type = MEM_X; + break; + case 'y': + mem_type = MEM_Y; + break; + case 'p': + mem_type = MEM_P; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC > 0) diff --git a/src/target/embeddedice.c b/src/target/embeddedice.c index 7aef153b58..f6e330b377 100644 --- a/src/target/embeddedice.c +++ b/src/target/embeddedice.c @@ -219,69 +219,69 @@ struct reg_cache *embeddedice_build_reg_cache(struct target *target, LOG_INFO("Embedded ICE version %d", eice_version); switch (eice_version) { - case 1: - /* ARM7TDMI r3, ARM7TDMI-S r3 - * - * REVISIT docs say ARM7TDMI-S r4 uses version 1 but - * that it has 6-bit CTRL and 5-bit STAT... doc bug? - * ARM7TDMI r4 docs say EICE v4. - */ - reg_list[EICE_DBG_CTRL].size = 3; - reg_list[EICE_DBG_STAT].size = 5; - break; - case 2: - /* ARM9TDMI */ - reg_list[EICE_DBG_CTRL].size = 4; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - break; - case 3: - LOG_ERROR("EmbeddedICE v%d handling might be broken", - eice_version); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 4: - /* ARM7TDMI r4 */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; - break; - case 5: - /* ARM9E-S rev 1 */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_single_step = 1; - arm7_9->has_monitor_mode = 1; - break; - case 6: - /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 10; - /* DBG_STAT has MOE bits */ - arm7_9->has_monitor_mode = 1; - break; - case 7: - LOG_ERROR("EmbeddedICE v%d handling might be broken", - eice_version); - reg_list[EICE_DBG_CTRL].size = 6; - reg_list[EICE_DBG_STAT].size = 5; - arm7_9->has_monitor_mode = 1; + case 1: + /* ARM7TDMI r3, ARM7TDMI-S r3 + * + * REVISIT docs say ARM7TDMI-S r4 uses version 1 but + * that it has 6-bit CTRL and 5-bit STAT... doc bug? + * ARM7TDMI r4 docs say EICE v4. + */ + reg_list[EICE_DBG_CTRL].size = 3; + reg_list[EICE_DBG_STAT].size = 5; + break; + case 2: + /* ARM9TDMI */ + reg_list[EICE_DBG_CTRL].size = 4; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + break; + case 3: + LOG_ERROR("EmbeddedICE v%d handling might be broken", + eice_version); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 4: + /* ARM7TDMI r4 */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + case 5: + /* ARM9E-S rev 1 */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_single_step = 1; + arm7_9->has_monitor_mode = 1; + break; + case 6: + /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 10; + /* DBG_STAT has MOE bits */ + arm7_9->has_monitor_mode = 1; + break; + case 7: + LOG_ERROR("EmbeddedICE v%d handling might be broken", + eice_version); + reg_list[EICE_DBG_CTRL].size = 6; + reg_list[EICE_DBG_STAT].size = 5; + arm7_9->has_monitor_mode = 1; + break; + default: + /* + * The Feroceon implementation has the version number + * in some unusual bits. Let feroceon.c validate it + * and do the appropriate setup itself. + */ + if (strcmp(target_type_name(target), "feroceon") == 0 || + strcmp(target_type_name(target), "dragonite") == 0) break; - default: - /* - * The Feroceon implementation has the version number - * in some unusual bits. Let feroceon.c validate it - * and do the appropriate setup itself. - */ - if (strcmp(target_type_name(target), "feroceon") == 0 || - strcmp(target_type_name(target), "dragonite") == 0) - break; - LOG_ERROR("unknown EmbeddedICE version " - "(comms ctrl: 0x%8.8" PRIx32 ")", - buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); + LOG_ERROR("unknown EmbeddedICE version " + "(comms ctrl: 0x%8.8" PRIx32 ")", + buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); } /* On Feroceon and Dragonite the second unit is seemingly missing. */ @@ -502,7 +502,7 @@ void embeddedice_write_reg(struct reg *reg, uint32_t value) { struct embeddedice_reg *ice_reg = reg->arch_info; - LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value); + LOG_DEBUG("%i: 0x%8.8" PRIx32, ice_reg->addr, value); arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); diff --git a/src/target/esirisc.c b/src/target/esirisc.c index fac5dc72ee..bcb0515d01 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -367,24 +367,24 @@ static int esirisc_read_memory(struct target *target, target_addr_t address, void *value_p; switch (size) { - case sizeof(value.word): - value_p = &value.word; - retval = esirisc_jtag_read_word(jtag_info, address, value_p); - break; - - case sizeof(value.hword): - value_p = &value.hword; - retval = esirisc_jtag_read_hword(jtag_info, address, value_p); - break; - - case sizeof(value.byte): - value_p = &value.byte; - retval = esirisc_jtag_read_byte(jtag_info, address, value_p); - break; - - default: - LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); - return ERROR_FAIL; + case sizeof(value.word): + value_p = &value.word; + retval = esirisc_jtag_read_word(jtag_info, address, value_p); + break; + + case sizeof(value.hword): + value_p = &value.hword; + retval = esirisc_jtag_read_hword(jtag_info, address, value_p); + break; + + case sizeof(value.byte): + value_p = &value.byte; + retval = esirisc_jtag_read_byte(jtag_info, address, value_p); + break; + + default: + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); + return ERROR_FAIL; } if (retval != ERROR_OK) { @@ -415,24 +415,24 @@ static int esirisc_write_memory(struct target *target, target_addr_t address, union esirisc_memory value; switch (size) { - case sizeof(value.word): - value.word = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_word(jtag_info, address, value.word); - break; - - case sizeof(value.hword): - value.hword = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); - break; - - case sizeof(value.byte): - value.byte = buf_get_u32(buffer, 0, num_bits); - retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); - break; - - default: - LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); - return ERROR_FAIL; + case sizeof(value.word): + value.word = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_word(jtag_info, address, value.word); + break; + + case sizeof(value.hword): + value.hword = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_hword(jtag_info, address, value.hword); + break; + + case sizeof(value.byte): + value.byte = buf_get_u32(buffer, 0, num_bits); + retval = esirisc_jtag_write_byte(jtag_info, address, value.byte); + break; + + default: + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); + return ERROR_FAIL; } if (retval != ERROR_OK) { @@ -641,25 +641,25 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc uint32_t sn; switch (watchpoint->length) { - case sizeof(uint64_t): - sn = 0x3; - break; - case sizeof(uint32_t): - sn = 0x2; - break; - - case sizeof(uint16_t): - sn = 0x1; - break; - - case sizeof(uint8_t): - sn = 0x0; - break; - - default: - LOG_TARGET_ERROR(target, "unsupported length: %" PRIu32, - watchpoint->length); - return ERROR_FAIL; + case sizeof(uint64_t): + sn = 0x3; + break; + case sizeof(uint32_t): + sn = 0x2; + break; + + case sizeof(uint16_t): + sn = 0x1; + break; + + case sizeof(uint8_t): + sn = 0x0; + break; + + default: + LOG_TARGET_ERROR(target, "unsupported length: %" PRIu32, + watchpoint->length); + return ERROR_FAIL; } dbs |= (sn << (2 * wp_index)); /* DBS.Sn */ @@ -679,21 +679,21 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc uint32_t dn; switch (watchpoint->rw) { - case WPT_READ: - dn = 0x1; - break; + case WPT_READ: + dn = 0x1; + break; - case WPT_WRITE: - dn = 0x2; - break; + case WPT_WRITE: + dn = 0x2; + break; - case WPT_ACCESS: - dn = 0x3; - break; + case WPT_ACCESS: + dn = 0x3; + break; - default: - LOG_TARGET_ERROR(target, "unsupported rw: %" PRId32, watchpoint->rw); - return ERROR_FAIL; + default: + LOG_TARGET_ERROR(target, "unsupported rw: %" PRId32, watchpoint->rw); + return ERROR_FAIL; } dbc |= (dn << (2 * wp_index)); /* DBC.Dn */ @@ -1046,33 +1046,33 @@ static int esirisc_debug_entry(struct target *target) uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); switch (eid) { - /* - * InstBreakpoint exceptions are also raised when a core is - * halted for debugging. The following is required to - * determine if a breakpoint was encountered. - */ - case EID_INST_BREAKPOINT: - breakpoint = breakpoint_find(target, - buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); - target->debug_reason = (breakpoint) ? - DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; - break; - - /* - * eSi-RISC treats watchpoints similarly to breakpoints, - * however GDB will not request to step over the current - * instruction when a watchpoint fires. The following is - * required to resume the target. - */ - case EID_DATA_BREAKPOINT: - esirisc_remove_watchpoints(target); - esirisc_debug_step(target); - esirisc_add_watchpoints(target); - target->debug_reason = DBG_REASON_WATCHPOINT; - break; - - default: - target->debug_reason = DBG_REASON_DBGRQ; + /* + * InstBreakpoint exceptions are also raised when a core is + * halted for debugging. The following is required to + * determine if a breakpoint was encountered. + */ + case EID_INST_BREAKPOINT: + breakpoint = breakpoint_find(target, + buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size)); + target->debug_reason = (breakpoint) ? + DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ; + break; + + /* + * eSi-RISC treats watchpoints similarly to breakpoints, + * however GDB will not request to step over the current + * instruction when a watchpoint fires. The following is + * required to resume the target. + */ + case EID_DATA_BREAKPOINT: + esirisc_remove_watchpoints(target); + esirisc_debug_step(target); + esirisc_add_watchpoints(target); + target->debug_reason = DBG_REASON_WATCHPOINT; + break; + + default: + target->debug_reason = DBG_REASON_DBGRQ; } } diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c index a1d92d1ca9..2dc08e5d2d 100644 --- a/src/target/esirisc_trace.c +++ b/src/target/esirisc_trace.c @@ -389,84 +389,87 @@ static int esirisc_trace_analyze_full(struct command_invocation *cmd, uint8_t *b goto fail; switch (id) { - case ESIRISC_TRACE_ID_EXECUTE: - case ESIRISC_TRACE_ID_STALL: - case ESIRISC_TRACE_ID_BRANCH: - command_print(cmd, "%s", esirisc_trace_id_strings[id]); + case ESIRISC_TRACE_ID_EXECUTE: + case ESIRISC_TRACE_ID_STALL: + case ESIRISC_TRACE_ID_BRANCH: + command_print(cmd, "%s", esirisc_trace_id_strings[id]); + break; + + case ESIRISC_TRACE_ID_EXTENDED: { + uint32_t ext_id; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id); + if (retval != ERROR_OK) + goto fail; + + switch (ext_id) { + case ESIRISC_TRACE_EXT_ID_STOP: + case ESIRISC_TRACE_EXT_ID_WAIT: + case ESIRISC_TRACE_EXT_ID_MULTICYCLE: + command_print(cmd, "%s", esirisc_trace_ext_id_strings[ext_id]); break; - case ESIRISC_TRACE_ID_EXTENDED: { - uint32_t ext_id; + case ESIRISC_TRACE_EXT_ID_ERET: + case ESIRISC_TRACE_EXT_ID_PC: + case ESIRISC_TRACE_EXT_ID_INDIRECT: + case ESIRISC_TRACE_EXT_ID_END_PC: { + uint32_t pc; - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 4, &ext_id); + retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); if (retval != ERROR_OK) goto fail; - switch (ext_id) { - case ESIRISC_TRACE_EXT_ID_STOP: - case ESIRISC_TRACE_EXT_ID_WAIT: - case ESIRISC_TRACE_EXT_ID_MULTICYCLE: - command_print(cmd, "%s", esirisc_trace_ext_id_strings[ext_id]); - break; - - case ESIRISC_TRACE_EXT_ID_ERET: - case ESIRISC_TRACE_EXT_ID_PC: - case ESIRISC_TRACE_EXT_ID_INDIRECT: - case ESIRISC_TRACE_EXT_ID_END_PC: { - uint32_t pc; - - retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &pc); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "%s PC: 0x%" PRIx32, - esirisc_trace_ext_id_strings[ext_id], pc); - - if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) { - command_print(cmd, "--- end of trace ---"); - return ERROR_OK; - } - break; - } - case ESIRISC_TRACE_EXT_ID_EXCEPTION: { - uint32_t eid, epc; - - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid); - if (retval != ERROR_OK) - goto fail; - - retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32, - esirisc_trace_ext_id_strings[ext_id], eid, epc); - break; - } - case ESIRISC_TRACE_EXT_ID_COUNT: { - uint32_t count; - - retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count); - if (retval != ERROR_OK) - goto fail; - - command_print(cmd, "repeats %" PRIu32 " %s", count, - (count == 1) ? "time" : "times"); - break; - } - case ESIRISC_TRACE_EXT_ID_END: - command_print(cmd, "--- end of trace ---"); - return ERROR_OK; - - default: - command_print(cmd, "invalid extended trace ID: %" PRIu32, ext_id); - return ERROR_FAIL; + command_print(cmd, "%s PC: 0x%" PRIx32, + esirisc_trace_ext_id_strings[ext_id], pc); + + if (ext_id == ESIRISC_TRACE_EXT_ID_END_PC) { + command_print(cmd, "--- end of trace ---"); + return ERROR_OK; } break; } + + case ESIRISC_TRACE_EXT_ID_EXCEPTION: { + uint32_t eid, epc; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &eid); + if (retval != ERROR_OK) + goto fail; + + retval = esirisc_trace_buf_get_pc(target, buffer, size, &pos, &epc); + if (retval != ERROR_OK) + goto fail; + + command_print(cmd, "%s EID: 0x%" PRIx32 ", EPC: 0x%" PRIx32, + esirisc_trace_ext_id_strings[ext_id], eid, epc); + break; + } + + case ESIRISC_TRACE_EXT_ID_COUNT: { + uint32_t count; + + retval = esirisc_trace_buf_get_u32(buffer, size, &pos, 6, &count); + if (retval != ERROR_OK) + goto fail; + + command_print(cmd, "repeats %" PRIu32 " %s", count, + (count == 1) ? "time" : "times"); + break; + } + + case ESIRISC_TRACE_EXT_ID_END: + command_print(cmd, "--- end of trace ---"); + return ERROR_OK; + default: - command_print(cmd, "invalid trace ID: %" PRIu32, id); + command_print(cmd, "invalid extended trace ID: %" PRIu32, ext_id); return ERROR_FAIL; + } + break; + } + default: + command_print(cmd, "invalid trace ID: %" PRIu32, id); + return ERROR_FAIL; } } @@ -511,21 +514,21 @@ static int esirisc_trace_analyze(struct command_invocation *cmd, uint8_t *buffer struct esirisc_trace *trace_info = &esirisc->trace_info; switch (trace_info->format) { - case ESIRISC_TRACE_FORMAT_FULL: - command_print(cmd, "--- full pipeline ---"); - return esirisc_trace_analyze_full(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_FULL: + command_print(cmd, "--- full pipeline ---"); + return esirisc_trace_analyze_full(cmd, buffer, size); - case ESIRISC_TRACE_FORMAT_BRANCH: - command_print(cmd, "--- branches taken ---"); - return esirisc_trace_analyze_full(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_BRANCH: + command_print(cmd, "--- branches taken ---"); + return esirisc_trace_analyze_full(cmd, buffer, size); - case ESIRISC_TRACE_FORMAT_ICACHE: - command_print(cmd, "--- icache misses ---"); - return esirisc_trace_analyze_simple(cmd, buffer, size); + case ESIRISC_TRACE_FORMAT_ICACHE: + command_print(cmd, "--- icache misses ---"); + return esirisc_trace_analyze_simple(cmd, buffer, size); - default: - command_print(cmd, "invalid trace format: %i", trace_info->format); - return ERROR_FAIL; + default: + command_print(cmd, "invalid trace format: %i", trace_info->format); + return ERROR_FAIL; } } diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 399ba8e7cd..4ea1c8a335 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -192,8 +192,8 @@ static int esp32_soc_reset(struct target *target) alive_sleep(10); xtensa_poll(target); if (timeval_ms() >= timeout) { - LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", - target->state); + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); get_timeout = true; break; } @@ -501,4 +501,5 @@ struct target_type esp32_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32_command_handlers, + .profiling = esp_xtensa_profiling, }; diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index b86e43e626..eb3ad71f24 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -272,8 +272,8 @@ static int esp32s2_soc_reset(struct target *target) alive_sleep(10); xtensa_poll(target); if (timeval_ms() >= timeout) { - LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state=%d", - target->state); + LOG_TARGET_ERROR(target, "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); return ERROR_TARGET_TIMEOUT; } } @@ -538,4 +538,5 @@ struct target_type esp32s2_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32s2_command_handlers, + .profiling = esp_xtensa_profiling, }; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 82413f77fb..14f7a7bb64 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -193,8 +193,8 @@ static int esp32s3_soc_reset(struct target *target) xtensa_poll(target); if (timeval_ms() >= timeout) { LOG_TARGET_ERROR(target, - "Timed out waiting for CPU to be reset, target state=%d", - target->state); + "Timed out waiting for CPU to be reset, target state %s", + target_state_name(target)); get_timeout = true; break; } diff --git a/src/target/etb.c b/src/target/etb.c index fb3112d70a..f88b589371 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -287,7 +287,7 @@ static int etb_write_reg(struct reg *reg, uint32_t value) uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; - LOG_DEBUG("%i: 0x%8.8" PRIx32 "", (int)(etb_reg->addr), value); + LOG_DEBUG("%i: 0x%8.8" PRIx32, (int)(etb_reg->addr), value); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); diff --git a/src/target/etm.c b/src/target/etm.c index d9a3cdc5e5..1a41d1c8bb 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -326,24 +326,24 @@ struct reg_cache *etm_build_reg_cache(struct target *target, } else { switch (config >> 28) { - case 7: - case 5: - case 3: - bcd_vers = 0x13; - break; - case 4: - case 2: - bcd_vers = 0x12; - break; - case 1: - bcd_vers = 0x11; - break; - case 0: - bcd_vers = 0x10; - break; - default: - LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); - goto fail; + case 7: + case 5: + case 3: + bcd_vers = 0x13; + break; + case 4: + case 2: + bcd_vers = 0x12; + break; + case 1: + bcd_vers = 0x11; + break; + case 0: + bcd_vers = 0x10; + break; + default: + LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); + goto fail; } } etm_ctx->bcd_vers = bcd_vers; @@ -584,7 +584,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value) return ERROR_COMMAND_SYNTAX_ERROR; } - LOG_DEBUG("%s (%u): 0x%8.8" PRIx32 "", r->name, reg_addr, value); + LOG_DEBUG("%s (%u): 0x%8.8" PRIx32, r->name, reg_addr, value); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) @@ -923,52 +923,48 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio ctx->pipe_index += 2; switch (ctx->last_branch_reason) { - case 0x0: /* normal PC change */ - next_pc = ctx->last_branch; - break; - case 0x1: /* tracing enabled */ - command_print(cmd, - "--- tracing enabled at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x2: /* trace restarted after FIFO overflow */ - command_print(cmd, - "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; - ctx->pipe_index++; - continue; - break; - case 0x3: /* exit from debug state */ + case 0x0: /* normal PC change */ + next_pc = ctx->last_branch; + break; + case 0x1: /* tracing enabled */ + command_print(cmd, + "--- tracing enabled at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x2: /* trace restarted after FIFO overflow */ + command_print(cmd, + "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x3: /* exit from debug state */ + command_print(cmd, + "--- exit from debug state at 0x%8.8" PRIx32 " ---", + ctx->last_branch); + ctx->current_pc = ctx->last_branch; + ctx->pipe_index++; + continue; + case 0x4: /* periodic synchronization point */ + next_pc = ctx->last_branch; + /* if we had no valid PC prior to this synchronization point, + * we have to move on with the next trace cycle + */ + if (!current_pc_ok) { command_print(cmd, - "--- exit from debug state at 0x%8.8" PRIx32 " ---", - ctx->last_branch); - ctx->current_pc = ctx->last_branch; + "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", + next_pc); + ctx->current_pc = next_pc; ctx->pipe_index++; continue; - break; - case 0x4: /* periodic synchronization point */ - next_pc = ctx->last_branch; - /* if we had no valid PC prior to this synchronization point, - * we have to move on with the next trace cycle - */ - if (!current_pc_ok) { - command_print(cmd, - "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", - next_pc); - ctx->current_pc = next_pc; - ctx->pipe_index++; - continue; - } - break; - default: /* reserved */ - LOG_ERROR( - "BUG: branch reason code 0x%" PRIx32 " is reserved", - ctx->last_branch_reason); - return ERROR_FAIL; + } + break; + default: /* reserved */ + LOG_ERROR("BUG: branch reason code 0x%" PRIx32 " is reserved", + ctx->last_branch_reason); + return ERROR_FAIL; } /* if we got here the branch was a normal PC change @@ -986,7 +982,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio command_print(cmd, "data abort"); else { command_print(cmd, - "exception vector 0x%2.2" PRIx32 "", + "exception vector 0x%2.2" PRIx32, ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; @@ -1044,7 +1040,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (ctx->ptr_ok) command_print(cmd, - "address: 0x%8.8" PRIx32 "", + "address: 0x%8.8" PRIx32, ctx->last_ptr); } @@ -1059,7 +1055,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd, - "data: 0x%8.8" PRIx32 "", + "data: 0x%8.8" PRIx32, data); } } @@ -1069,7 +1065,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_invocatio if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; - command_print(cmd, "data: 0x%8.8" PRIx32 "", data); + command_print(cmd, "data: 0x%8.8" PRIx32, data); } } @@ -1148,21 +1144,21 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, uint8_t context_id; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], context_id); switch (context_id) { - case 0: - tracemode |= ETM_CTRL_CONTEXTID_NONE; - break; - case 8: - tracemode |= ETM_CTRL_CONTEXTID_8; - break; - case 16: - tracemode |= ETM_CTRL_CONTEXTID_16; - break; - case 32: - tracemode |= ETM_CTRL_CONTEXTID_32; - break; - default: - command_print(CMD, "invalid option '%s'", CMD_ARGV[1]); - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + tracemode |= ETM_CTRL_CONTEXTID_NONE; + break; + case 8: + tracemode |= ETM_CTRL_CONTEXTID_8; + break; + case 16: + tracemode |= ETM_CTRL_CONTEXTID_16; + break; + case 32: + tracemode |= ETM_CTRL_CONTEXTID_32; + break; + default: + command_print(CMD, "invalid option '%s'", CMD_ARGV[1]); + return ERROR_COMMAND_SYNTAX_ERROR; } bool etmv1_cycle_accurate; @@ -1205,14 +1201,14 @@ COMMAND_HANDLER(handle_etm_tracemode_command) uint32_t tracemode = etm->control; switch (CMD_ARGC) { - case 0: - break; - case 4: - CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, - &tracemode); - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + break; + case 4: + CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, + &tracemode); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } /** @@ -1223,33 +1219,33 @@ COMMAND_HANDLER(handle_etm_tracemode_command) command_print(CMD, "current tracemode configuration:"); switch (tracemode & ETM_CTRL_TRACE_MASK) { - default: - command_print(CMD, "data tracing: none"); - break; - case ETM_CTRL_TRACE_DATA: - command_print(CMD, "data tracing: data only"); - break; - case ETM_CTRL_TRACE_ADDR: - command_print(CMD, "data tracing: address only"); - break; - case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: - command_print(CMD, "data tracing: address and data"); - break; + default: + command_print(CMD, "data tracing: none"); + break; + case ETM_CTRL_TRACE_DATA: + command_print(CMD, "data tracing: data only"); + break; + case ETM_CTRL_TRACE_ADDR: + command_print(CMD, "data tracing: address only"); + break; + case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: + command_print(CMD, "data tracing: address and data"); + break; } switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { - case ETM_CTRL_CONTEXTID_NONE: - command_print(CMD, "contextid tracing: none"); - break; - case ETM_CTRL_CONTEXTID_8: - command_print(CMD, "contextid tracing: 8 bit"); - break; - case ETM_CTRL_CONTEXTID_16: - command_print(CMD, "contextid tracing: 16 bit"); - break; - case ETM_CTRL_CONTEXTID_32: - command_print(CMD, "contextid tracing: 32 bit"); - break; + case ETM_CTRL_CONTEXTID_NONE: + command_print(CMD, "contextid tracing: none"); + break; + case ETM_CTRL_CONTEXTID_8: + command_print(CMD, "contextid tracing: 8 bit"); + break; + case ETM_CTRL_CONTEXTID_16: + command_print(CMD, "contextid tracing: 16 bit"); + break; + case ETM_CTRL_CONTEXTID_32: + command_print(CMD, "contextid tracing: 32 bit"); + break; } if (tracemode & ETM_CTRL_CYCLE_ACCURATE) @@ -1337,39 +1333,39 @@ COMMAND_HANDLER(handle_etm_config_command) uint8_t port_width; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], port_width); switch (port_width) { - /* before ETMv3.0 */ - case 4: - portmode |= ETM_PORT_4BIT; - break; - case 8: - portmode |= ETM_PORT_8BIT; - break; - case 16: - portmode |= ETM_PORT_16BIT; - break; - /* ETMv3.0 and later*/ - case 24: - portmode |= ETM_PORT_24BIT; - break; - case 32: - portmode |= ETM_PORT_32BIT; - break; - case 48: - portmode |= ETM_PORT_48BIT; - break; - case 64: - portmode |= ETM_PORT_64BIT; - break; - case 1: - portmode |= ETM_PORT_1BIT; - break; - case 2: - portmode |= ETM_PORT_2BIT; - break; - default: - command_print(CMD, - "unsupported ETM port width '%s'", CMD_ARGV[1]); - return ERROR_FAIL; + /* before ETMv3.0 */ + case 4: + portmode |= ETM_PORT_4BIT; + break; + case 8: + portmode |= ETM_PORT_8BIT; + break; + case 16: + portmode |= ETM_PORT_16BIT; + break; + /* ETMv3.0 and later*/ + case 24: + portmode |= ETM_PORT_24BIT; + break; + case 32: + portmode |= ETM_PORT_32BIT; + break; + case 48: + portmode |= ETM_PORT_48BIT; + break; + case 64: + portmode |= ETM_PORT_64BIT; + break; + case 1: + portmode |= ETM_PORT_1BIT; + break; + case 2: + portmode |= ETM_PORT_2BIT; + break; + default: + command_print(CMD, + "unsupported ETM port width '%s'", CMD_ARGV[1]); + return ERROR_FAIL; } if (strcmp("normal", CMD_ARGV[2]) == 0) @@ -1500,38 +1496,38 @@ COMMAND_HANDLER(handle_etm_info_command) if (etm->bcd_vers >= 0x30) max_port_size |= (config >> 6) & 0x08; switch (max_port_size) { - /* before ETMv3.0 */ - case 0: - max_port_size = 4; - break; - case 1: - max_port_size = 8; - break; - case 2: - max_port_size = 16; - break; - /* ETMv3.0 and later*/ - case 3: - max_port_size = 24; - break; - case 4: - max_port_size = 32; - break; - case 5: - max_port_size = 48; - break; - case 6: - max_port_size = 64; - break; - case 8: - max_port_size = 1; - break; - case 9: - max_port_size = 2; - break; - default: - LOG_ERROR("Illegal max_port_size"); - return ERROR_FAIL; + /* before ETMv3.0 */ + case 0: + max_port_size = 4; + break; + case 1: + max_port_size = 8; + break; + case 2: + max_port_size = 16; + break; + /* ETMv3.0 and later*/ + case 3: + max_port_size = 24; + break; + case 4: + max_port_size = 32; + break; + case 5: + max_port_size = 48; + break; + case 6: + max_port_size = 64; + break; + case 8: + max_port_size = 1; + break; + case 9: + max_port_size = 2; + break; + default: + LOG_ERROR("Illegal max_port_size"); + return ERROR_FAIL; } command_print(CMD, "max. port size: %i", max_port_size); @@ -1970,19 +1966,19 @@ COMMAND_HANDLER(handle_etm_analyze_command) if (retval != ERROR_OK) { /* FIX! error should be reported inside etmv1_analyze_trace() */ switch (retval) { - case ERROR_ETM_ANALYSIS_FAILED: - command_print(CMD, - "further analysis failed (corrupted trace data or just end of data"); - break; - case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: - command_print(CMD, - "no instruction for current address available, analysis aborted"); - break; - case ERROR_TRACE_IMAGE_UNAVAILABLE: - command_print(CMD, "no image available for trace analysis"); - break; - default: - command_print(CMD, "unknown error"); + case ERROR_ETM_ANALYSIS_FAILED: + command_print(CMD, + "further analysis failed (corrupted trace data or just end of data"); + break; + case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: + command_print(CMD, + "no instruction for current address available, analysis aborted"); + break; + case ERROR_TRACE_IMAGE_UNAVAILABLE: + command_print(CMD, "no image available for trace analysis"); + break; + default: + command_print(CMD, "unknown error"); } } diff --git a/src/target/fa526.c b/src/target/fa526.c index d832d3e7d1..8afb1f0061 100644 --- a/src/target/fa526.c +++ b/src/target/fa526.c @@ -80,15 +80,15 @@ static void fa526_read_core_regs_target_buffer(struct target *target, if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -315,7 +315,7 @@ static int fa526_init_arch_info(struct target *target, arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; - arm920t->armv4_5_mmu.mmu_enabled = 0; + arm920t->armv4_5_mmu.mmu_enabled = false; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if diff --git a/src/target/feroceon.c b/src/target/feroceon.c index cf2c838b7d..2bb7c6a3ed 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -191,15 +191,15 @@ static void feroceon_read_core_regs_target_buffer(struct target *target, for (i = 0; i <= 15; i++) { if (mask & (1 << i)) { switch (size) { - case 4: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); - break; - case 2: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); - break; - case 1: - arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); - break; + case 4: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); + break; + case 2: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); + break; + case 1: + arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); + break; } } } @@ -555,7 +555,7 @@ static int feroceon_bulk_write_memory(struct target *target, if (endaddress != address + count*4) { LOG_ERROR("DCC write failed," " expected end address 0x%08" TARGET_PRIxADDR - " got 0x%0" PRIx32 "", + " got 0x%0" PRIx32, address + count*4, endaddress); retval = ERROR_FAIL; } diff --git a/src/target/image.c b/src/target/image.c index 6864e4e828..40470d8dd3 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -669,7 +669,7 @@ static int image_elf32_read_section(struct image *image, if (offset < field32(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field32(elf, segment->p_filesz) - offset); - LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, + LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR, read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset); @@ -712,7 +712,7 @@ static int image_elf64_read_section(struct image *image, if (offset < field64(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field64(elf, segment->p_filesz) - offset); - LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size, + LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR, read_size, field64(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field64(elf, segment->p_offset) + offset); @@ -814,36 +814,35 @@ static int image_mot_buffer_complete_inner(struct image *image, } } else if (record_type >= 1 && record_type <= 3) { switch (record_type) { - case 1: - /* S1 - 16 bit address data record */ - sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 4; - count -= 2; - break; - - case 2: - /* S2 - 24 bit address data record */ - sscanf(&lpsz_line[bytes_read], "%6" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 6; - count -= 3; - break; - - case 3: - /* S3 - 32 bit address data record */ - sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &address); - cal_checksum += (uint8_t)(address >> 24); - cal_checksum += (uint8_t)(address >> 16); - cal_checksum += (uint8_t)(address >> 8); - cal_checksum += (uint8_t)address; - bytes_read += 8; - count -= 4; - break; - + case 1: + /* S1 - 16 bit address data record */ + sscanf(&lpsz_line[bytes_read], "%4" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 4; + count -= 2; + break; + + case 2: + /* S2 - 24 bit address data record */ + sscanf(&lpsz_line[bytes_read], "%6" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 6; + count -= 3; + break; + + case 3: + /* S3 - 32 bit address data record */ + sscanf(&lpsz_line[bytes_read], "%8" SCNx32, &address); + cal_checksum += (uint8_t)(address >> 24); + cal_checksum += (uint8_t)(address >> 16); + cal_checksum += (uint8_t)(address >> 8); + cal_checksum += (uint8_t)address; + bytes_read += 8; + count -= 4; + break; } if (full_address != address) { @@ -1087,7 +1086,7 @@ int image_read_section(struct image *image, /* don't read past the end of a section */ if (offset + size > image->sections[section].size) { LOG_DEBUG( - "read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", + "read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32, offset, size, image->sections[section].size); diff --git a/src/target/mips32.c b/src/target/mips32.c index 4527c5fa88..b8c61a5bfc 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -374,7 +374,7 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; - LOG_DEBUG("read core reg %i value 0x%" PRIx64 "", num, reg_value); + LOG_DEBUG("read core reg %i value 0x%" PRIx64, num, reg_value); return ERROR_OK; } @@ -419,7 +419,7 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) mips32->core_regs.gpr[cnum] = (uint32_t)reg_value; } - LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx64, num, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; @@ -485,7 +485,7 @@ int mips32_arch_state(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); - LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", + LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32, mips_isa_strings[mips32->isa_mode], debug_reason_name(target), buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); @@ -1687,26 +1687,25 @@ COMMAND_HANDLER(mips32_handle_cp0_command) } switch (CMD_ARGC) { - case 0: /* No arg => print out all cp0 regs */ - retval = mips32_cp0_get_all_regs(CMD, ejtag_info, mips32->cp0_mask); - break; - case 1: /* 1 arg => get cp0 #reg/#sel value by name */ - retval = mips32_cp0_get_reg_by_name(CMD, ejtag_info, mips32->cp0_mask); - break; - case 2: /* 2 args => get cp0 reg/sel value or set value by name */ - tmp = *CMD_ARGV[0]; - if (isdigit(tmp)) /* starts from number then args are #reg and #sel */ - retval = mips32_cp0_get_reg_by_number(CMD, ejtag_info); - else /* or set value by register name */ - retval = mips32_cp0_set_reg_by_name(CMD, mips32, ejtag_info); - - break; - case 3: /* 3 args => set cp0 reg/sel value*/ - retval = mips32_cp0_set_reg_by_number(CMD, mips32, ejtag_info); - break; - default: /* Other argc => err */ - retval = ERROR_COMMAND_SYNTAX_ERROR; - break; + case 0: /* No arg => print out all cp0 regs */ + retval = mips32_cp0_get_all_regs(CMD, ejtag_info, mips32->cp0_mask); + break; + case 1: /* 1 arg => get cp0 #reg/#sel value by name */ + retval = mips32_cp0_get_reg_by_name(CMD, ejtag_info, mips32->cp0_mask); + break; + case 2: /* 2 args => get cp0 reg/sel value or set value by name */ + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) /* starts from number then args are #reg and #sel */ + retval = mips32_cp0_get_reg_by_number(CMD, ejtag_info); + else /* or set value by register name */ + retval = mips32_cp0_set_reg_by_name(CMD, mips32, ejtag_info); + break; + case 3: /* 3 args => set cp0 reg/sel value*/ + retval = mips32_cp0_set_reg_by_number(CMD, mips32, ejtag_info); + break; + default: /* Other argc => err */ + retval = ERROR_COMMAND_SYNTAX_ERROR; + break; } return retval; @@ -2003,20 +2002,20 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command) uint32_t mmu_type = (config0 >> 7) & 7; /* MMU Type Info */ char *mmu; switch (mmu_type) { - case MIPS32_MMU_TLB: - mmu = "TLB"; + case MIPS32_MMU_TLB: + mmu = "TLB"; break; - case MIPS32_MMU_BAT: - mmu = "BAT"; + case MIPS32_MMU_BAT: + mmu = "BAT"; break; - case MIPS32_MMU_FIXED: - mmu = "FIXED"; + case MIPS32_MMU_FIXED: + mmu = "FIXED"; break; - case MIPS32_MMU_DUAL_VTLB_FTLB: - mmu = "DUAL VAR/FIXED"; + case MIPS32_MMU_DUAL_VTLB_FTLB: + mmu = "DUAL VAR/FIXED"; break; - default: - mmu = "Unknown"; + default: + mmu = "Unknown"; } command_print(CMD, "MMU Type: %s", mmu); @@ -2262,25 +2261,25 @@ COMMAND_HANDLER(mips32_handle_dsp_command) } switch (CMD_ARGC) { - case 0: - retval = mips32_dsp_get_all_regs(CMD, mips32); - break; - case 1: - retval = mips32_dsp_get_register(CMD, mips32); - break; - case 2: - tmp = *CMD_ARGV[0]; - if (isdigit(tmp)) { - command_print(CMD, "Error: invalid dsp command format"); - retval = ERROR_COMMAND_ARGUMENT_INVALID; - } else { - retval = mips32_dsp_set_register(CMD, mips32); - } - break; - default: - command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + case 0: + retval = mips32_dsp_get_all_regs(CMD, mips32); + break; + case 1: + retval = mips32_dsp_get_register(CMD, mips32); + break; + case 2: + tmp = *CMD_ARGV[0]; + if (isdigit(tmp)) { + command_print(CMD, "Error: invalid dsp command format"); retval = ERROR_COMMAND_ARGUMENT_INVALID; - break; + } else { + retval = mips32_dsp_set_register(CMD, mips32); + } + break; + default: + command_print(CMD, "Error: invalid argument format, required 0-2, given %d", CMD_ARGC); + retval = ERROR_COMMAND_ARGUMENT_INVALID; + break; } return retval; } diff --git a/src/target/mips32_dmaacc.c b/src/target/mips32_dmaacc.c index beffbf51ee..030a24a5cd 100644 --- a/src/target/mips32_dmaacc.c +++ b/src/target/mips32_dmaacc.c @@ -186,18 +186,18 @@ static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_ /* Handle the bigendian/littleendian */ switch (addr & 0x3) { - case 0: - *data = v & 0xff; - break; - case 1: - *data = (v >> 8) & 0xff; - break; - case 2: - *data = (v >> 16) & 0xff; - break; - case 3: - *data = (v >> 24) & 0xff; - break; + case 0: + *data = v & 0xff; + break; + case 1: + *data = (v >> 8) & 0xff; + break; + case 2: + *data = (v >> 16) & 0xff; + break; + case 3: + *data = (v >> 24) & 0xff; + break; } return ERROR_OK; @@ -341,12 +341,12 @@ static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint3 int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { switch (size) { - case 1: - return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); - case 2: - return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); - case 4: - return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); + case 1: + return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); + case 2: + return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); + case 4: + return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); } return ERROR_OK; @@ -397,12 +397,12 @@ static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf) { switch (size) { - case 1: - return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf); - case 2: - return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf); - case 4: - return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf); + case 1: + return mips32_dmaacc_write_mem8(ejtag_info, addr, count, buf); + case 2: + return mips32_dmaacc_write_mem16(ejtag_info, addr, count, buf); + case 4: + return mips32_dmaacc_write_mem32(ejtag_info, addr, count, buf); } return ERROR_OK; diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index ea90d6f83a..9a22a5031e 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -819,19 +819,19 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz mips32_cp0_read(ejtag_info, &conf, 16, 0); switch (KSEGX(addr)) { - case KUSEG: - cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; - break; - case KSEG0: - cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; - break; - case KSEG2: - case KSEG3: - cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; - break; - default: - /* what ? */ - break; + case KUSEG: + cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; + break; + case KSEG0: + cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; + break; + case KSEG2: + case KSEG3: + cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; + break; + default: + /* what ? */ + break; } /** @@ -1256,19 +1256,19 @@ static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag *ejtag mips32_cp0_read(ejtag_info, &conf, 16, 0); switch (KSEGX(addr)) { - case KUSEG: - cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; - break; - case KSEG0: - cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; - break; - case KSEG2: - case KSEG3: - cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; - break; - default: - /* what ? */ - break; + case KUSEG: + cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; + break; + case KSEG0: + cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; + break; + case KSEG2: + case KSEG3: + cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; + break; + default: + /* what ? */ + break; } /** diff --git a/src/target/mips64.c b/src/target/mips64.c index 3d193a3009..0a3ded0aa3 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -283,7 +283,7 @@ static int mips64_write_core_reg(struct target *target, int num) reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); mips64->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx64, num, reg_value); mips64->core_cache->reg_list[num].valid = true; mips64->core_cache->reg_list[num].dirty = false; @@ -361,7 +361,7 @@ int mips64_arch_state(struct target *target) exit(-1); } - LOG_USER("target halted due to %s, pc: 0x%" PRIx64 "", + LOG_USER("target halted due to %s, pc: 0x%" PRIx64, debug_reason_name(target), buf_get_u64(pc->value, 0, 64)); return ERROR_OK; diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 2ff4aa926f..750c53eba6 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -245,7 +245,7 @@ int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info) /* break bit will be cleared by hardware */ ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); - LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl); + LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32, ejtag_ctrl); if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) goto error; @@ -342,18 +342,18 @@ void ejtag_main_print_imp(struct mips_ejtag *ejtag_info) EJTAG_IMP_HAS(EJTAG_IMP_MIPS64) ? " MIPS64" : " MIPS32"); switch (ejtag_info->ejtag_version) { - case EJTAG_VERSION_20: - ejtag_v20_print_imp(ejtag_info); - break; - case EJTAG_VERSION_25: - case EJTAG_VERSION_26: - case EJTAG_VERSION_31: - case EJTAG_VERSION_41: - case EJTAG_VERSION_51: - ejtag_v26_print_imp(ejtag_info); - break; - default: - break; + case EJTAG_VERSION_20: + ejtag_v20_print_imp(ejtag_info); + break; + case EJTAG_VERSION_25: + case EJTAG_VERSION_26: + case EJTAG_VERSION_31: + case EJTAG_VERSION_41: + case EJTAG_VERSION_51: + ejtag_v26_print_imp(ejtag_info); + break; + default: + break; } } @@ -369,27 +369,27 @@ int mips_ejtag_init(struct mips_ejtag *ejtag_info) ejtag_info->ejtag_version = ((ejtag_info->impcode >> 29) & 0x07); switch (ejtag_info->ejtag_version) { - case EJTAG_VERSION_20: - LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); - break; - case EJTAG_VERSION_25: - LOG_DEBUG("EJTAG: Version 2.5 Detected"); - break; - case EJTAG_VERSION_26: - LOG_DEBUG("EJTAG: Version 2.6 Detected"); - break; - case EJTAG_VERSION_31: - LOG_DEBUG("EJTAG: Version 3.1 Detected"); - break; - case EJTAG_VERSION_41: - LOG_DEBUG("EJTAG: Version 4.1 Detected"); - break; - case EJTAG_VERSION_51: - LOG_DEBUG("EJTAG: Version 5.1 Detected"); - break; - default: - LOG_DEBUG("EJTAG: Unknown Version Detected"); - break; + case EJTAG_VERSION_20: + LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); + break; + case EJTAG_VERSION_25: + LOG_DEBUG("EJTAG: Version 2.5 Detected"); + break; + case EJTAG_VERSION_26: + LOG_DEBUG("EJTAG: Version 2.6 Detected"); + break; + case EJTAG_VERSION_31: + LOG_DEBUG("EJTAG: Version 3.1 Detected"); + break; + case EJTAG_VERSION_41: + LOG_DEBUG("EJTAG: Version 4.1 Detected"); + break; + case EJTAG_VERSION_51: + LOG_DEBUG("EJTAG: Version 5.1 Detected"); + break; + default: + LOG_DEBUG("EJTAG: Unknown Version Detected"); + break; } ejtag_main_print_imp(ejtag_info); diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 4e27914a9d..49658b7353 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -486,11 +486,11 @@ static int mips_m4k_internal_restore(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target resumed at 0x%" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -638,7 +638,7 @@ static int mips_m4k_set_breakpoint(struct target *target, ejtag_info->ejtag_ibm_offs, 0x00000000); target_write_u32(target, comparator_list[bp_num].reg_address + ejtag_info->ejtag_ibc_offs, 1); - LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { @@ -893,17 +893,17 @@ static int mips_m4k_set_watchpoint(struct target *target, } switch (watchpoint->rw) { - case WPT_READ: - enable &= ~EJTAG_DBCN_NOLB; - break; - case WPT_WRITE: - enable &= ~EJTAG_DBCN_NOSB; - break; - case WPT_ACCESS: - enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable &= ~EJTAG_DBCN_NOLB; + break; + case WPT_WRITE: + enable &= ~EJTAG_DBCN_NOSB; + break; + case WPT_ACCESS: + enable &= ~(EJTAG_DBCN_NOLB | EJTAG_DBCN_NOSB); + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } watchpoint_set(watchpoint, wp_num); @@ -928,7 +928,7 @@ static int mips_m4k_set_watchpoint(struct target *target, /* TODO: probably this value is ignored on 2.0 */ target_write_u32(target, comparator_list[wp_num].reg_address + ejtag_info->ejtag_dbv_offs, 0); - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32, wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; } @@ -1012,7 +1012,7 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address, struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -1077,7 +1077,7 @@ static int mips_m4k_write_memory(struct target *target, target_addr_t address, struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { @@ -1204,7 +1204,7 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre int retval; int write_t = 1; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); /* check alignment */ @@ -1270,7 +1270,7 @@ static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t addres int retval; int write_t = 0; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); /* check alignment */ diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index a181a154ee..eb94399e66 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -473,7 +473,7 @@ static int mips_mips64_set_watchpoint(struct target *target, if (retval != ERROR_OK) return retval; - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64 "", wp_num, c->bp_value); + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx64, wp_num, c->bp_value); return ERROR_OK; } @@ -642,7 +642,7 @@ static int mips_mips64_resume(struct target *target, bool current, /* Single step past breakpoint at current address */ bp = breakpoint_find(target, (uint64_t) resume_pc); if (bp) { - LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64 "", + LOG_DEBUG("unset breakpoint at 0x%16.16" PRIx64, bp->address); retval = mips_mips64_unset_breakpoint(target, bp); if (retval != ERROR_OK) @@ -682,7 +682,7 @@ static int mips_mips64_resume(struct target *target, bool current, if (retval != ERROR_OK) return retval; - LOG_DEBUG("target resumed at 0x%" PRIx64 "", resume_pc); + LOG_DEBUG("target resumed at 0x%" PRIx64, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; retval = target_call_event_callbacks(target, @@ -690,7 +690,7 @@ static int mips_mips64_resume(struct target *target, bool current, if (retval != ERROR_OK) return retval; - LOG_DEBUG("target debug resumed at 0x%" PRIx64 "", resume_pc); + LOG_DEBUG("target debug resumed at 0x%" PRIx64, resume_pc); } return ERROR_OK; @@ -911,7 +911,7 @@ static int mips_mips64_read_memory(struct target *target, uint64_t address, } else t = buffer; - LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); retval = mips64_pracc_read_mem(ejtag_info, address, size, count, (void *)t); @@ -949,7 +949,7 @@ static int mips_mips64_bulk_write_memory(struct target *target, struct working_area *fast_data_area; int retval; - LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32, address, count); if (address & 0x7) @@ -1066,7 +1066,7 @@ static int mips_mips64_write_memory(struct target *target, uint64_t address, buffer = t; } - LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: 0x%16.16" PRIx64 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); retval = mips64_pracc_write_mem(ejtag_info, address, size, count, diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index 185a506c45..99abcde110 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -118,50 +118,49 @@ static int jsp_input(struct connection *connection) buf_p = buffer; while (bytes_read) { switch (t_con->state) { - case TELNET_STATE_DATA: - if (*buf_p == 0xff) - t_con->state = TELNET_STATE_IAC; - else { - int out_len = 1; - int in_len; - unsigned char in_buffer[10]; - or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, - &out_len, buf_p, &in_len, - in_buffer); - if (in_len) - telnet_write(connection, - in_buffer, in_len); - } + case TELNET_STATE_DATA: + if (*buf_p == 0xff) { + t_con->state = TELNET_STATE_IAC; + } else { + int out_len = 1; + int in_len; + unsigned char in_buffer[10]; + or1k_adv_jtag_jsp_xfer(jsp_service->jtag_info, + &out_len, buf_p, &in_len, + in_buffer); + if (in_len) + telnet_write(connection, in_buffer, in_len); + } + break; + case TELNET_STATE_IAC: + switch (*buf_p) { + case 0xfe: + t_con->state = TELNET_STATE_DONT; break; - case TELNET_STATE_IAC: - switch (*buf_p) { - case 0xfe: - t_con->state = TELNET_STATE_DONT; - break; - case 0xfd: - t_con->state = TELNET_STATE_DO; - break; - case 0xfc: - t_con->state = TELNET_STATE_WONT; - break; - case 0xfb: - t_con->state = TELNET_STATE_WILL; - break; - } + case 0xfd: + t_con->state = TELNET_STATE_DO; break; - case TELNET_STATE_SB: + case 0xfc: + t_con->state = TELNET_STATE_WONT; break; - case TELNET_STATE_SE: + case 0xfb: + t_con->state = TELNET_STATE_WILL; break; - case TELNET_STATE_WILL: - case TELNET_STATE_WONT: - case TELNET_STATE_DO: - case TELNET_STATE_DONT: - t_con->state = TELNET_STATE_DATA; - break; - default: - LOG_ERROR("unknown telnet state"); - exit(-1); + } + break; + case TELNET_STATE_SB: + break; + case TELNET_STATE_SE: + break; + case TELNET_STATE_WILL: + case TELNET_STATE_WONT: + case TELNET_STATE_DO: + case TELNET_STATE_DONT: + t_con->state = TELNET_STATE_DATA; + break; + default: + LOG_ERROR("unknown telnet state"); + exit(-1); } bytes_read--; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 101b0f2141..8a64e96287 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -3013,9 +3013,9 @@ static int riscv_effective_privilege_mode(struct target *target, int *v_mode, in return ERROR_OK; } -static int riscv_mmu(struct target *target, int *enabled) +static int riscv_mmu(struct target *target, bool *enabled) { - *enabled = 0; + *enabled = false; if (!riscv_virt2phys_mode_is_sw(target)) return ERROR_OK; @@ -3046,7 +3046,7 @@ static int riscv_mmu(struct target *target, int *enabled) /* vsatp is identical to satp, so we can use the satp macros. */ if (get_field(vsatp, RISCV_SATP_MODE(xlen)) != SATP_MODE_OFF) { LOG_TARGET_DEBUG(target, "VS-stage translation is enabled."); - *enabled = 1; + *enabled = true; return ERROR_OK; } @@ -3058,7 +3058,7 @@ static int riscv_mmu(struct target *target, int *enabled) } if (get_field(hgatp, RISCV_HGATP_MODE(xlen)) != HGATP_MODE_OFF) { LOG_TARGET_DEBUG(target, "G-stage address translation is enabled."); - *enabled = 1; + *enabled = true; } else { LOG_TARGET_DEBUG(target, "No V-mode address translation enabled."); } @@ -3083,7 +3083,7 @@ static int riscv_mmu(struct target *target, int *enabled) LOG_TARGET_DEBUG(target, "MMU is disabled."); } else { LOG_TARGET_DEBUG(target, "MMU is enabled."); - *enabled = 1; + *enabled = true; } return ERROR_OK; @@ -3299,7 +3299,7 @@ static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, targe static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_addr_t *physical) { - int enabled; + bool enabled; if (riscv_mmu(target, &enabled) != ERROR_OK) return ERROR_FAIL; if (!enabled) { @@ -3410,7 +3410,7 @@ static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t return ERROR_OK; } - int mmu_enabled; + bool mmu_enabled; int result = riscv_mmu(target, &mmu_enabled); if (result != ERROR_OK) return result; diff --git a/src/target/rtt.c b/src/target/rtt.c index 5ce049ae18..a8ab24a60b 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -37,12 +37,12 @@ static int read_rtt_channel(struct target *target, return ret; channel->address = address; - channel->name_addr = buf_get_u32(buf + 0, 0, 32); - channel->buffer_addr = buf_get_u32(buf + 4, 0, 32); - channel->size = buf_get_u32(buf + 8, 0, 32); - channel->write_pos = buf_get_u32(buf + 12, 0, 32); - channel->read_pos = buf_get_u32(buf + 16, 0, 32); - channel->flags = buf_get_u32(buf + 20, 0, 32); + channel->name_addr = target_buffer_get_u32(target, buf + 0); + channel->buffer_addr = target_buffer_get_u32(target, buf + 4); + channel->size = target_buffer_get_u32(target, buf + 8); + channel->write_pos = target_buffer_get_u32(target, buf + 12); + channel->read_pos = target_buffer_get_u32(target, buf + 16); + channel->flags = target_buffer_get_u32(target, buf + 20); return ERROR_OK; } @@ -230,10 +230,8 @@ int target_rtt_read_control_block(struct target *target, memcpy(ctrl->id, buf, RTT_CB_MAX_ID_LENGTH); ctrl->id[RTT_CB_MAX_ID_LENGTH - 1] = '\0'; - ctrl->num_up_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 0, - 0, 32); - ctrl->num_down_channels = buf_get_u32(buf + RTT_CB_MAX_ID_LENGTH + 4, - 0, 32); + ctrl->num_up_channels = target_buffer_get_u32(target, buf + RTT_CB_MAX_ID_LENGTH + 0); + ctrl->num_down_channels = target_buffer_get_u32(target, buf + RTT_CB_MAX_ID_LENGTH + 4); return ERROR_OK; } diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index ffcd3aafde..5f8ab1082c 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -308,60 +308,60 @@ static char *semihosting_user_op_params; static const char *semihosting_opcode_to_str(const uint64_t opcode) { switch (opcode) { - case SEMIHOSTING_SYS_CLOSE: - return "CLOSE"; - case SEMIHOSTING_SYS_CLOCK: - return "CLOCK"; - case SEMIHOSTING_SYS_ELAPSED: - return "ELAPSED"; - case SEMIHOSTING_SYS_ERRNO: - return "ERRNO"; - case SEMIHOSTING_SYS_EXIT: - return "EXIT"; - case SEMIHOSTING_SYS_EXIT_EXTENDED: - return "EXIT_EXTENDED"; - case SEMIHOSTING_SYS_FLEN: - return "FLEN"; - case SEMIHOSTING_SYS_GET_CMDLINE: - return "GET_CMDLINE"; - case SEMIHOSTING_SYS_HEAPINFO: - return "HEAPINFO"; - case SEMIHOSTING_SYS_ISERROR: - return "ISERROR"; - case SEMIHOSTING_SYS_ISTTY: - return "ISTTY"; - case SEMIHOSTING_SYS_OPEN: - return "OPEN"; - case SEMIHOSTING_SYS_READ: - return "READ"; - case SEMIHOSTING_SYS_READC: - return "READC"; - case SEMIHOSTING_SYS_REMOVE: - return "REMOVE"; - case SEMIHOSTING_SYS_RENAME: - return "RENAME"; - case SEMIHOSTING_SYS_SEEK: - return "SEEK"; - case SEMIHOSTING_SYS_SYSTEM: - return "SYSTEM"; - case SEMIHOSTING_SYS_TICKFREQ: - return "TICKFREQ"; - case SEMIHOSTING_SYS_TIME: - return "TIME"; - case SEMIHOSTING_SYS_TMPNAM: - return "TMPNAM"; - case SEMIHOSTING_SYS_WRITE: - return "WRITE"; - case SEMIHOSTING_SYS_WRITEC: - return "WRITEC"; - case SEMIHOSTING_SYS_WRITE0: - return "WRITE0"; - case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF: - return "USER_CMD"; - case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END: - return "ARM_RESERVED_CMD"; - default: - return ""; + case SEMIHOSTING_SYS_CLOSE: + return "CLOSE"; + case SEMIHOSTING_SYS_CLOCK: + return "CLOCK"; + case SEMIHOSTING_SYS_ELAPSED: + return "ELAPSED"; + case SEMIHOSTING_SYS_ERRNO: + return "ERRNO"; + case SEMIHOSTING_SYS_EXIT: + return "EXIT"; + case SEMIHOSTING_SYS_EXIT_EXTENDED: + return "EXIT_EXTENDED"; + case SEMIHOSTING_SYS_FLEN: + return "FLEN"; + case SEMIHOSTING_SYS_GET_CMDLINE: + return "GET_CMDLINE"; + case SEMIHOSTING_SYS_HEAPINFO: + return "HEAPINFO"; + case SEMIHOSTING_SYS_ISERROR: + return "ISERROR"; + case SEMIHOSTING_SYS_ISTTY: + return "ISTTY"; + case SEMIHOSTING_SYS_OPEN: + return "OPEN"; + case SEMIHOSTING_SYS_READ: + return "READ"; + case SEMIHOSTING_SYS_READC: + return "READC"; + case SEMIHOSTING_SYS_REMOVE: + return "REMOVE"; + case SEMIHOSTING_SYS_RENAME: + return "RENAME"; + case SEMIHOSTING_SYS_SEEK: + return "SEEK"; + case SEMIHOSTING_SYS_SYSTEM: + return "SYSTEM"; + case SEMIHOSTING_SYS_TICKFREQ: + return "TICKFREQ"; + case SEMIHOSTING_SYS_TIME: + return "TIME"; + case SEMIHOSTING_SYS_TMPNAM: + return "TMPNAM"; + case SEMIHOSTING_SYS_WRITE: + return "WRITE"; + case SEMIHOSTING_SYS_WRITEC: + return "WRITEC"; + case SEMIHOSTING_SYS_WRITE0: + return "WRITE0"; + case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF: + return "USER_CMD"; + case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END: + return "ARM_RESERVED_CMD"; + default: + return ""; } } @@ -399,1244 +399,1239 @@ int semihosting_common(struct target *target) semihosting->param); switch (semihosting->op) { + case SEMIHOSTING_SYS_CLOCK: /* 0x10 */ + /* + * Returns the number of centiseconds (hundredths of a second) + * since the execution started. + * + * Values returned can be of limited use for some benchmarking + * purposes because of communication overhead or other + * agent-specific factors. For example, with a debug hardware + * unit the request is passed back to the host for execution. + * This can lead to unpredictable delays in transmission and + * process scheduling. + * + * Use this function to calculate time intervals, by calculating + * differences between intervals with and without the code + * sequence to be timed. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The number of centiseconds since some arbitrary start + * point, if the call is successful. + * - –1 if the call is not successful. For example, because + * of a communications error. + */ + { + clock_t delta = clock() - semihosting->setup_time; - case SEMIHOSTING_SYS_CLOCK: /* 0x10 */ - /* - * Returns the number of centiseconds (hundredths of a second) - * since the execution started. - * - * Values returned can be of limited use for some benchmarking - * purposes because of communication overhead or other - * agent-specific factors. For example, with a debug hardware - * unit the request is passed back to the host for execution. - * This can lead to unpredictable delays in transmission and - * process scheduling. - * - * Use this function to calculate time intervals, by calculating - * differences between intervals with and without the code - * sequence to be timed. - * - * Entry - * The PARAMETER REGISTER must contain 0. There are no other - * parameters. - * - * Return - * On exit, the RETURN REGISTER contains: - * - The number of centiseconds since some arbitrary start - * point, if the call is successful. - * - –1 if the call is not successful. For example, because - * of a communications error. - */ - { - clock_t delta = clock() - semihosting->setup_time; + semihosting->result = delta / (CLOCKS_PER_SEC / 100); + } + break; + + case SEMIHOSTING_SYS_CLOSE: /* 0x02 */ + /* + * Closes a file on the host system. The handle must reference + * a file that was opened with SYS_OPEN. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 Contains a handle for an open file. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful + * - –1 if the call is not successful. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; - semihosting->result = delta / (CLOCKS_PER_SEC / 100); + { + int fd = semihosting_get_field(target, 0, fields); + /* Do not allow to close OpenOCD's own standard streams */ + if (fd == 0 || fd == 1 || fd == 2) { + LOG_DEBUG("ignoring semihosting attempt to close %s", + (fd == 0) ? "stdin" : + (fd == 1) ? "stdout" : "stderr"); + /* Just pretend success */ + semihosting->result = 0; + break; + } + /* Close the descriptor */ + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "close"; + fileio_info->param_1 = fd; + } else { + semihosting->result = close(fd); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); + } } break; - case SEMIHOSTING_SYS_CLOSE: /* 0x02 */ - /* - * Closes a file on the host system. The handle must reference - * a file that was opened with SYS_OPEN. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * - field 1 Contains a handle for an open file. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful - * - –1 if the call is not successful. - */ - retval = semihosting_read_fields(target, 1, fields); + case SEMIHOSTING_SYS_ERRNO: /* 0x13 */ + /* + * Returns the value of the C library errno variable that is + * associated with the semihosting implementation. The errno + * variable can be set by a number of C library semihosted + * functions, including: + * - SYS_REMOVE + * - SYS_OPEN + * - SYS_CLOSE + * - SYS_READ + * - SYS_WRITE + * - SYS_SEEK. + * + * Whether errno is set or not, and to what value, is entirely + * host-specific, except where the ISO C standard defines the + * behavior. + * + * Entry + * There are no parameters. The PARAMETER REGISTER must be 0. + * + * Return + * On exit, the RETURN REGISTER contains the value of the C + * library errno variable. + */ + semihosting->result = semihosting->sys_errno; + break; + + case SEMIHOSTING_SYS_EXIT: /* 0x18 */ + /* + * Note: SYS_EXIT was called angel_SWIreason_ReportException in + * previous versions of the documentation. + * + * An application calls this operation to report an exception + * to the debugger directly. The most common use is to report + * that execution has completed, using ADP_Stopped_ApplicationExit. + * + * Note: This semihosting operation provides no means for 32-bit + * callers to indicate an application exit with a specified exit + * code. Semihosting callers may prefer to check for the presence + * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use + * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it + * is available. + * + * Entry (32-bit) + * On entry, the PARAMETER register is set to a reason code + * describing the cause of the trap. Not all semihosting client + * implementations will necessarily trap every corresponding + * event. Important reason codes are: + * + * - ADP_Stopped_ApplicationExit 0x20026 + * - ADP_Stopped_RunTimeErrorUnknown 0x20023 + * + * Entry (64-bit) + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which is one of the set of + * reason codes in the above tables. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. + * In particular, if field 1 is ADP_Stopped_ApplicationExit + * then field 2 is an exit status code, as passed to the C + * standard library exit() function. A simulator receiving + * this request must notify a connected debugger, if present, + * and then exit with the specified status. + * + * Return + * No return is expected from these calls. However, it is + * possible for the debugger to request that the application + * continues by performing an RDI_Execute request or equivalent. + * In this case, execution continues with the registers as they + * were on entry to the operation, or as subsequently modified + * by the debugger. + */ + if (semihosting->word_size_bytes == 8) { + retval = semihosting_read_fields(target, 2, fields); if (retval != ERROR_OK) return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - /* Do not allow to close OpenOCD's own standard streams */ - if (fd == 0 || fd == 1 || fd == 2) { - LOG_DEBUG("ignoring semihosting attempt to close %s", - (fd == 0) ? "stdin" : - (fd == 1) ? "stdout" : "stderr"); - /* Just pretend success */ - semihosting->result = 0; - break; - } - /* Close the descriptor */ - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "close"; - fileio_info->param_1 = fd; - } else { - semihosting->result = close(fd); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result); - } - } - break; - case SEMIHOSTING_SYS_ERRNO: /* 0x13 */ - /* - * Returns the value of the C library errno variable that is - * associated with the semihosting implementation. The errno - * variable can be set by a number of C library semihosted - * functions, including: - * - SYS_REMOVE - * - SYS_OPEN - * - SYS_CLOSE - * - SYS_READ - * - SYS_WRITE - * - SYS_SEEK. - * - * Whether errno is set or not, and to what value, is entirely - * host-specific, except where the ISO C standard defines the - * behavior. - * - * Entry - * There are no parameters. The PARAMETER REGISTER must be 0. - * - * Return - * On exit, the RETURN REGISTER contains the value of the C - * library errno variable. - */ - semihosting->result = semihosting->sys_errno; - break; + int type = semihosting_get_field(target, 0, fields); + int code = semihosting_get_field(target, 1, fields); - case SEMIHOSTING_SYS_EXIT: /* 0x18 */ - /* - * Note: SYS_EXIT was called angel_SWIreason_ReportException in - * previous versions of the documentation. - * - * An application calls this operation to report an exception - * to the debugger directly. The most common use is to report - * that execution has completed, using ADP_Stopped_ApplicationExit. - * - * Note: This semihosting operation provides no means for 32-bit - * callers to indicate an application exit with a specified exit - * code. Semihosting callers may prefer to check for the presence - * of the SH_EXT_EXTENDED_REPORT_EXCEPTION extension and use - * the SYS_REPORT_EXCEPTION_EXTENDED operation instead, if it - * is available. - * - * Entry (32-bit) - * On entry, the PARAMETER register is set to a reason code - * describing the cause of the trap. Not all semihosting client - * implementations will necessarily trap every corresponding - * event. Important reason codes are: - * - * - ADP_Stopped_ApplicationExit 0x20026 - * - ADP_Stopped_RunTimeErrorUnknown 0x20023 - * - * Entry (64-bit) - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 The exception type, which is one of the set of - * reason codes in the above tables. - * - field 2 A subcode, whose meaning depends on the reason - * code in field 1. - * In particular, if field 1 is ADP_Stopped_ApplicationExit - * then field 2 is an exit status code, as passed to the C - * standard library exit() function. A simulator receiving - * this request must notify a connected debugger, if present, - * and then exit with the specified status. - * - * Return - * No return is expected from these calls. However, it is - * possible for the debugger to request that the application - * continues by performing an RDI_Execute request or equivalent. - * In this case, execution continues with the registers as they - * were on entry to the operation, or as subsequently modified - * by the debugger. - */ - if (semihosting->word_size_bytes == 8) { - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int type = semihosting_get_field(target, 0, fields); - int code = semihosting_get_field(target, 1, fields); - - if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(code); - else { - fprintf(stderr, - "semihosting: *** application exited with %d ***\n", - code); - } - } else { - fprintf(stderr, - "semihosting: application exception %#x\n", - type); - } - } + if (type == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(code); + + fprintf(stderr, + "semihosting: *** application exited with %d ***\n", + code); } else { - if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(0); - else { - fprintf(stderr, - "semihosting: *** application exited normally ***\n"); - } - } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) { - /* Chosen more or less arbitrarily to have a nicer message, - * otherwise all other return the same exit code 1. */ - if (!gdb_get_actual_connections()) - exit(1); - else { - fprintf(stderr, - "semihosting: *** application exited with error ***\n"); - } - } else { - if (!gdb_get_actual_connections()) - exit(1); - else { - fprintf(stderr, - "semihosting: application exception %#x\n", - (unsigned) semihosting->param); - } - } - } - if (!semihosting->has_resumable_exit) { - semihosting->is_resumable = false; - return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + fprintf(stderr, + "semihosting: application exception %#x\n", type); } - break; + } else { + if (semihosting->param == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(0); + + fprintf(stderr, + "semihosting: *** application exited normally ***\n"); + } else if (semihosting->param == ADP_STOPPED_RUN_TIME_ERROR) { + /* Chosen more or less arbitrarily to have a nicer message, + * otherwise all other return the same exit code 1. */ + if (!gdb_get_actual_connections()) + exit(1); + + fprintf(stderr, + "semihosting: *** application exited with error ***\n"); + } else { + if (!gdb_get_actual_connections()) + exit(1); - case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */ - /* - * This operation is only supported if the semihosting extension - * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is - * reported using feature byte 0, bit 0. If this extension is - * supported, then the implementation provides a means to - * report a normal exit with a nonzero exit status in both 32-bit - * and 64-bit semihosting APIs. - * - * The implementation must provide the semihosting call - * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. - * - * SYS_EXIT_EXTENDED is used by an application to report an - * exception or exit to the debugger directly. The most common - * use is to report that execution has completed, using - * ADP_Stopped_ApplicationExit. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 The exception type, which should be one of the set - * of reason codes that are documented for the SYS_EXIT - * (0x18) call. For example, ADP_Stopped_ApplicationExit. - * - field 2 A subcode, whose meaning depends on the reason - * code in field 1. In particular, if field 1 is - * ADP_Stopped_ApplicationExit then field 2 is an exit status - * code, as passed to the C standard library exit() function. - * A simulator receiving this request must notify a connected - * debugger, if present, and then exit with the specified status. - * - * Return - * No return is expected from these calls. - * - * For the A64 API, this call is identical to the behavior of - * the mandatory SYS_EXIT (0x18) call. If this extension is - * supported, then both calls must be implemented. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int type = semihosting_get_field(target, 0, fields); - int code = semihosting_get_field(target, 1, fields); - - if (type == ADP_STOPPED_APPLICATION_EXIT) { - if (!gdb_get_actual_connections()) - exit(code); - else { - fprintf(stderr, - "semihosting: *** application exited with %d ***\n", - code); - } - } else { - fprintf(stderr, "semihosting: exception %#x\n", - type); - } + fprintf(stderr, + "semihosting: application exception %#x\n", + (unsigned int)semihosting->param); } - if (!semihosting->has_resumable_exit) { - semihosting->is_resumable = false; - return target_call_event_callbacks(target, TARGET_EVENT_HALTED); - } - break; + } + if (!semihosting->has_resumable_exit) { + semihosting->is_resumable = false; + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + break; - case SEMIHOSTING_SYS_FLEN: /* 0x0C */ - /* - * Returns the length of a specified file. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * - field 1 A handle for a previously opened, seekable file - * object. - * - * Return - * On exit, the RETURN REGISTER contains: - * - The current length of the file object, if the call is - * successful. - * - –1 if an error occurs. - */ - if (semihosting->is_fileio) { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; + case SEMIHOSTING_SYS_EXIT_EXTENDED: /* 0x20 */ + /* + * This operation is only supported if the semihosting extension + * SH_EXT_EXIT_EXTENDED is implemented. SH_EXT_EXIT_EXTENDED is + * reported using feature byte 0, bit 0. If this extension is + * supported, then the implementation provides a means to + * report a normal exit with a nonzero exit status in both 32-bit + * and 64-bit semihosting APIs. + * + * The implementation must provide the semihosting call + * SYS_EXIT_EXTENDED for both A64 and A32/T32 semihosting APIs. + * + * SYS_EXIT_EXTENDED is used by an application to report an + * exception or exit to the debugger directly. The most common + * use is to report that execution has completed, using + * ADP_Stopped_ApplicationExit. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 The exception type, which should be one of the set + * of reason codes that are documented for the SYS_EXIT + * (0x18) call. For example, ADP_Stopped_ApplicationExit. + * - field 2 A subcode, whose meaning depends on the reason + * code in field 1. In particular, if field 1 is + * ADP_Stopped_ApplicationExit then field 2 is an exit status + * code, as passed to the C standard library exit() function. + * A simulator receiving this request must notify a connected + * debugger, if present, and then exit with the specified status. + * + * Return + * No return is expected from these calls. + * + * For the A64 API, this call is identical to the behavior of + * the mandatory SYS_EXIT (0x18) call. If this extension is + * supported, then both calls must be implemented. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; + + { + int type = semihosting_get_field(target, 0, fields); + int code = semihosting_get_field(target, 1, fields); + + if (type == ADP_STOPPED_APPLICATION_EXIT) { + if (!gdb_get_actual_connections()) + exit(code); + + fprintf(stderr, + "semihosting: *** application exited with %d ***\n", + code); + } else { + fprintf(stderr, "semihosting: exception %#x\n", type); } - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - struct stat buf; - semihosting->result = fstat(fd, &buf); - if (semihosting->result == -1) { - semihosting->sys_errno = errno; - LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); - break; - } + } + if (!semihosting->has_resumable_exit) { + semihosting->is_resumable = false; + return target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + break; + + case SEMIHOSTING_SYS_FLEN: /* 0x0C */ + /* + * Returns the length of a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * - field 1 A handle for a previously opened, seekable file + * object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - The current length of the file object, if the call is + * successful. + * - –1 if an error occurs. + */ + if (semihosting->is_fileio) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; + + { + int fd = semihosting_get_field(target, 0, fields); + struct stat buf; + semihosting->result = fstat(fd, &buf); + if (semihosting->result == -1) { + semihosting->sys_errno = errno; LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); - semihosting->result = buf.st_size; + break; } - break; + LOG_DEBUG("fstat(%d)=%" PRId64, fd, semihosting->result); + semihosting->result = buf.st_size; + } + break; - case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */ - /* - * Returns the command line that is used for the call to the - * executable, that is, argc and argv. - * - * Entry - * On entry, the PARAMETER REGISTER points to a two-field data - * block to be used for returning the command string and its length: - * - field 1 A pointer to a buffer of at least the size that is - * specified in field 2. - * - field 2 The length of the buffer in bytes. - * - * Return - * On exit: - * If the call is successful, then the RETURN REGISTER contains 0, - * the PARAMETER REGISTER is unchanged, and the data block is - * updated as follows: - * - field 1 A pointer to a null-terminated string of the command - * line. - * - field 2 The length of the string in bytes. - * If the call is not successful, then the RETURN REGISTER - * contains -1. - * - * Note: The semihosting implementation might impose limits on - * the maximum length of the string that can be transferred. - * However, the implementation must be able to support a - * command-line length of at least 80 bytes. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t size = semihosting_get_field(target, 1, fields); - - char *arg = semihosting->cmdline ? - semihosting->cmdline : ""; - uint32_t len = strlen(arg) + 1; - if (len > size) - semihosting->result = -1; - else { - semihosting_set_field(target, len, 1, fields); - retval = target_write_buffer(target, addr, len, - (uint8_t *)arg); - if (retval != ERROR_OK) - return retval; - semihosting->result = 0; + case SEMIHOSTING_SYS_GET_CMDLINE: /* 0x15 */ + /* + * Returns the command line that is used for the call to the + * executable, that is, argc and argv. + * + * Entry + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the command string and its length: + * - field 1 A pointer to a buffer of at least the size that is + * specified in field 2. + * - field 2 The length of the buffer in bytes. + * + * Return + * On exit: + * If the call is successful, then the RETURN REGISTER contains 0, + * the PARAMETER REGISTER is unchanged, and the data block is + * updated as follows: + * - field 1 A pointer to a null-terminated string of the command + * line. + * - field 2 The length of the string in bytes. + * If the call is not successful, then the RETURN REGISTER + * contains -1. + * + * Note: The semihosting implementation might impose limits on + * the maximum length of the string that can be transferred. + * However, the implementation must be able to support a + * command-line length of at least 80 bytes. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; - retval = semihosting_write_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - } - LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); - } - break; + { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t size = semihosting_get_field(target, 1, fields); - case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */ - /* - * Returns the system stack and heap parameters. - * - * Entry - * On entry, the PARAMETER REGISTER contains the address of a - * pointer to a four-field data block. The contents of the data - * block are filled by the function. The following C-like - * pseudocode describes the layout of the block: - * struct block { - * void* heap_base; - * void* heap_limit; - * void* stack_base; - * void* stack_limit; - * }; - * - * Return - * On exit, the PARAMETER REGISTER is unchanged and the data - * block has been updated. - */ - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - /* tell the remote we have no idea */ - memset(fields, 0, 4 * semihosting->word_size_bytes); - retval = target_write_memory(target, addr, 4, - semihosting->word_size_bytes, - fields); + char *arg = semihosting->cmdline ? semihosting->cmdline : ""; + uint32_t len = strlen(arg) + 1; + if (len > size) { + semihosting->result = -1; + } else { + semihosting_set_field(target, len, 1, fields); + retval = target_write_buffer(target, addr, len, + (uint8_t *)arg); if (retval != ERROR_OK) return retval; semihosting->result = 0; + + retval = semihosting_write_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; } - break; + LOG_DEBUG("SYS_GET_CMDLINE=[%s], %" PRId64, arg, semihosting->result); + } + break; - case SEMIHOSTING_SYS_ISERROR: /* 0x08 */ - /* - * Determines whether the return code from another semihosting - * call is an error status or not. - * - * This call is passed a parameter block containing the error - * code to examine. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field data block: - * - field 1 The required status word to check. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the status field is not an error indication - * - A nonzero value if the status field is an error indication. - */ - retval = semihosting_read_fields(target, 1, fields); + case SEMIHOSTING_SYS_HEAPINFO: /* 0x16 */ + /* + * Returns the system stack and heap parameters. + * + * Entry + * On entry, the PARAMETER REGISTER contains the address of a + * pointer to a four-field data block. The contents of the data + * block are filled by the function. The following C-like + * pseudocode describes the layout of the block: + * struct block { + * void* heap_base; + * void* heap_limit; + * void* stack_base; + * void* stack_limit; + * }; + * + * Return + * On exit, the PARAMETER REGISTER is unchanged and the data + * block has been updated. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; + + { + uint64_t addr = semihosting_get_field(target, 0, fields); + /* tell the remote we have no idea */ + memset(fields, 0, 4 * semihosting->word_size_bytes); + retval = target_write_memory(target, addr, 4, + semihosting->word_size_bytes, + fields); if (retval != ERROR_OK) return retval; + semihosting->result = 0; + } + break; - uint64_t code = semihosting_get_field(target, 0, fields); - semihosting->result = (code != 0); - break; + case SEMIHOSTING_SYS_ISERROR: /* 0x08 */ + /* + * Determines whether the return code from another semihosting + * call is an error status or not. + * + * This call is passed a parameter block containing the error + * code to examine. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field data block: + * - field 1 The required status word to check. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the status field is not an error indication + * - A nonzero value if the status field is an error indication. + */ + retval = semihosting_read_fields(target, 1, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_ISTTY: /* 0x09 */ - /* - * Checks whether a file is connected to an interactive device. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * one-field argument block: - * field 1 A handle for a previously opened file object. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 1 if the handle identifies an interactive device. - * - 0 if the handle identifies a file. - * - A value other than 1 or 0 if an error occurs. - */ - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "isatty"; - fileio_info->param_1 = semihosting->param; - } else { - retval = semihosting_read_fields(target, 1, fields); - if (retval != ERROR_OK) - return retval; - int fd = semihosting_get_field(target, 0, fields); - // isatty() on Windows may return any non-zero value if fd is a terminal - semihosting->result = isatty(fd) ? 1 : 0; - if (semihosting->result == 0) - semihosting->sys_errno = errno; - LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result); - } - break; + uint64_t code = semihosting_get_field(target, 0, fields); + semihosting->result = (code != 0); + break; - case SEMIHOSTING_SYS_OPEN: /* 0x01 */ - /* - * Opens a file on the host system. - * - * The file path is specified either as relative to the current - * directory of the host process, or absolute, using the path - * conventions of the host operating system. - * - * Semihosting implementations must support opening the special - * path name :semihosting-features as part of the semihosting - * extensions reporting mechanism. - * - * ARM targets interpret the special path name :tt as meaning - * the console input stream, for an open-read or the console - * output stream, for an open-write. Opening these streams is - * performed as part of the standard startup code for those - * applications that reference the C stdio streams. The - * semihosting extension SH_EXT_STDOUT_STDERR allows the - * semihosting caller to open separate output streams - * corresponding to stdout and stderr. This extension is - * reported using feature byte 0, bit 1. Use SYS_OPEN with - * the special path name :semihosting-features to access the - * feature bits. - * - * If this extension is supported, the implementation must - * support the following additional semantics to SYS_OPEN: - * - If the special path name :tt is opened with an fopen - * mode requesting write access (w, wb, w+, or w+b), then - * this is a request to open stdout. - * - If the special path name :tt is opened with a mode - * requesting append access (a, ab, a+, or a+b), then this is - * a request to open stderr. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field argument block: - * - field 1 A pointer to a null-terminated string containing - * a file or device name. - * - field 2 An integer that specifies the file opening mode. - * - field 3 An integer that gives the length of the string - * pointed to by field 1. - * - * The length does not include the terminating null character - * that must be present. - * - * Return - * On exit, the RETURN REGISTER contains: - * - A nonzero handle if the call is successful. - * - –1 if the call is not successful. - */ - retval = semihosting_read_fields(target, 3, fields); + case SEMIHOSTING_SYS_ISTTY: /* 0x09 */ + /* + * Checks whether a file is connected to an interactive device. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * one-field argument block: + * field 1 A handle for a previously opened file object. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 1 if the handle identifies an interactive device. + * - 0 if the handle identifies a file. + * - A value other than 1 or 0 if an error occurs. + */ + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "isatty"; + fileio_info->param_1 = semihosting->param; + } else { + retval = semihosting_read_fields(target, 1, fields); if (retval != ERROR_OK) return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - uint32_t mode = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); + int fd = semihosting_get_field(target, 0, fields); + // isatty() on Windows may return any non-zero value if fd is a terminal + semihosting->result = isatty(fd) ? 1 : 0; + if (semihosting->result == 0) + semihosting->sys_errno = errno; + LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result); + } + break; - if (mode > 11) { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; - break; + case SEMIHOSTING_SYS_OPEN: /* 0x01 */ + /* + * Opens a file on the host system. + * + * The file path is specified either as relative to the current + * directory of the host process, or absolute, using the path + * conventions of the host operating system. + * + * Semihosting implementations must support opening the special + * path name :semihosting-features as part of the semihosting + * extensions reporting mechanism. + * + * ARM targets interpret the special path name :tt as meaning + * the console input stream, for an open-read or the console + * output stream, for an open-write. Opening these streams is + * performed as part of the standard startup code for those + * applications that reference the C stdio streams. The + * semihosting extension SH_EXT_STDOUT_STDERR allows the + * semihosting caller to open separate output streams + * corresponding to stdout and stderr. This extension is + * reported using feature byte 0, bit 1. Use SYS_OPEN with + * the special path name :semihosting-features to access the + * feature bits. + * + * If this extension is supported, the implementation must + * support the following additional semantics to SYS_OPEN: + * - If the special path name :tt is opened with an fopen + * mode requesting write access (w, wb, w+, or w+b), then + * this is a request to open stdout. + * - If the special path name :tt is opened with a mode + * requesting append access (a, ab, a+, or a+b), then this is + * a request to open stderr. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field argument block: + * - field 1 A pointer to a null-terminated string containing + * a file or device name. + * - field 2 An integer that specifies the file opening mode. + * - field 3 An integer that gives the length of the string + * pointed to by field 1. + * + * The length does not include the terminating null character + * that must be present. + * + * Return + * On exit, the RETURN REGISTER contains: + * - A nonzero handle if the call is successful. + * - –1 if the call is not successful. + */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; + + { + uint64_t addr = semihosting_get_field(target, 0, fields); + uint32_t mode = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); + + if (mode > 11) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + break; + } + size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0; + uint8_t *fn = malloc(basedir_len + len + 2); + if (!fn) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + if (basedir_len > 0) { + strcpy((char *)fn, semihosting->basedir); + if (fn[basedir_len - 1] != '/') + fn[basedir_len++] = '/'; } - size_t basedir_len = semihosting->basedir ? strlen(semihosting->basedir) : 0; - uint8_t *fn = malloc(basedir_len + len + 2); - if (!fn) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - if (basedir_len > 0) { - strcpy((char *)fn, semihosting->basedir); - if (fn[basedir_len - 1] != '/') - fn[basedir_len++] = '/'; - } - retval = target_read_memory(target, addr, 1, len, fn + basedir_len); - if (retval != ERROR_OK) { - free(fn); - return retval; - } - fn[basedir_len + len] = 0; - /* TODO: implement the :semihosting-features special file. - * */ - if (semihosting->is_fileio) { - if (strcmp((char *)fn, ":semihosting-features") == 0) { + retval = target_read_memory(target, addr, 1, len, fn + basedir_len); + if (retval != ERROR_OK) { + free(fn); + return retval; + } + fn[basedir_len + len] = 0; + /* TODO: implement the :semihosting-features special file. + * */ + if (semihosting->is_fileio) { + if (strcmp((char *)fn, ":semihosting-features") == 0) { + semihosting->result = -1; + semihosting->sys_errno = EINVAL; + } else if (strcmp((char *)fn, ":tt") == 0) { + if (mode == 0) { + semihosting->result = 0; + } else if (mode == 4) { + semihosting->result = 1; + } else if (mode == 8) { + semihosting->result = 2; + } else { semihosting->result = -1; semihosting->sys_errno = EINVAL; - } else if (strcmp((char *)fn, ":tt") == 0) { - if (mode == 0) { - semihosting->result = 0; - } else if (mode == 4) { - semihosting->result = 1; - } else if (mode == 8) { - semihosting->result = 2; - } else { - semihosting->result = -1; - semihosting->sys_errno = EINVAL; - } - } else { - semihosting->hit_fileio = true; - fileio_info->identifier = "open"; - fileio_info->param_1 = addr; - fileio_info->param_2 = len; - fileio_info->param_3 = open_gdb_modeflags[mode]; - fileio_info->param_4 = 0644; } } else { - if (strcmp((char *)fn, ":tt") == 0) { - /* Mode is: - * - 0-3 ("r") for stdin, - * - 4-7 ("w") for stdout, - * - 8-11 ("a") for stderr */ - int fd; - if (mode < 4) { - fd = dup(STDIN_FILENO); - semihosting->stdin_fd = fd; - LOG_DEBUG("dup(STDIN)=%d", fd); - } else if (mode < 8) { - fd = dup(STDOUT_FILENO); - semihosting->stdout_fd = fd; - LOG_DEBUG("dup(STDOUT)=%d", fd); - } else { - fd = dup(STDERR_FILENO); - semihosting->stderr_fd = fd; - LOG_DEBUG("dup(STDERR)=%d", fd); - } - semihosting->result = fd; - if (fd == -1) - semihosting->sys_errno = errno; + semihosting->hit_fileio = true; + fileio_info->identifier = "open"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; + fileio_info->param_3 = open_gdb_modeflags[mode]; + fileio_info->param_4 = 0644; + } + } else { + if (strcmp((char *)fn, ":tt") == 0) { + /* Mode is: + * - 0-3 ("r") for stdin, + * - 4-7 ("w") for stdout, + * - 8-11 ("a") for stderr */ + int fd; + if (mode < 4) { + fd = dup(STDIN_FILENO); + semihosting->stdin_fd = fd; + LOG_DEBUG("dup(STDIN)=%d", fd); + } else if (mode < 8) { + fd = dup(STDOUT_FILENO); + semihosting->stdout_fd = fd; + LOG_DEBUG("dup(STDOUT)=%d", fd); } else { - /* cygwin requires the permission setting - * otherwise it will fail to reopen a previously - * written file */ - semihosting->result = open((char *)fn, - open_host_modeflags[mode], - 0644); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); + fd = dup(STDERR_FILENO); + semihosting->stderr_fd = fd; + LOG_DEBUG("dup(STDERR)=%d", fd); } + semihosting->result = fd; + if (fd == -1) + semihosting->sys_errno = errno; + } else { + /* cygwin requires the permission setting + * otherwise it will fail to reopen a previously + * written file */ + semihosting->result = open((char *)fn, + open_host_modeflags[mode], + 0644); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result); } - free(fn); } + free(fn); } - break; + } + break; - case SEMIHOSTING_SYS_READ: /* 0x06 */ - /* - * Reads the contents of a file into a buffer. The file position - * is specified either: - * - Explicitly by a SYS_SEEK. - * - Implicitly one byte beyond the previous SYS_READ or - * SYS_WRITE request. - * - * The file position is at the start of the file when it is - * opened, and is lost when the file is closed. Perform the - * file operation as a single action whenever possible. For - * example, do not split a read of 16KB into four 4KB chunks - * unless there is no alternative. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field data block: - * - field 1 Contains a handle for a file previously opened - * with SYS_OPEN. - * - field 2 Points to a buffer. - * - field 3 Contains the number of bytes to read to the buffer - * from the file. - * - * Return - * On exit, the RETURN REGISTER contains the number of bytes not - * filled in the buffer (buffer_length - bytes_read) as follows: - * - If the RETURN REGISTER is 0, the entire buffer was - * successfully filled. - * - If the RETURN REGISTER is the same as field 3, no bytes - * were read (EOF can be assumed). - * - If the RETURN REGISTER contains a value smaller than - * field 3, the read succeeded but the buffer was only partly - * filled. For interactive devices, this is the most common - * return value. - */ - retval = semihosting_read_fields(target, 3, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - uint64_t addr = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "read"; - fileio_info->param_1 = fd; - fileio_info->param_2 = addr; - fileio_info->param_3 = len; + case SEMIHOSTING_SYS_READ: /* 0x06 */ + /* + * Reads the contents of a file into a buffer. The file position + * is specified either: + * - Explicitly by a SYS_SEEK. + * - Implicitly one byte beyond the previous SYS_READ or + * SYS_WRITE request. + * + * The file position is at the start of the file when it is + * opened, and is lost when the file is closed. Perform the + * file operation as a single action whenever possible. For + * example, do not split a read of 16KB into four 4KB chunks + * unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to a buffer. + * - field 3 Contains the number of bytes to read to the buffer + * from the file. + * + * Return + * On exit, the RETURN REGISTER contains the number of bytes not + * filled in the buffer (buffer_length - bytes_read) as follows: + * - If the RETURN REGISTER is 0, the entire buffer was + * successfully filled. + * - If the RETURN REGISTER is the same as field 3, no bytes + * were read (EOF can be assumed). + * - If the RETURN REGISTER contains a value smaller than + * field 3, the read succeeded but the buffer was only partly + * filled. For interactive devices, this is the most common + * return value. + */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; + + { + int fd = semihosting_get_field(target, 0, fields); + uint64_t addr = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "read"; + fileio_info->param_1 = fd; + fileio_info->param_2 = addr; + fileio_info->param_3 = len; + } else { + uint8_t *buf = malloc(len); + if (!buf) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; } else { - uint8_t *buf = malloc(len); - if (!buf) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - semihosting->result = semihosting_read(semihosting, fd, buf, len); - LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, - fd, - addr, - len, - semihosting->result); - if (semihosting->result >= 0) { - retval = target_write_buffer(target, addr, - semihosting->result, - buf); - if (retval != ERROR_OK) { - free(buf); - return retval; - } - /* the number of bytes NOT filled in */ - semihosting->result = len - - semihosting->result; + semihosting->result = semihosting_read(semihosting, fd, buf, len); + LOG_DEBUG("read(%d, 0x%" PRIx64 ", %zu)=%" PRId64, + fd, + addr, + len, + semihosting->result); + if (semihosting->result >= 0) { + retval = target_write_buffer(target, addr, + semihosting->result, + buf); + if (retval != ERROR_OK) { + free(buf); + return retval; } - free(buf); + /* the number of bytes NOT filled in */ + semihosting->result = len - + semihosting->result; } + free(buf); } } - break; + } + break; - case SEMIHOSTING_SYS_READC: /* 0x07 */ - /* - * Reads a byte from the console. - * - * Entry - * The PARAMETER REGISTER must contain 0. There are no other - * parameters or values possible. - * - * Return - * On exit, the RETURN REGISTER contains the byte read from - * the console. - */ - if (semihosting->is_fileio) { - LOG_ERROR("SYS_READC not supported by semihosting fileio"); - return ERROR_FAIL; - } - semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); - LOG_DEBUG("getchar()=%" PRId64, semihosting->result); - break; + case SEMIHOSTING_SYS_READC: /* 0x07 */ + /* + * Reads a byte from the console. + * + * Entry + * The PARAMETER REGISTER must contain 0. There are no other + * parameters or values possible. + * + * Return + * On exit, the RETURN REGISTER contains the byte read from + * the console. + */ + if (semihosting->is_fileio) { + LOG_ERROR("SYS_READC not supported by semihosting fileio"); + return ERROR_FAIL; + } + semihosting->result = semihosting_getchar(semihosting, semihosting->stdin_fd); + LOG_DEBUG("getchar()=%" PRId64, semihosting->result); + break; - case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ - /* - * Deletes a specified file on the host filing system. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 Points to a null-terminated string that gives the - * path name of the file to be deleted. - * - field 2 The length of the string. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the delete is successful - * - A nonzero, host-specific error code if the delete fails. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t len = semihosting_get_field(target, 1, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "unlink"; - fileio_info->param_1 = addr; - fileio_info->param_2 = len; - } else { - uint8_t *fn = malloc(len+1); - if (!fn) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = - target_read_memory(target, addr, 1, len, - fn); - if (retval != ERROR_OK) { - free(fn); - return retval; - } - fn[len] = 0; - semihosting->result = remove((char *)fn); - if (semihosting->result == -1) - semihosting->sys_errno = errno; - LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); + case SEMIHOSTING_SYS_REMOVE: /* 0x0E */ + /* + * Deletes a specified file on the host filing system. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a null-terminated string that gives the + * path name of the file to be deleted. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the delete is successful + * - A nonzero, host-specific error code if the delete fails. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; + { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t len = semihosting_get_field(target, 1, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "unlink"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; + } else { + uint8_t *fn = malloc(len + 1); + if (!fn) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_memory(target, addr, 1, len, fn); + if (retval != ERROR_OK) { free(fn); + return retval; } + fn[len] = 0; + semihosting->result = remove((char *)fn); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result); + + free(fn); } } - break; + } + break; - case SEMIHOSTING_SYS_RENAME: /* 0x0F */ - /* - * Renames a specified file. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * four-field data block: - * - field 1 A pointer to the name of the old file. - * - field 2 The length of the old filename. - * - field 3 A pointer to the new filename. - * - field 4 The length of the new filename. Both strings are - * null-terminated. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the rename is successful. - * - A nonzero, host-specific error code if the rename fails. - */ - retval = semihosting_read_fields(target, 4, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr1 = semihosting_get_field(target, 0, fields); - size_t len1 = semihosting_get_field(target, 1, fields); - uint64_t addr2 = semihosting_get_field(target, 2, fields); - size_t len2 = semihosting_get_field(target, 3, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "rename"; - fileio_info->param_1 = addr1; - fileio_info->param_2 = len1; - fileio_info->param_3 = addr2; - fileio_info->param_4 = len2; + case SEMIHOSTING_SYS_RENAME: /* 0x0F */ + /* + * Renames a specified file. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * four-field data block: + * - field 1 A pointer to the name of the old file. + * - field 2 The length of the old filename. + * - field 3 A pointer to the new filename. + * - field 4 The length of the new filename. Both strings are + * null-terminated. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the rename is successful. + * - A nonzero, host-specific error code if the rename fails. + */ + retval = semihosting_read_fields(target, 4, fields); + if (retval != ERROR_OK) + return retval; + + { + uint64_t addr1 = semihosting_get_field(target, 0, fields); + size_t len1 = semihosting_get_field(target, 1, fields); + uint64_t addr2 = semihosting_get_field(target, 2, fields); + size_t len2 = semihosting_get_field(target, 3, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "rename"; + fileio_info->param_1 = addr1; + fileio_info->param_2 = len1; + fileio_info->param_3 = addr2; + fileio_info->param_4 = len2; + } else { + uint8_t *fn1 = malloc(len1 + 1); + uint8_t *fn2 = malloc(len2 + 1); + if (!fn1 || !fn2) { + free(fn1); + free(fn2); + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; } else { - uint8_t *fn1 = malloc(len1+1); - uint8_t *fn2 = malloc(len2+1); - if (!fn1 || !fn2) { + retval = target_read_memory(target, addr1, 1, len1, fn1); + if (retval != ERROR_OK) { free(fn1); free(fn2); - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = target_read_memory(target, addr1, 1, len1, - fn1); - if (retval != ERROR_OK) { - free(fn1); - free(fn2); - return retval; - } - retval = target_read_memory(target, addr2, 1, len2, - fn2); - if (retval != ERROR_OK) { - free(fn1); - free(fn2); - return retval; - } - fn1[len1] = 0; - fn2[len2] = 0; - semihosting->result = rename((char *)fn1, - (char *)fn2); - // rename() on Windows returns nonzero on error - if (semihosting->result != 0) - semihosting->sys_errno = errno; - LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno); + return retval; + } + retval = target_read_memory(target, addr2, 1, len2, fn2); + if (retval != ERROR_OK) { free(fn1); free(fn2); + return retval; } - } - } - break; - - case SEMIHOSTING_SYS_SEEK: /* 0x0A */ - /* - * Seeks to a specified position in a file using an offset - * specified from the start of the file. The file is assumed - * to be a byte array and the offset is given in bytes. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field data block: - * - field 1 A handle for a seekable file object. - * - field 2 The absolute byte position to seek to. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the request is successful. - * - A negative value if the request is not successful. - * Use SYS_ERRNO to read the value of the host errno variable - * describing the error. - * - * Note: The effect of seeking outside the current extent of - * the file object is undefined. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - off_t pos = semihosting_get_field(target, 1, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "lseek"; - fileio_info->param_1 = fd; - fileio_info->param_2 = pos; - fileio_info->param_3 = SEEK_SET; - } else { - semihosting->result = lseek(fd, pos, SEEK_SET); - if (semihosting->result == -1) + fn1[len1] = 0; + fn2[len2] = 0; + semihosting->result = rename((char *)fn1, (char *)fn2); + // rename() on Windows returns nonzero on error + if (semihosting->result != 0) semihosting->sys_errno = errno; - LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result); - if (semihosting->result == pos) - semihosting->result = 0; + LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno); + free(fn1); + free(fn2); } } - break; + } + break; - case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */ - /* - * Passes a command to the host command-line interpreter. - * This enables you to execute a system command such as dir, - * ls, or pwd. The terminal I/O is on the host, and is not - * visible to the target. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field argument block: - * - field 1 Points to a string to be passed to the host - * command-line interpreter. - * - field 2 The length of the string. - * - * Return - * On exit, the RETURN REGISTER contains the return status. - */ - - /* Provide SYS_SYSTEM functionality. Uses the - * libc system command, there may be a reason *NOT* - * to use this, but as I can't think of one, I - * implemented it this way. - */ - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) - return retval; - else { - uint64_t addr = semihosting_get_field(target, 0, fields); - size_t len = semihosting_get_field(target, 1, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "system"; - fileio_info->param_1 = addr; - fileio_info->param_2 = len; - } else { - uint8_t *cmd = malloc(len+1); - if (!cmd) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = target_read_memory(target, - addr, - 1, - len, - cmd); - if (retval != ERROR_OK) { - free(cmd); - return retval; - } else { - cmd[len] = 0; - semihosting->result = system( - (const char *)cmd); - LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); - } + case SEMIHOSTING_SYS_SEEK: /* 0x0A */ + /* + * Seeks to a specified position in a file using an offset + * specified from the start of the file. The file is assumed + * to be a byte array and the offset is given in bytes. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 A handle for a seekable file object. + * - field 2 The absolute byte position to seek to. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the request is successful. + * - A negative value if the request is not successful. + * Use SYS_ERRNO to read the value of the host errno variable + * describing the error. + * + * Note: The effect of seeking outside the current extent of + * the file object is undefined. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; - free(cmd); - } - } + { + int fd = semihosting_get_field(target, 0, fields); + off_t pos = semihosting_get_field(target, 1, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "lseek"; + fileio_info->param_1 = fd; + fileio_info->param_2 = pos; + fileio_info->param_3 = SEEK_SET; + } else { + semihosting->result = lseek(fd, pos, SEEK_SET); + if (semihosting->result == -1) + semihosting->sys_errno = errno; + LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result); + if (semihosting->result == pos) + semihosting->result = 0; } - break; + } + break; - case SEMIHOSTING_SYS_TIME: /* 0x11 */ - /* - * Returns the number of seconds since 00:00 January 1, 1970. - * This value is real-world time, regardless of any debug agent - * configuration. - * - * Entry - * There are no parameters. - * - * Return - * On exit, the RETURN REGISTER contains the number of seconds. - */ - semihosting->result = time(NULL); - break; + case SEMIHOSTING_SYS_SYSTEM: /* 0x12 */ + /* + * Passes a command to the host command-line interpreter. + * This enables you to execute a system command such as dir, + * ls, or pwd. The terminal I/O is on the host, and is not + * visible to the target. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field argument block: + * - field 1 Points to a string to be passed to the host + * command-line interpreter. + * - field 2 The length of the string. + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ - case SEMIHOSTING_SYS_WRITE: /* 0x05 */ - /* - * Writes the contents of a buffer to a specified file at the - * current file position. The file position is specified either: - * - Explicitly, by a SYS_SEEK. - * - Implicitly as one byte beyond the previous SYS_READ or - * SYS_WRITE request. - * - * The file position is at the start of the file when the file - * is opened, and is lost when the file is closed. - * - * Perform the file operation as a single action whenever - * possible. For example, do not split a write of 16KB into - * four 4KB chunks unless there is no alternative. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * three-field data block: - * - field 1 Contains a handle for a file previously opened - * with SYS_OPEN. - * - field 2 Points to the memory containing the data to be written. - * - field 3 Contains the number of bytes to be written from - * the buffer to the file. - * - * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful. - * - The number of bytes that are not written, if there is an error. - */ - retval = semihosting_read_fields(target, 3, fields); - if (retval != ERROR_OK) - return retval; - else { - int fd = semihosting_get_field(target, 0, fields); - uint64_t addr = semihosting_get_field(target, 1, fields); - size_t len = semihosting_get_field(target, 2, fields); - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "write"; - fileio_info->param_1 = fd; - fileio_info->param_2 = addr; - fileio_info->param_3 = len; + /* Provide SYS_SYSTEM functionality. Uses the + * libc system command, there may be a reason *NOT* + * to use this, but as I can't think of one, I + * implemented it this way. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) + return retval; + + { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t len = semihosting_get_field(target, 1, fields); + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "system"; + fileio_info->param_1 = addr; + fileio_info->param_2 = len; + } else { + uint8_t *cmd = malloc(len + 1); + if (!cmd) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; } else { - uint8_t *buf = malloc(len); - if (!buf) { - semihosting->result = -1; - semihosting->sys_errno = ENOMEM; - } else { - retval = target_read_buffer(target, addr, len, buf); - if (retval != ERROR_OK) { - free(buf); - return retval; - } - semihosting->result = semihosting_write(semihosting, fd, buf, len); - LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, - fd, + retval = target_read_memory(target, addr, + 1, len, - semihosting->result); - if (semihosting->result >= 0) { - /* The number of bytes that are NOT written. - * */ - semihosting->result = len - - semihosting->result; - } - - free(buf); + cmd); + if (retval != ERROR_OK) { + free(cmd); + return retval; } + cmd[len] = 0; + semihosting->result = system((const char *)cmd); + LOG_DEBUG("system('%s')=%" PRId64, cmd, semihosting->result); + + free(cmd); } } - break; + } + break; - case SEMIHOSTING_SYS_WRITEC: /* 0x03 */ - /* - * Writes a character byte, pointed to by the PARAMETER REGISTER, - * to the debug channel. When executed under a semihosting - * debugger, the character appears on the host debugger console. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to the - * character. - * - * Return - * None. The RETURN REGISTER is corrupted. - */ - if (semihosting->is_fileio) { - semihosting->hit_fileio = true; - fileio_info->identifier = "write"; - fileio_info->param_1 = 1; - fileio_info->param_2 = semihosting->param; - fileio_info->param_3 = 1; - } else { - uint64_t addr = semihosting->param; - unsigned char c; - retval = target_read_memory(target, addr, 1, 1, &c); - if (retval != ERROR_OK) - return retval; - semihosting_putchar(semihosting, semihosting->stdout_fd, c); - semihosting->result = 0; - } - break; + case SEMIHOSTING_SYS_TIME: /* 0x11 */ + /* + * Returns the number of seconds since 00:00 January 1, 1970. + * This value is real-world time, regardless of any debug agent + * configuration. + * + * Entry + * There are no parameters. + * + * Return + * On exit, the RETURN REGISTER contains the number of seconds. + */ + semihosting->result = time(NULL); + break; + + case SEMIHOSTING_SYS_WRITE: /* 0x05 */ + /* + * Writes the contents of a buffer to a specified file at the + * current file position. The file position is specified either: + * - Explicitly, by a SYS_SEEK. + * - Implicitly as one byte beyond the previous SYS_READ or + * SYS_WRITE request. + * + * The file position is at the start of the file when the file + * is opened, and is lost when the file is closed. + * + * Perform the file operation as a single action whenever + * possible. For example, do not split a write of 16KB into + * four 4KB chunks unless there is no alternative. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-field data block: + * - field 1 Contains a handle for a file previously opened + * with SYS_OPEN. + * - field 2 Points to the memory containing the data to be written. + * - field 3 Contains the number of bytes to be written from + * the buffer to the file. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - The number of bytes that are not written, if there is an error. + */ + retval = semihosting_read_fields(target, 3, fields); + if (retval != ERROR_OK) + return retval; - case SEMIHOSTING_SYS_WRITE0: /* 0x04 */ - /* - * Writes a null-terminated string to the debug channel. - * When executed under a semihosting debugger, the characters - * appear on the host debugger console. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to the - * first byte of the string. - * - * Return - * None. The RETURN REGISTER is corrupted. - */ + { + int fd = semihosting_get_field(target, 0, fields); + uint64_t addr = semihosting_get_field(target, 1, fields); + size_t len = semihosting_get_field(target, 2, fields); if (semihosting->is_fileio) { - size_t count = 0; - uint64_t addr = semihosting->param; - for (;; addr++) { - unsigned char c; - retval = target_read_memory(target, addr, 1, 1, &c); - if (retval != ERROR_OK) - return retval; - if (c == '\0') - break; - count++; - } semihosting->hit_fileio = true; fileio_info->identifier = "write"; - fileio_info->param_1 = 1; - fileio_info->param_2 = semihosting->param; - fileio_info->param_3 = count; + fileio_info->param_1 = fd; + fileio_info->param_2 = addr; + fileio_info->param_3 = len; } else { - uint64_t addr = semihosting->param; - do { - unsigned char c; - retval = target_read_memory(target, addr++, 1, 1, &c); - if (retval != ERROR_OK) + uint8_t *buf = malloc(len); + if (!buf) { + semihosting->result = -1; + semihosting->sys_errno = ENOMEM; + } else { + retval = target_read_buffer(target, addr, len, buf); + if (retval != ERROR_OK) { + free(buf); return retval; - if (!c) - break; - semihosting_putchar(semihosting, semihosting->stdout_fd, c); - } while (1); - semihosting->result = 0; - } - break; - - case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107: - /** - * This is a user defined operation (while user cmds 0x100-0x1ff - * are possible, only 0x100-0x107 are currently implemented). - * - * Reads the user operation parameters from target, then fires the - * corresponding target event. When the target callbacks returned, - * cleans up the command parameter buffer. - * - * Entry - * On entry, the PARAMETER REGISTER contains a pointer to a - * two-field data block: - * - field 1 Contains a pointer to the bound command parameter - * string - * - field 2 Contains the command parameter string length - * - * Return - * On exit, the RETURN REGISTER contains the return status. - */ - if (semihosting->user_command_extension) { - retval = semihosting->user_command_extension(target); - if (retval != ERROR_NOT_IMPLEMENTED) - break; - /* If custom user command not handled, we are looking for the TCL handler */ - } - - assert(!semihosting_user_op_params); - retval = semihosting_read_fields(target, 2, fields); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read fields for user defined command" - " op=0x%x", semihosting->op); - return retval; - } - - uint64_t addr = semihosting_get_field(target, 0, fields); - - size_t len = semihosting_get_field(target, 1, fields); - if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { - LOG_ERROR("The maximum length for user defined command " - "parameter is %u, received length is %zu (op=0x%x)", - SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + } + semihosting->result = semihosting_write(semihosting, fd, buf, len); + LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64, + fd, + addr, len, - semihosting->op); - return ERROR_FAIL; - } + semihosting->result); + if (semihosting->result >= 0) { + /* The number of bytes that are NOT written. + * */ + semihosting->result = len - + semihosting->result; + } - semihosting_user_op_params = malloc(len + 1); - if (!semihosting_user_op_params) - return ERROR_FAIL; - semihosting_user_op_params[len] = 0; - - retval = target_read_buffer(target, addr, len, - (uint8_t *)(semihosting_user_op_params)); - if (retval != ERROR_OK) { - LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)", - semihosting->op, - semihosting_opcode_to_str(semihosting->op)); - free(semihosting_user_op_params); - semihosting_user_op_params = NULL; - return retval; + free(buf); + } } + } + break; - target_handle_event(target, semihosting->op); - free(semihosting_user_op_params); - semihosting_user_op_params = NULL; - semihosting->result = 0; - break; - - case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ + case SEMIHOSTING_SYS_WRITEC: /* 0x03 */ /* - * Returns the number of elapsed target ticks since execution - * started. - * Use SYS_TICKFREQ to determine the tick frequency. - * - * Entry (32-bit) - * On entry, the PARAMETER REGISTER points to a two-field data - * block to be used for returning the number of elapsed ticks: - * - field 1 The least significant field and is at the low address. - * - field 2 The most significant field and is at the high address. + * Writes a character byte, pointed to by the PARAMETER REGISTER, + * to the debug channel. When executed under a semihosting + * debugger, the character appears on the host debugger console. * - * Entry (64-bit) - * On entry the PARAMETER REGISTER points to a one-field data - * block to be used for returning the number of elapsed ticks: - * - field 1 The number of elapsed ticks as a 64-bit value. + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to the + * character. * * Return - * On exit: - * - On success, the RETURN REGISTER contains 0, the PARAMETER - * REGISTER is unchanged, and the data block pointed to by the - * PARAMETER REGISTER is filled in with the number of elapsed - * ticks. - * - On failure, the RETURN REGISTER contains -1, and the - * PARAMETER REGISTER contains -1. - * - * Note: Some semihosting implementations might not support this - * semihosting operation, and they always return -1 in the - * RETURN REGISTER. + * None. The RETURN REGISTER is corrupted. */ + if (semihosting->is_fileio) { + semihosting->hit_fileio = true; + fileio_info->identifier = "write"; + fileio_info->param_1 = 1; + fileio_info->param_2 = semihosting->param; + fileio_info->param_3 = 1; + } else { + uint64_t addr = semihosting->param; + unsigned char c; + retval = target_read_memory(target, addr, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + semihosting_putchar(semihosting, semihosting->stdout_fd, c); + semihosting->result = 0; + } + break; - case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */ + case SEMIHOSTING_SYS_WRITE0: /* 0x04 */ /* - * Returns the tick frequency. + * Writes a null-terminated string to the debug channel. + * When executed under a semihosting debugger, the characters + * appear on the host debugger console. * * Entry - * The PARAMETER REGISTER must contain 0 on entry to this routine. + * On entry, the PARAMETER REGISTER contains a pointer to the + * first byte of the string. * * Return - * On exit, the RETURN REGISTER contains either: - * - The number of ticks per second. - * - –1 if the target does not know the value of one tick. - * - * Note: Some semihosting implementations might not support - * this semihosting operation, and they always return -1 in the - * RETURN REGISTER. + * None. The RETURN REGISTER is corrupted. */ + if (semihosting->is_fileio) { + size_t count = 0; + uint64_t addr = semihosting->param; + for (;; addr++) { + unsigned char c; + retval = target_read_memory(target, addr, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + if (c == '\0') + break; + count++; + } + semihosting->hit_fileio = true; + fileio_info->identifier = "write"; + fileio_info->param_1 = 1; + fileio_info->param_2 = semihosting->param; + fileio_info->param_3 = count; + } else { + uint64_t addr = semihosting->param; + do { + unsigned char c; + retval = target_read_memory(target, addr++, 1, 1, &c); + if (retval != ERROR_OK) + return retval; + if (!c) + break; + semihosting_putchar(semihosting, semihosting->stdout_fd, c); + } while (1); + semihosting->result = 0; + } + break; - case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */ - /* - * Returns a temporary name for a file identified by a system - * file identifier. + case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X107: + /** + * This is a user defined operation (while user cmds 0x100-0x1ff + * are possible, only 0x100-0x107 are currently implemented). + * + * Reads the user operation parameters from target, then fires the + * corresponding target event. When the target callbacks returned, + * cleans up the command parameter buffer. * * Entry * On entry, the PARAMETER REGISTER contains a pointer to a - * three-word argument block: - * - field 1 A pointer to a buffer. - * - field 2 A target identifier for this filename. Its value - * must be an integer in the range 0-255. - * - field 3 Contains the length of the buffer. The length must - * be at least the value of L_tmpnam on the host system. + * two-field data block: + * - field 1 Contains a pointer to the bound command parameter + * string + * - field 2 Contains the command parameter string length * * Return - * On exit, the RETURN REGISTER contains: - * - 0 if the call is successful. - * - –1 if an error occurs. - * - * The buffer pointed to by the PARAMETER REGISTER contains - * the filename, prefixed with a suitable directory name. - * If you use the same target identifier again, the same - * filename is returned. - * - * Note: The returned string must be null-terminated. + * On exit, the RETURN REGISTER contains the return status. */ + if (semihosting->user_command_extension) { + retval = semihosting->user_command_extension(target); + if (retval != ERROR_NOT_IMPLEMENTED) + break; + /* If custom user command not handled, we are looking for the TCL handler */ + } - default: - fprintf(stderr, "semihosting: unsupported call %#x\n", - (unsigned) semihosting->op); - semihosting->result = -1; - semihosting->sys_errno = ENOTSUP; + assert(!semihosting_user_op_params); + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read fields for user defined command" + " op=0x%x", semihosting->op); + return retval; + } + + uint64_t addr = semihosting_get_field(target, 0, fields); + + size_t len = semihosting_get_field(target, 1, fields); + if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) { + LOG_ERROR("The maximum length for user defined command " + "parameter is %u, received length is %zu (op=0x%x)", + SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH, + len, + semihosting->op); + return ERROR_FAIL; + } + + semihosting_user_op_params = malloc(len + 1); + if (!semihosting_user_op_params) + return ERROR_FAIL; + semihosting_user_op_params[len] = 0; + + retval = target_read_buffer(target, addr, len, + (uint8_t *)(semihosting_user_op_params)); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)", + semihosting->op, + semihosting_opcode_to_str(semihosting->op)); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + return retval; + } + + target_handle_event(target, semihosting->op); + free(semihosting_user_op_params); + semihosting_user_op_params = NULL; + semihosting->result = 0; + break; + + case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ + /* + * Returns the number of elapsed target ticks since execution + * started. + * Use SYS_TICKFREQ to determine the tick frequency. + * + * Entry (32-bit) + * On entry, the PARAMETER REGISTER points to a two-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The least significant field and is at the low address. + * - field 2 The most significant field and is at the high address. + * + * Entry (64-bit) + * On entry the PARAMETER REGISTER points to a one-field data + * block to be used for returning the number of elapsed ticks: + * - field 1 The number of elapsed ticks as a 64-bit value. + * + * Return + * On exit: + * - On success, the RETURN REGISTER contains 0, the PARAMETER + * REGISTER is unchanged, and the data block pointed to by the + * PARAMETER REGISTER is filled in with the number of elapsed + * ticks. + * - On failure, the RETURN REGISTER contains -1, and the + * PARAMETER REGISTER contains -1. + * + * Note: Some semihosting implementations might not support this + * semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + + case SEMIHOSTING_SYS_TICKFREQ: /* 0x31 */ + /* + * Returns the tick frequency. + * + * Entry + * The PARAMETER REGISTER must contain 0 on entry to this routine. + * + * Return + * On exit, the RETURN REGISTER contains either: + * - The number of ticks per second. + * - –1 if the target does not know the value of one tick. + * + * Note: Some semihosting implementations might not support + * this semihosting operation, and they always return -1 in the + * RETURN REGISTER. + */ + + case SEMIHOSTING_SYS_TMPNAM: /* 0x0D */ + /* + * Returns a temporary name for a file identified by a system + * file identifier. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * three-word argument block: + * - field 1 A pointer to a buffer. + * - field 2 A target identifier for this filename. Its value + * must be an integer in the range 0-255. + * - field 3 Contains the length of the buffer. The length must + * be at least the value of L_tmpnam on the host system. + * + * Return + * On exit, the RETURN REGISTER contains: + * - 0 if the call is successful. + * - –1 if an error occurs. + * + * The buffer pointed to by the PARAMETER REGISTER contains + * the filename, prefixed with a suitable directory name. + * If you use the same target identifier again, the same + * filename is returned. + * + * Note: The returned string must be null-terminated. + */ + + default: + fprintf(stderr, "semihosting: unsupported call %#x\n", + (unsigned int)semihosting->op); + semihosting->result = -1; + semihosting->sys_errno = ENOTSUP; } if (!semihosting->hit_fileio) { @@ -1690,18 +1685,18 @@ static int semihosting_common_fileio_end(struct target *target, int result, * below: */ switch (semihosting->op) { - case SEMIHOSTING_SYS_WRITE: /* 0x05 */ - case SEMIHOSTING_SYS_READ: /* 0x06 */ - if (result < 0) - semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ - else - semihosting->result = (int64_t)fileio_info->param_3 - result; - break; + case SEMIHOSTING_SYS_WRITE: /* 0x05 */ + case SEMIHOSTING_SYS_READ: /* 0x06 */ + if (result < 0) + semihosting->result = fileio_info->param_3; /* Zero bytes read/written. */ + else + semihosting->result = (int64_t)fileio_info->param_3 - result; + break; - case SEMIHOSTING_SYS_SEEK: /* 0x0a */ - if (result > 0) - semihosting->result = 0; - break; + case SEMIHOSTING_SYS_SEEK: /* 0x0a */ + if (result > 0) + semihosting->result = 0; + break; } bool fileio_failed = false; diff --git a/src/target/startup.tcl b/src/target/startup.tcl index e9646097f0..1cc9bb7fda 100644 --- a/src/target/startup.tcl +++ b/src/target/startup.tcl @@ -316,3 +316,9 @@ proc _post_init_target_cortex_a_cache_auto {} { } } lappend post_init_commands _post_init_target_cortex_a_cache_auto + +lappend _telnet_autocomplete_skip "cache_config l2x" +proc "cache_config l2x" {args} { + echo "DEPRECATED! use 'cache l2x conf' not 'cache_config l2x'" + eval cache_config l2x $args +} diff --git a/src/target/stm8.c b/src/target/stm8.c index 81c41f2b2a..05989eeb95 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -704,19 +704,19 @@ static int stm8_write_flash(struct target *target, enum mem_type type, int res; switch (type) { - case (FLASH): - stm8_unlock_flash(target); - break; - case (EEPROM): - stm8_unlock_eeprom(target); - break; - case (OPTION): - stm8_unlock_eeprom(target); - opt = OPT; - break; - default: - LOG_ERROR("BUG: wrong mem_type %d", type); - assert(0); + case FLASH: + stm8_unlock_flash(target); + break; + case EEPROM: + stm8_unlock_eeprom(target); + break; + case OPTION: + stm8_unlock_eeprom(target); + opt = OPT; + break; + default: + LOG_ERROR("BUG: wrong mem_type %d", type); + assert(0); } if (size == 2) { @@ -870,7 +870,7 @@ static int stm8_poll(struct target *target) uint8_t csr1, csr2; #ifdef LOG_STM8 - LOG_DEBUG("target->state=%d", target->state); + LOG_DEBUG("target->state %s", target_state_name(target)); #endif /* read dm_csrx control regs */ @@ -1094,11 +1094,11 @@ static int stm8_resume(struct target *target, bool current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target resumed at 0x%" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + LOG_DEBUG("target debug resumed at 0x%" PRIx32, resume_pc); } return ERROR_OK; @@ -1173,7 +1173,7 @@ static int stm8_read_core_reg(struct target *target, unsigned int num) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = stm8->core_regs[num]; - LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("read core reg %i value 0x%" PRIx32, num, reg_value); buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; @@ -1193,7 +1193,7 @@ static int stm8_write_core_reg(struct target *target, unsigned int num) reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32); stm8->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + LOG_DEBUG("write core reg %i value 0x%" PRIx32, num, reg_value); stm8->core_cache->reg_list[num].valid = true; stm8->core_cache->reg_list[num].dirty = false; @@ -1327,7 +1327,7 @@ static int stm8_arch_state(struct target *target) { struct stm8_common *stm8 = target_to_stm8(target); - LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32, debug_reason_name(target), buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); @@ -1438,7 +1438,7 @@ static int stm8_set_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; - LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { @@ -1601,17 +1601,17 @@ static int stm8_set_watchpoint(struct target *target, enum hw_break_type enable = 0; switch (watchpoint->rw) { - case WPT_READ: - enable = HWBRK_RD; - break; - case WPT_WRITE: - enable = HWBRK_WR; - break; - case WPT_ACCESS: - enable = HWBRK_ACC; - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable = HWBRK_RD; + break; + case WPT_WRITE: + enable = HWBRK_WR; + break; + case WPT_ACCESS: + enable = HWBRK_ACC; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } comparator_list[wp_num].used = true; @@ -1626,7 +1626,7 @@ static int stm8_set_watchpoint(struct target *target, watchpoint_set(watchpoint, wp_num); - LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32, wp_num, comparator_list[wp_num].bp_value); diff --git a/src/target/target.c b/src/target/target.c index 11252522d4..120103f7d0 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -71,45 +71,45 @@ static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); static struct target_type *target_types[] = { + // Keep in alphabetic order this list of targets + &aarch64_target, + &arcv2_target, + &arm11_target, + &arm720t_target, &arm7tdmi_target, - &arm9tdmi_target, &arm920t_target, - &arm720t_target, - &arm966e_target, - &arm946e_target, &arm926ejs_target, - &fa526_target, - &feroceon_target, - &dragonite_target, - &xscale_target, - &xtensa_chip_target, - &cortexm_target, + &arm946e_target, + &arm966e_target, + &arm9tdmi_target, + &armv8r_target, + &avr32_ap7k_target, + &avr_target, &cortexa_target, + &cortexm_target, &cortexr4_target, - &arm11_target, - &ls1_sap_target, - &mips_m4k_target, - &avr_target, + &dragonite_target, &dsp563xx_target, &dsp5680xx_target, - &testee_target, - &avr32_ap7k_target, - &hla_target, - &esp32_target, + &esirisc_target, &esp32s2_target, &esp32s3_target, + &esp32_target, + &fa526_target, + &feroceon_target, + &hla_target, + &ls1_sap_target, + &mem_ap_target, + &mips_m4k_target, + &mips_mips64_target, &or1k_target, - &quark_x10xx_target, &quark_d20xx_target, - &stm8_target, + &quark_x10xx_target, &riscv_target, - &mem_ap_target, - &esirisc_target, - &arcv2_target, - &aarch64_target, - &armv8r_target, - &mips_mips64_target, - NULL, + &stm8_target, + &testee_target, + &xscale_target, + &xtensa_chip_target, }; struct target *all_targets; @@ -650,9 +650,9 @@ static int identity_virt2phys(struct target *target, return ERROR_OK; } -static int no_mmu(struct target *target, int *enabled) +static int no_mmu(struct target *target, bool *enabled) { - *enabled = 0; + *enabled = false; return ERROR_OK; } @@ -1983,7 +1983,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w /* Reevaluate working area address based on MMU state*/ if (!target->working_areas) { int retval; - int enabled; + bool enabled; retval = target->type->mmu(target, &enabled); if (retval != ERROR_OK) @@ -2549,7 +2549,7 @@ int target_read_u64(struct target *target, target_addr_t address, uint64_t *valu if (retval == ERROR_OK) { *value = target_buffer_get_u64(target, value_buf); - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, *value); } else { @@ -2573,7 +2573,7 @@ int target_read_u32(struct target *target, target_addr_t address, uint32_t *valu if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, *value); } else { @@ -2640,7 +2640,7 @@ int target_write_u64(struct target *target, target_addr_t address, uint64_t valu return ERROR_FAIL; } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, value); @@ -2661,7 +2661,7 @@ int target_write_u32(struct target *target, target_addr_t address, uint32_t valu return ERROR_FAIL; } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, value); @@ -2721,7 +2721,7 @@ int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t return ERROR_FAIL; } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64, address, value); @@ -2742,7 +2742,7 @@ int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t return ERROR_FAIL; } - LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32, address, value); @@ -3212,8 +3212,6 @@ COMMAND_HANDLER(handle_wait_halt_command) /* wait for target state to change. The trick here is to have a low * latency for short waits and not to suck up all the CPU time * on longer waits. - * - * After 500ms, keep_alive() is invoked */ int target_wait_state(struct target *target, enum target_state state, unsigned int ms) { @@ -3235,8 +3233,7 @@ int target_wait_state(struct target *target, enum target_state state, unsigned i nvp_value2name(nvp_target_state, state)->name); } - if (cur - then > 500) - keep_alive(); + keep_alive(); if ((cur-then) > ms) { LOG_ERROR("timed out while waiting for target %s", @@ -3554,20 +3551,20 @@ COMMAND_HANDLER(handle_mw_command) struct target *target = get_current_target(CMD_CTX); unsigned int wordsize; switch (CMD_NAME[2]) { - case 'd': - wordsize = 8; - break; - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'd': + wordsize = 8; + break; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_mem(target, address, fn, wordsize, value, count); @@ -3960,7 +3957,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, retval = context_breakpoint_add(target, asid, length, hw); /* error is always logged in context_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) - command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); + command_print(cmd, "Context breakpoint set at 0x%8.8" PRIx32, asid); } else { if (!target->type->add_hybrid_breakpoint) { @@ -3970,7 +3967,7 @@ static int handle_bp_command_set(struct command_invocation *cmd, retval = hybrid_breakpoint_add(target, addr, asid, length, hw); /* error is always logged in hybrid_breakpoint_add(), do not print it again */ if (retval == ERROR_OK) - command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); + command_print(cmd, "Hybrid breakpoint set at 0x%8.8" PRIx32, asid); } return retval; } @@ -3983,39 +3980,39 @@ COMMAND_HANDLER(handle_bp_command) int hw = BKPT_SOFT; switch (CMD_ARGC) { - case 0: - return handle_bp_command_list(CMD); + case 0: + return handle_bp_command_list(CMD); - case 2: - asid = 0; + case 2: + asid = 0; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + return handle_bp_command_set(CMD, addr, asid, length, hw); + + case 3: + if (strcmp(CMD_ARGV[2], "hw") == 0) { + hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + asid = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); - - case 3: - if (strcmp(CMD_ARGV[2], "hw") == 0) { - hw = BKPT_HARD; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - asid = 0; - return handle_bp_command_set(CMD, addr, asid, length, hw); - } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { - hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - addr = 0; - return handle_bp_command_set(CMD, addr, asid, length, hw); - } - /* fallthrough */ - case 4: + } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { hw = BKPT_HARD; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + addr = 0; return handle_bp_command_set(CMD, addr, asid, length, hw); + } + /* fallthrough */ + case 4: + hw = BKPT_HARD; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); + return handle_bp_command_set(CMD, addr, asid, length, hw); - default: - return ERROR_COMMAND_SYNTAX_ERROR; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -4650,11 +4647,18 @@ COMMAND_HANDLER(handle_target_write_memory) */ void target_handle_event(struct target *target, enum target_event e) { - struct target_event_action *teap; + struct target_event_action *teap, *tmp; int retval; - list_for_each_entry(teap, &target->events_action, list) { + list_for_each_entry_safe(teap, tmp, &target->events_action, list) { if (teap->event == e) { + /* + * The event can be destroyed by its own handler. + * Make a local copy and use it in place of the original. + */ + struct target_event_action local_teap = *teap; + teap = &local_teap; + LOG_DEBUG("target: %s (%s) event: %d (%s) action: %s", target_name(target), target_type_name(target), @@ -4670,7 +4674,13 @@ void target_handle_event(struct target *target, enum target_event e) struct target *saved_target_override = cmd_ctx->current_target_override; cmd_ctx->current_target_override = target; + /* + * The event can be destroyed by its own handler. + * Prevent the body to get deallocated by Jim. + */ + Jim_IncrRefCount(teap->body); retval = Jim_EvalObj(teap->interp, teap->body); + Jim_DecrRefCount(teap->interp, teap->body); cmd_ctx->current_target_override = saved_target_override; @@ -4719,7 +4729,7 @@ COMMAND_HANDLER(handle_target_get_reg) const char *reg_name = Jim_String(elem); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, true); if (!reg || !reg->exist) { command_print(CMD, "unknown register '%s'", reg_name); @@ -4777,7 +4787,7 @@ COMMAND_HANDLER(handle_set_reg_command) for (unsigned int i = 0; i < length; i += 2) { const char *reg_name = Jim_String(dict[i]); const char *reg_value = Jim_String(dict[i + 1]); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, true); if (!reg || !reg->exist) { command_print(CMD, "unknown register '%s'", reg_name); @@ -4873,16 +4883,18 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde goi.is_configure = is_configure; int e = (*target->type->target_jim_configure)(target, &goi); index = CMD_ARGC - goi.argc; + + int reslen; + const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); + if (reslen > 0) + command_print(CMD, "%s", result); + if (e == JIM_OK) { /* more? */ continue; } if (e == JIM_ERR) { /* An error */ - int reslen; - const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); - if (reslen > 0) - command_print(CMD, "%s", result); return ERROR_FAIL; } /* otherwise we 'continue' below */ @@ -4908,7 +4920,8 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde case TCFG_EVENT: if (index == CMD_ARGC) { - command_print(CMD, "missing event-name"); + command_print(CMD, "expecting %s event-name event-body", + CMD_ARGV[index - 1]); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -4921,7 +4934,8 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde if (is_configure) { if (index == CMD_ARGC) { - command_print(CMD, "missing event-body"); + command_print(CMD, "expecting %s %s event-body", + CMD_ARGV[index - 2], CMD_ARGV[index - 1]); return ERROR_COMMAND_ARGUMENT_INVALID; } } @@ -5160,17 +5174,10 @@ static COMMAND_HELPER(target_configure, struct target *target, unsigned int inde command_print(CMD, "missing argument to %s", CMD_ARGV[index - 1]); return ERROR_COMMAND_ARGUMENT_INVALID; } - struct jim_getopt_info goi; - jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, CMD_JIMTCL_ARGV + index); + retval = rtos_create(CMD, target, CMD_ARGV[index]); + if (retval != ERROR_OK) + return retval; index++; - goi.is_configure = true; - int resval = rtos_create(&goi, target); - int reslen; - const char *result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen); - if (reslen > 0) - command_print(CMD, "%s", result); - if (resval != JIM_OK) - return ERROR_FAIL; } else { if (index != CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; @@ -5693,9 +5700,8 @@ static const struct command_registration target_instance_command_handlers[] = { COMMAND_HANDLER(handle_target_create) { int retval = ERROR_OK; - int x; - if (CMD_ARGC < 4) + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* check if the target name clashes with an existing command name */ @@ -5717,15 +5723,16 @@ COMMAND_HANDLER(handle_target_create) LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); } /* now does target type exist */ - for (x = 0 ; target_types[x] ; x++) { + size_t x; + for (x = 0 ; x < ARRAY_SIZE(target_types) ; x++) { if (strcmp(cp, target_types[x]->name) == 0) { /* found */ break; } } - if (!target_types[x]) { + if (x == ARRAY_SIZE(target_types)) { char *all = NULL; - for (x = 0 ; target_types[x] ; x++) { + for (x = 0 ; x < ARRAY_SIZE(target_types) ; x++) { char *prev = all; if (all) all = alloc_printf("%s, %s", all, target_types[x]->name); @@ -5927,7 +5934,7 @@ COMMAND_HANDLER(handle_target_types) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned int x = 0; target_types[x]; x++) + for (size_t x = 0; x < ARRAY_SIZE(target_types); x++) command_print(CMD, "%s", target_types[x]->name); return ERROR_OK; @@ -6040,7 +6047,7 @@ static const struct command_registration target_subcommand_handlers[] = { .name = "create", .mode = COMMAND_CONFIG, .handler = handle_target_create, - .usage = "name type '-chain-position' name [options ...]", + .usage = "name type [options ...]", .help = "Creates and selects a new target", }, { @@ -6762,25 +6769,25 @@ static int target_register_user_commands(struct command_context *cmd_ctx) const char *target_debug_reason_str(enum target_debug_reason reason) { switch (reason) { - case DBG_REASON_DBGRQ: - return "DBGRQ"; - case DBG_REASON_BREAKPOINT: - return "BREAKPOINT"; - case DBG_REASON_WATCHPOINT: - return "WATCHPOINT"; - case DBG_REASON_WPTANDBKPT: - return "WPTANDBKPT"; - case DBG_REASON_SINGLESTEP: - return "SINGLESTEP"; - case DBG_REASON_NOTHALTED: - return "NOTHALTED"; - case DBG_REASON_EXIT: - return "EXIT"; - case DBG_REASON_EXC_CATCH: - return "EXC_CATCH"; - case DBG_REASON_UNDEFINED: - return "UNDEFINED"; - default: - return "UNKNOWN!"; + case DBG_REASON_DBGRQ: + return "DBGRQ"; + case DBG_REASON_BREAKPOINT: + return "BREAKPOINT"; + case DBG_REASON_WATCHPOINT: + return "WATCHPOINT"; + case DBG_REASON_WPTANDBKPT: + return "WPTANDBKPT"; + case DBG_REASON_SINGLESTEP: + return "SINGLESTEP"; + case DBG_REASON_NOTHALTED: + return "NOTHALTED"; + case DBG_REASON_EXIT: + return "EXIT"; + case DBG_REASON_EXC_CATCH: + return "EXC_CATCH"; + case DBG_REASON_UNDEFINED: + return "UNDEFINED"; + default: + return "UNKNOWN!"; } } diff --git a/src/target/target_request.c b/src/target/target_request.c index 8d51dc3d60..11586a696f 100644 --- a/src/target/target_request.c +++ b/src/target/target_request.c @@ -74,15 +74,15 @@ static int target_hexmsg(struct target *target, int size, uint32_t length) line_len = 0; for (i = 0; i < length; i++) { switch (size) { - case 4: - line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4*i))); - break; - case 2: - line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i))); - break; - case 1: - line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); - break; + case 4: + line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4 * i))); + break; + case 2: + line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2 * i))); + break; + case 1: + line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); + break; } if ((i%8 == 7) || (i == length - 1)) { @@ -120,24 +120,24 @@ int target_request(struct target *target, uint32_t request) } switch (target_req_cmd) { - case TARGET_REQ_TRACEMSG: - trace_point(target, (request & 0xffffff00) >> 8); - break; - case TARGET_REQ_DEBUGMSG: - if (((request & 0xff00) >> 8) == 0) - target_asciimsg(target, (request & 0xffff0000) >> 16); - else - target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); - break; - case TARGET_REQ_DEBUGCHAR: - target_charmsg(target, (request & 0x00ff0000) >> 16); - break; -/* case TARGET_REQ_SEMIHOSTING: - * break; + case TARGET_REQ_TRACEMSG: + trace_point(target, (request & 0xffffff00) >> 8); + break; + case TARGET_REQ_DEBUGMSG: + if (((request & 0xff00) >> 8) == 0) + target_asciimsg(target, (request & 0xffff0000) >> 16); + else + target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); + break; + case TARGET_REQ_DEBUGCHAR: + target_charmsg(target, (request & 0x00ff0000) >> 16); + break; +/* case TARGET_REQ_SEMIHOSTING: + * break; */ - default: - LOG_ERROR("unknown target request: %2.2x", target_req_cmd); - break; + default: + LOG_ERROR("unknown target request: %2.2x", target_req_cmd); + break; } return ERROR_OK; diff --git a/src/target/target_type.h b/src/target/target_type.h index eddedbf34f..ccbe03a476 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -201,10 +201,6 @@ struct target_type { /* otherwise: JIM_OK, or JIM_ERR, */ int (*target_jim_configure)(struct target *target, struct jim_getopt_info *goi); - /* target commands specifically handled by the target */ - /* returns JIM_OK, or JIM_ERR, or JIM_CONTINUE - if option not understood */ - int (*target_jim_commands)(struct target *target, struct jim_getopt_info *goi); - /** * This method is used to perform target setup that requires * JTAG access. @@ -268,7 +264,7 @@ struct target_type { int (*write_phys_memory)(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); - int (*mmu)(struct target *target, int *enabled); + int (*mmu)(struct target *target, bool *enabled); /* after reset is complete, the target can check if things are properly set up. * @@ -311,6 +307,7 @@ struct target_type { unsigned int (*data_bits)(struct target *target); }; +// Keep in alphabetic order this list of targets extern struct target_type aarch64_target; extern struct target_type arcv2_target; extern struct target_type arm11_target; diff --git a/src/target/trace.c b/src/target/trace.c index 333a787f92..a92fd27bf4 100644 --- a/src/target/trace.c +++ b/src/target/trace.c @@ -115,7 +115,7 @@ COMMAND_HANDLER(handle_trace_history_command) if (trace->trace_history[i % trace->trace_history_size] < trace->num_trace_points) { uint32_t address; address = trace->trace_points[trace->trace_history[i % trace->trace_history_size]].address; - command_print(CMD, "trace point %i: 0x%8.8" PRIx32 "", + command_print(CMD, "trace point %i: 0x%8.8" PRIx32, (int)(trace->trace_history[i % trace->trace_history_size]), address); } else diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index 8cca9a5e91..8ad9d00fec 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -96,7 +96,7 @@ int x86_32_common_init_arch_info(struct target *t, struct x86_32_common *x86_32) return ERROR_OK; } -int x86_32_common_mmu(struct target *t, int *enabled) +int x86_32_common_mmu(struct target *t, bool *enabled) { *enabled = true; return ERROR_OK; @@ -331,27 +331,27 @@ static int read_mem(struct target *t, uint32_t size, } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDB32); - else - retval = x86_32->submit_instruction(t, MEMRDB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDH32); - else - retval = x86_32->submit_instruction(t, MEMRDH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMRDW32); - else - retval = x86_32->submit_instruction(t, MEMRDW16); - break; - default: - LOG_ERROR("%s invalid read mem size", __func__); - break; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDB32); + else + retval = x86_32->submit_instruction(t, MEMRDB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDH32); + else + retval = x86_32->submit_instruction(t, MEMRDH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMRDW32); + else + retval = x86_32->submit_instruction(t, MEMRDW16); + break; + default: + LOG_ERROR("%s invalid read mem size", __func__); + break; } if (retval != ERROR_OK) @@ -407,27 +407,27 @@ static int write_mem(struct target *t, uint32_t size, return retval; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRB32); - else - retval = x86_32->submit_instruction(t, MEMWRB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRH32); - else - retval = x86_32->submit_instruction(t, MEMWRH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, MEMWRW32); - else - retval = x86_32->submit_instruction(t, MEMWRW16); - break; - default: - LOG_ERROR("%s invalid write mem size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRB32); + else + retval = x86_32->submit_instruction(t, MEMWRB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRH32); + else + retval = x86_32->submit_instruction(t, MEMWRH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, MEMWRW32); + else + retval = x86_32->submit_instruction(t, MEMWRW16); + break; + default: + LOG_ERROR("%s invalid write mem size", __func__); + return ERROR_FAIL; } if (retval != ERROR_OK) @@ -706,27 +706,27 @@ static int x86_32_common_read_io(struct target *t, uint32_t addr, pg_disabled = true; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, IORDB32); - else - retval = x86_32->submit_instruction(t, IORDB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, IORDH32); - else - retval = x86_32->submit_instruction(t, IORDH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, IORDW32); - else - retval = x86_32->submit_instruction(t, IORDW16); - break; - default: - LOG_ERROR("%s invalid read io size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, IORDB32); + else + retval = x86_32->submit_instruction(t, IORDB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, IORDH32); + else + retval = x86_32->submit_instruction(t, IORDH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, IORDW32); + else + retval = x86_32->submit_instruction(t, IORDW16); + break; + default: + LOG_ERROR("%s invalid read io size", __func__); + return ERROR_FAIL; } /* restore CR0.PG bit if needed */ @@ -795,27 +795,27 @@ int x86_32_common_write_io(struct target *t, uint32_t addr, pg_disabled = true; } switch (size) { - case BYTE: - if (use32) - retval = x86_32->submit_instruction(t, IOWRB32); - else - retval = x86_32->submit_instruction(t, IOWRB16); - break; - case WORD: - if (use32) - retval = x86_32->submit_instruction(t, IOWRH32); - else - retval = x86_32->submit_instruction(t, IOWRH16); - break; - case DWORD: - if (use32) - retval = x86_32->submit_instruction(t, IOWRW32); - else - retval = x86_32->submit_instruction(t, IOWRW16); - break; - default: - LOG_ERROR("%s invalid write io size", __func__); - return ERROR_FAIL; + case BYTE: + if (use32) + retval = x86_32->submit_instruction(t, IOWRB32); + else + retval = x86_32->submit_instruction(t, IOWRB16); + break; + case WORD: + if (use32) + retval = x86_32->submit_instruction(t, IOWRH32); + else + retval = x86_32->submit_instruction(t, IOWRH16); + break; + case DWORD: + if (use32) + retval = x86_32->submit_instruction(t, IOWRW32); + else + retval = x86_32->submit_instruction(t, IOWRW16); + break; + default: + LOG_ERROR("%s invalid write io size", __func__); + return ERROR_FAIL; } /* restore CR0.PG bit if needed */ @@ -899,29 +899,29 @@ static int set_debug_regs(struct target *t, uint32_t address, } switch (bp_type) { - case 0: - /* 00 - only on instruction execution */ - DR7_SET_EXE(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - case 1: - /* 01 - only on data writes */ - DR7_SET_WRITE(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - case 2: - /* 10 UNSUPPORTED - an I/O read and I/O write */ - LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type); - return ERROR_FAIL; - break; - case 3: - /* on data read or data write */ - DR7_SET_ACCESS(dr7, bp_num); - DR7_SET_LENGTH(dr7, bp_num, bp_length); - break; - default: - LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type); - return ERROR_FAIL; + case 0: + /* 00 - only on instruction execution */ + DR7_SET_EXE(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + case 1: + /* 01 - only on data writes */ + DR7_SET_WRITE(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + case 2: + /* 10 UNSUPPORTED - an I/O read and I/O write */ + LOG_ERROR("%s unsupported feature bp_type=%d", __func__, bp_type); + return ERROR_FAIL; + break; + case 3: + /* on data read or data write */ + DR7_SET_ACCESS(dr7, bp_num); + DR7_SET_LENGTH(dr7, bp_num, bp_length); + break; + default: + LOG_ERROR("%s invalid request [only 0-3] bp_type=%d", __func__, bp_type); + return ERROR_FAIL; } /* update regs in the reg cache ready to be written to hardware @@ -1027,7 +1027,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) if (read_phys_mem(t, physaddr, 1, 1, bp->orig_instr)) return ERROR_FAIL; - LOG_DEBUG("set software breakpoint - orig byte=0x%02" PRIx8 "", *bp->orig_instr); + LOG_DEBUG("set software breakpoint - orig byte=0x%02" PRIx8, *bp->orig_instr); /* just write the instruction trap byte */ if (write_phys_mem(t, physaddr, 1, 1, &opcode)) @@ -1040,7 +1040,7 @@ static int set_swbp(struct target *t, struct breakpoint *bp) if (readback != SW_BP_OPCODE) { LOG_ERROR("%s software breakpoint error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); - LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8 "", + LOG_ERROR("%s readback=0x%02" PRIx8 " orig=0x%02" PRIx8, __func__, readback, *bp->orig_instr); return ERROR_FAIL; } @@ -1089,7 +1089,7 @@ static int unset_swbp(struct target *t, struct breakpoint *bp) } else { LOG_ERROR("%s software breakpoint remove error at " TARGET_ADDR_FMT ", check memory", __func__, bp->address); - LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8 "", + LOG_ERROR("%s current=0x%02" PRIx8 " orig=0x%02" PRIx8, __func__, current_instr, *bp->orig_instr); return ERROR_FAIL; } @@ -1206,21 +1206,19 @@ static int set_watchpoint(struct target *t, struct watchpoint *wp) } switch (wp->rw) { - case WPT_WRITE: - if (set_debug_regs(t, wp->address, wp_num, - DR7_BP_WRITE, wp->length) != ERROR_OK) { - return ERROR_FAIL; - } - break; - case WPT_ACCESS: - if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE, - wp->length) != ERROR_OK) { - return ERROR_FAIL; - } - break; - default: - LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); - break; + case WPT_WRITE: + if (set_debug_regs(t, wp->address, wp_num, + DR7_BP_WRITE, wp->length) != ERROR_OK) + return ERROR_FAIL; + break; + case WPT_ACCESS: + if (set_debug_regs(t, wp->address, wp_num, DR7_BP_READWRITE, + wp->length) != ERROR_OK) + return ERROR_FAIL; + break; + default: + LOG_ERROR("%s only 'access' or 'write' watchpoints are supported", __func__); + break; } watchpoint_set(wp, wp_num); debug_reg_list[wp_num].used = 1; @@ -1460,17 +1458,17 @@ COMMAND_HANDLER(handle_iow_command) unsigned int wordsize; switch (CMD_NAME[2]) { - case 'w': - wordsize = 4; - break; - case 'h': - wordsize = 2; - break; - case 'b': - wordsize = 1; - break; - default: - return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + wordsize = 4; + break; + case 'h': + wordsize = 2; + break; + case 'b': + wordsize = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_io(target, address, wordsize, value); } diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h index e232747697..7e8672ea00 100644 --- a/src/target/x86_32_common.h +++ b/src/target/x86_32_common.h @@ -299,7 +299,7 @@ int x86_32_get_gdb_reg_list(struct target *t, enum target_register_class reg_class); int x86_32_common_init_arch_info(struct target *target, struct x86_32_common *x86_32); -int x86_32_common_mmu(struct target *t, int *enabled); +int x86_32_common_mmu(struct target *t, bool *enabled); int x86_32_common_virt2phys(struct target *t, target_addr_t address, target_addr_t *physical); int x86_32_common_read_phys_mem(struct target *t, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); diff --git a/src/target/xscale.c b/src/target/xscale.c index 84318a905f..712db4ee2a 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -22,6 +22,7 @@ #include "arm_simulator.h" #include "arm_disassembler.h" #include +#include #include "register.h" #include "image.h" #include "arm_opcodes.h" @@ -399,7 +400,7 @@ static int xscale_read_tx(struct target *target, int consume) } if (!((!(field0_in & 1)) && consume)) goto done; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else @@ -470,7 +471,7 @@ static int xscale_write_rx(struct target *target) } if (!(field0_in & 1)) goto done; - if (debug_level >= 3) { + if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else @@ -516,24 +517,24 @@ static int xscale_send(struct target *target, const uint8_t *buffer, int count, uint32_t t; switch (size) { - case 4: - if (endianness == TARGET_LITTLE_ENDIAN) - t = le_to_h_u32(buffer); - else - t = be_to_h_u32(buffer); - break; - case 2: - if (endianness == TARGET_LITTLE_ENDIAN) - t = le_to_h_u16(buffer); - else - t = be_to_h_u16(buffer); - break; - case 1: - t = buffer[0]; - break; - default: - LOG_ERROR("BUG: size neither 4, 2 nor 1"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 4: + if (endianness == TARGET_LITTLE_ENDIAN) + t = le_to_h_u32(buffer); + else + t = be_to_h_u32(buffer); + break; + case 2: + if (endianness == TARGET_LITTLE_ENDIAN) + t = le_to_h_u16(buffer); + else + t = be_to_h_u16(buffer); + break; + case 1: + t = buffer[0]; + break; + default: + LOG_ERROR("BUG: size neither 4, 2 nor 1"); + return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(t1, 0, 32, t); @@ -639,7 +640,7 @@ static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8] int word; struct scan_field fields[2]; - LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32 "", va); + LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32, va); /* LDIC into IR */ xscale_jtag_set_instr(target->tap, @@ -774,10 +775,6 @@ static int xscale_arch_state(struct target *target) struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; - static const char *state[] = { - "disabled", "enabled" - }; - static const char *arch_dbg_reason[] = { "", "\n(processor reset)", "\n(trace buffer full)" }; @@ -789,9 +786,9 @@ static int xscale_arch_state(struct target *target) arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s%s", - state[xscale->armv4_5_mmu.mmu_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], - state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], + str_enabled_disabled(xscale->armv4_5_mmu.mmu_enabled), + str_enabled_disabled(xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled), + str_enabled_disabled(xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled), arch_dbg_reason[xscale->arch_debug_reason]); return ERROR_OK; @@ -859,24 +856,24 @@ static int xscale_debug_entry(struct target *target) buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, buffer[0]); arm->core_cache->reg_list[0].dirty = true; arm->core_cache->reg_list[0].valid = true; - LOG_DEBUG("r0: 0x%8.8" PRIx32 "", buffer[0]); + LOG_DEBUG("r0: 0x%8.8" PRIx32, buffer[0]); /* move pc from buffer to register cache */ buf_set_u32(arm->pc->value, 0, 32, buffer[1]); arm->pc->dirty = true; arm->pc->valid = true; - LOG_DEBUG("pc: 0x%8.8" PRIx32 "", buffer[1]); + LOG_DEBUG("pc: 0x%8.8" PRIx32, buffer[1]); /* move data from buffer to register cache */ for (i = 1; i <= 7; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); arm->core_cache->reg_list[i].dirty = true; arm->core_cache->reg_list[i].valid = true; - LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, buffer[i + 1]); + LOG_DEBUG("r%i: 0x%8.8" PRIx32, i, buffer[i + 1]); } arm_set_cpsr(arm, buffer[9]); - LOG_DEBUG("cpsr: 0x%8.8" PRIx32 "", buffer[9]); + LOG_DEBUG("cpsr: 0x%8.8" PRIx32, buffer[9]); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; @@ -919,46 +916,46 @@ static int xscale_debug_entry(struct target *target) pc = buf_get_u32(arm->pc->value, 0, 32); switch (moe) { - case 0x0: /* Processor reset */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; - pc -= 4; - break; - case 0x1: /* Instruction breakpoint hit */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x2: /* Data breakpoint hit */ - target->debug_reason = DBG_REASON_WATCHPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x3: /* BKPT instruction executed */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x4: /* Ext. debug event */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x5: /* Vector trap occurred */ - target->debug_reason = DBG_REASON_BREAKPOINT; - xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; - pc -= 4; - break; - case 0x6: /* Trace buffer full break */ - target->debug_reason = DBG_REASON_DBGRQ; - xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; - pc -= 4; - break; - case 0x7: /* Reserved (may flag Hot-Debug support) */ - default: - LOG_ERROR("Method of Entry is 'Reserved'"); - exit(-1); - break; + case 0x0: /* Processor reset */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; + pc -= 4; + break; + case 0x1: /* Instruction breakpoint hit */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x2: /* Data breakpoint hit */ + target->debug_reason = DBG_REASON_WATCHPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x3: /* BKPT instruction executed */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x4: /* Ext. debug event */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x5: /* Vector trap occurred */ + target->debug_reason = DBG_REASON_BREAKPOINT; + xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; + pc -= 4; + break; + case 0x6: /* Trace buffer full break */ + target->debug_reason = DBG_REASON_DBGRQ; + xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; + pc -= 4; + break; + case 0x7: /* Reserved (may flag Hot-Debug support) */ + default: + LOG_ERROR("Method of Entry is 'Reserved'"); + exit(-1); + break; } /* apply PC fixup */ @@ -982,11 +979,11 @@ static int xscale_debug_entry(struct target *target) xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); - xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; + xscale->armv4_5_mmu.mmu_enabled = xscale->cp15_control_reg & 0x1U; xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = - (xscale->cp15_control_reg & 0x4U) ? 1 : 0; + xscale->cp15_control_reg & 0x4U; xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = - (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; + xscale->cp15_control_reg & 0x1000U; /* tracing enabled, read collected trace data */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { @@ -1162,7 +1159,7 @@ static int xscale_resume(struct target *target, bool current, uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); } @@ -1187,7 +1184,7 @@ static int xscale_resume(struct target *target, bool current, /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1251,7 +1248,7 @@ static int xscale_resume(struct target *target, bool current, for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1296,7 +1293,7 @@ static int xscale_step_inner(struct target *target, bool current, target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( - "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", + "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32, current_opcode); return retval; } @@ -1340,7 +1337,7 @@ static int xscale_step_inner(struct target *target, bool current, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); if (retval != ERROR_OK) return retval; - LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, + LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32, i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } @@ -1818,20 +1815,20 @@ static int xscale_read_memory(struct target *target, target_addr_t address, /* extract data from host-endian buffer into byte stream */ for (i = 0; i < count; i++) { switch (size) { - case 4: - target_buffer_set_u32(target, buffer, buf32[i]); - buffer += 4; - break; - case 2: - target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); - buffer += 2; - break; - case 1: - *buffer++ = buf32[i] & 0xff; - break; - default: - LOG_ERROR("invalid read size"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 4: + target_buffer_set_u32(target, buffer, buf32[i]); + buffer += 4; + break; + case 2: + target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); + buffer += 2; + break; + case 1: + *buffer++ = buf32[i] & 0xff; + break; + default: + LOG_ERROR("invalid read size"); + return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -1910,24 +1907,24 @@ static int xscale_write_memory(struct target *target, target_addr_t address, #if 0 for (i = 0; i < count; i++) { switch (size) { - case 4: - value = target_buffer_get_u32(target, buffer); - xscale_send_u32(target, value); - buffer += 4; - break; - case 2: - value = target_buffer_get_u16(target, buffer); - xscale_send_u32(target, value); - buffer += 2; - break; - case 1: - value = *buffer; - xscale_send_u32(target, value); - buffer += 1; - break; - default: - LOG_ERROR("should never get here"); - exit(-1); + case 4: + value = target_buffer_get_u32(target, buffer); + xscale_send_u32(target, value); + buffer += 4; + break; + case 2: + value = target_buffer_get_u16(target, buffer); + xscale_send_u32(target, value); + buffer += 2; + break; + case 1: + value = *buffer; + xscale_send_u32(target, value); + buffer += 1; + break; + default: + LOG_ERROR("should never get here"); + exit(-1); } } #endif @@ -2237,17 +2234,17 @@ static int xscale_set_watchpoint(struct target *target, } switch (watchpoint->rw) { - case WPT_READ: - enable = 0x3; - break; - case WPT_ACCESS: - enable = 0x2; - break; - case WPT_WRITE: - enable = 0x1; - break; - default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + case WPT_READ: + enable = 0x3; + break; + case WPT_ACCESS: + enable = 0x2; + break; + case WPT_WRITE: + enable = 0x1; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } /* For watchpoint across more than one word, both DBR registers must @@ -2688,61 +2685,60 @@ static int xscale_analyze_trace(struct target *target, struct command_invocation continue; switch (trace_msg_type) { - case 0: /* Exceptions */ - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - exception = (trace_data->entries[i].data & 0x70) >> 4; - - /* FIXME: vector table may be at ffff0000 */ - branch_target = (trace_data->entries[i].data & 0xf0) >> 2; - break; - - case 8: /* Direct Branch */ - break; - - case 9: /* Indirect Branch */ - xscale_branch_address(trace_data, i, &branch_target); - break; - - case 13: /* Checkpointed Indirect Branch */ - xscale_branch_address(trace_data, i, &branch_target); - if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) - chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is - *oldest */ - else - chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and - *newest */ - - chkpt++; - break; - - case 12: /* Checkpointed Direct Branch */ - if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) - chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is - *oldest */ - else - chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and - *newest */ - - /* if no current_pc, checkpoint will be starting point */ - if (current_pc == 0) - branch_target = chkpt_reg; + case 0: /* Exceptions */ + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + exception = (trace_data->entries[i].data & 0x70) >> 4; - chkpt++; - break; + /* FIXME: vector table may be at ffff0000 */ + branch_target = (trace_data->entries[i].data & 0xf0) >> 2; + break; - case 15:/* Roll-over */ - break; + case 8: /* Direct Branch */ + break; - default:/* Reserved */ - LOG_WARNING("trace is suspect: invalid trace message byte"); - continue; + case 9: /* Indirect Branch */ + xscale_branch_address(trace_data, i, &branch_target); + break; + + case 13: /* Checkpointed Indirect Branch */ + xscale_branch_address(trace_data, i, &branch_target); + if (trace_data->num_checkpoints == 2 && chkpt == 0) + chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is + *oldest */ + else + chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and + *newest */ + chkpt++; + break; + + case 12: /* Checkpointed Direct Branch */ + if (trace_data->num_checkpoints == 2 && chkpt == 0) + chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is + *oldest */ + else + chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and + *newest */ + + /* if no current_pc, checkpoint will be starting point */ + if (current_pc == 0) + branch_target = chkpt_reg; + + chkpt++; + break; + + case 15:/* Roll-over */ + break; + + default:/* Reserved */ + LOG_WARNING("trace is suspect: invalid trace message byte"); + continue; } /* If we don't have the current_pc yet, but we did get the branch target @@ -3007,7 +3003,7 @@ static int xscale_init_arch_info(struct target *target, xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; xscale->armv4_5_mmu.has_tiny_pages = 1; - xscale->armv4_5_mmu.mmu_enabled = 0; + xscale->armv4_5_mmu.mmu_enabled = false; return ERROR_OK; } @@ -3126,7 +3122,7 @@ static int xscale_virt2phys(struct target *target, return ERROR_OK; } -static int xscale_mmu(struct target *target, int *enabled) +static int xscale_mmu(struct target *target, bool *enabled) { struct xscale_common *xscale = target_to_xscale(target); @@ -3523,33 +3519,33 @@ COMMAND_HANDLER(xscale_handle_cp15) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg_no); /*translate from xscale cp15 register no to openocd register*/ switch (reg_no) { - case 0: - reg_no = XSCALE_MAINID; - break; - case 1: - reg_no = XSCALE_CTRL; - break; - case 2: - reg_no = XSCALE_TTB; - break; - case 3: - reg_no = XSCALE_DAC; - break; - case 5: - reg_no = XSCALE_FSR; - break; - case 6: - reg_no = XSCALE_FAR; - break; - case 13: - reg_no = XSCALE_PID; - break; - case 15: - reg_no = XSCALE_CPACCESS; - break; - default: - command_print(CMD, "invalid register number"); - return ERROR_COMMAND_SYNTAX_ERROR; + case 0: + reg_no = XSCALE_MAINID; + break; + case 1: + reg_no = XSCALE_CTRL; + break; + case 2: + reg_no = XSCALE_TTB; + break; + case 3: + reg_no = XSCALE_DAC; + break; + case 5: + reg_no = XSCALE_FSR; + break; + case 6: + reg_no = XSCALE_FAR; + break; + case 13: + reg_no = XSCALE_PID; + break; + case 15: + reg_no = XSCALE_CPACCESS; + break; + default: + command_print(CMD, "invalid register number"); + return ERROR_COMMAND_SYNTAX_ERROR; } reg = &xscale->reg_cache->reg_list[reg_no]; @@ -3560,7 +3556,7 @@ COMMAND_HANDLER(xscale_handle_cp15) /* read cp15 control register */ xscale_get_reg(reg); value = buf_get_u32(reg->value, 0, 32); - command_print(CMD, "%s (/%i): 0x%" PRIx32 "", reg->name, (int)(reg->size), + command_print(CMD, "%s (/%i): 0x%" PRIx32, reg->name, (int)(reg->size), value); } else if (CMD_ARGC == 2) { uint32_t value; diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 3a877edfa6..f8c36b01d7 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -949,7 +949,8 @@ int xtensa_smpbreak_set(struct target *target, uint32_t set) xtensa->smp_break = set; if (target_was_examined(target)) res = xtensa_smpbreak_write(xtensa, xtensa->smp_break); - LOG_TARGET_DEBUG(target, "set smpbreak=%" PRIx32 ", state=%i", set, target->state); + LOG_TARGET_DEBUG(target, "set smpbreak=%" PRIx32 ", state %s", set, + target_state_name(target)); return res; } @@ -1555,7 +1556,7 @@ int xtensa_get_gdb_reg_list(struct target *target, return ERROR_OK; } -int xtensa_mmu_is_enabled(struct target *target, int *enabled) +int xtensa_mmu_is_enabled(struct target *target, bool *enabled) { struct xtensa *xtensa = target_to_xtensa(target); *enabled = xtensa->core_config->mmu.itlb_entries_count > 0 || @@ -2076,17 +2077,16 @@ int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t si /* Disable fast memory access instructions and retry before reporting an error */ LOG_TARGET_DEBUG(target, "Disabling LDDR32.P/SDDR32.P"); xtensa->probe_lsddr32p = 0; - res = xtensa_read_memory(target, address, size, count, albuff); - bswap = false; + res = xtensa_read_memory(target, address, size, count, buffer); } else { LOG_TARGET_WARNING(target, "Failed reading %d bytes at address "TARGET_ADDR_FMT, count * size, address); } + } else { + if (bswap) + buf_bswap32(albuff, albuff, addrend_al - addrstart_al); + memcpy(buffer, albuff + (address & 3), (size * count)); } - - if (bswap) - buf_bswap32(albuff, albuff, addrend_al - addrstart_al); - memcpy(buffer, albuff + (address & 3), (size * count)); free(albuff); return res; } diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h index a920f77cdf..daa88b10d1 100644 --- a/src/target/xtensa/xtensa.h +++ b/src/target/xtensa/xtensa.h @@ -392,7 +392,7 @@ int xtensa_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints); int xtensa_do_step(struct target *target, bool current, target_addr_t address, bool handle_breakpoints); -int xtensa_mmu_is_enabled(struct target *target, int *enabled); +int xtensa_mmu_is_enabled(struct target *target, bool *enabled); int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); int xtensa_write_memory(struct target *target, diff --git a/src/transport/transport.c b/src/transport/transport.c index ab5be490fb..5323a7ca0a 100644 --- a/src/transport/transport.c +++ b/src/transport/transport.c @@ -258,7 +258,7 @@ struct transport *get_current_transport(void) const char *get_current_transport_name(void) { if (!session || !is_transport_id_valid(session->id)) - NULL; + return NULL; return transport_full_name(session->id); } diff --git a/src/xsvf/xsvf.c b/src/xsvf/xsvf.c index 617c2f423e..5f5bf8d094 100644 --- a/src/xsvf/xsvf.c +++ b/src/xsvf/xsvf.c @@ -117,57 +117,57 @@ static enum tap_state xsvf_to_tap(int xsvf_state) enum tap_state ret; switch (xsvf_state) { - case XSV_RESET: - ret = TAP_RESET; - break; - case XSV_IDLE: - ret = TAP_IDLE; - break; - case XSV_DRSELECT: - ret = TAP_DRSELECT; - break; - case XSV_DRCAPTURE: - ret = TAP_DRCAPTURE; - break; - case XSV_DRSHIFT: - ret = TAP_DRSHIFT; - break; - case XSV_DREXIT1: - ret = TAP_DREXIT1; - break; - case XSV_DRPAUSE: - ret = TAP_DRPAUSE; - break; - case XSV_DREXIT2: - ret = TAP_DREXIT2; - break; - case XSV_DRUPDATE: - ret = TAP_DRUPDATE; - break; - case XSV_IRSELECT: - ret = TAP_IRSELECT; - break; - case XSV_IRCAPTURE: - ret = TAP_IRCAPTURE; - break; - case XSV_IRSHIFT: - ret = TAP_IRSHIFT; - break; - case XSV_IREXIT1: - ret = TAP_IREXIT1; - break; - case XSV_IRPAUSE: - ret = TAP_IRPAUSE; - break; - case XSV_IREXIT2: - ret = TAP_IREXIT2; - break; - case XSV_IRUPDATE: - ret = TAP_IRUPDATE; - break; - default: - LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); - exit(1); + case XSV_RESET: + ret = TAP_RESET; + break; + case XSV_IDLE: + ret = TAP_IDLE; + break; + case XSV_DRSELECT: + ret = TAP_DRSELECT; + break; + case XSV_DRCAPTURE: + ret = TAP_DRCAPTURE; + break; + case XSV_DRSHIFT: + ret = TAP_DRSHIFT; + break; + case XSV_DREXIT1: + ret = TAP_DREXIT1; + break; + case XSV_DRPAUSE: + ret = TAP_DRPAUSE; + break; + case XSV_DREXIT2: + ret = TAP_DREXIT2; + break; + case XSV_DRUPDATE: + ret = TAP_DRUPDATE; + break; + case XSV_IRSELECT: + ret = TAP_IRSELECT; + break; + case XSV_IRCAPTURE: + ret = TAP_IRCAPTURE; + break; + case XSV_IRSHIFT: + ret = TAP_IRSHIFT; + break; + case XSV_IREXIT1: + ret = TAP_IREXIT1; + break; + case XSV_IRPAUSE: + ret = TAP_IRPAUSE; + break; + case XSV_IREXIT2: + ret = TAP_IREXIT2; + break; + case XSV_IRUPDATE: + ret = TAP_IRUPDATE; + break; + default: + LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); + exit(1); } return ret; @@ -275,94 +275,91 @@ COMMAND_HANDLER(handle_xsvf_command) enum tap_state mystate; switch (opcode) { - case XCOMMENT: - /* ignore/show comments between XSTATE ops */ + case XCOMMENT: + /* ignore/show comments between XSTATE ops */ + break; + case XSTATE: + /* try to collect another transition */ + if (pathlen == XSTATE_MAX_PATH) { + LOG_ERROR("XSVF: path too long"); + do_abort = 1; break; - case XSTATE: - /* try to collect another transition */ - if (pathlen == XSTATE_MAX_PATH) { - LOG_ERROR("XSVF: path too long"); - do_abort = 1; - break; - } - - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } + } - mystate = xsvf_to_tap(uc); - path[pathlen++] = mystate; - - LOG_DEBUG("XSTATE 0x%02X %s", uc, - tap_state_name(mystate)); - - /* If path is incomplete, collect more */ - if (!svf_tap_state_is_stable(mystate)) - continue; - - /* Else execute the path transitions we've - * collected so far. - * - * NOTE: Punting on the saved path is not - * strictly correct, but we must to do this - * unless jtag_add_pathmove() stops rejecting - * paths containing RESET. This is probably - * harmless, since there aren't many options - * for going from a stable state to reset; - * at the worst, we may issue extra clocks - * once we get to RESET. - */ - if (mystate == TAP_RESET) { - LOG_WARNING("XSVF: dodgey RESET"); - path[0] = mystate; - } + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; + break; + } - /* FALL THROUGH */ - default: - /* Execute the path we collected - * - * NOTE: OpenOCD requires something that XSVF - * doesn't: the last TAP state in the path - * must be stable. In practice, tools that - * create XSVF seem to follow that rule too. - */ - collecting_path = false; + mystate = xsvf_to_tap(uc); + path[pathlen++] = mystate; - if (path[0] == TAP_RESET) - jtag_add_tlr(); - else - jtag_add_pathmove(pathlen, path); + LOG_DEBUG("XSTATE 0x%02X %s", uc, + tap_state_name(mystate)); - result = jtag_execute_queue(); - if (result != ERROR_OK) { - LOG_ERROR("XSVF: pathmove error %d", result); - do_abort = 1; - break; - } + /* If path is incomplete, collect more */ + if (!svf_tap_state_is_stable(mystate)) continue; - } - } - switch (opcode) { - case XCOMPLETE: - LOG_DEBUG("XCOMPLETE"); + /* Else execute the path transitions we've + * collected so far. + * + * NOTE: Punting on the saved path is not + * strictly correct, but we must to do this + * unless jtag_add_pathmove() stops rejecting + * paths containing RESET. This is probably + * harmless, since there aren't many options + * for going from a stable state to reset; + * at the worst, we may issue extra clocks + * once we get to RESET. + */ + if (mystate == TAP_RESET) { + LOG_WARNING("XSVF: dodgey RESET"); + path[0] = mystate; + } + + /* FALL THROUGH */ + default: + /* Execute the path we collected + * + * NOTE: OpenOCD requires something that XSVF + * doesn't: the last TAP state in the path + * must be stable. In practice, tools that + * create XSVF seem to follow that rule too. + */ + collecting_path = false; + + if (path[0] == TAP_RESET) + jtag_add_tlr(); + else + jtag_add_pathmove(pathlen, path); result = jtag_execute_queue(); if (result != ERROR_OK) { - tdo_mismatch = 1; + LOG_ERROR("XSVF: pathmove error %d", result); + do_abort = 1; break; } - break; + continue; + } + } - case XTDOMASK: - LOG_DEBUG("XTDOMASK"); - if (dr_in_mask && - (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) - do_abort = 1; - break; + switch (opcode) { + case XCOMPLETE: + LOG_DEBUG("XCOMPLETE"); + result = jtag_execute_queue(); + if (result != ERROR_OK) + tdo_mismatch = 1; + break; + + case XTDOMASK: + LOG_DEBUG("XTDOMASK"); + if (dr_in_mask && + (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) + do_abort = 1; + break; - case XRUNTEST: + case XRUNTEST: { uint8_t xruntest_buf[4]; @@ -376,20 +373,20 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XREPEAT: + case XREPEAT: { uint8_t myrepeat; - if (read(xsvf_fd, &myrepeat, 1) < 0) + if (read(xsvf_fd, &myrepeat, 1) < 0) { do_abort = 1; - else { + } else { xrepeat = myrepeat; LOG_DEBUG("XREPEAT %d", xrepeat); } } break; - case XSDRSIZE: + case XSDRSIZE: { uint8_t xsdrsize_buf[4]; @@ -411,8 +408,8 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XSDR: /* these two are identical except for the dr_in_buf */ - case XSDRTDO: + case XSDR: /* these two are identical except for the dr_in_buf */ + case XSDRTDO: { int limit = xrepeat; int matched = 0; @@ -521,47 +518,47 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XSETSDRMASKS: - LOG_ERROR("unsupported XSETSDRMASKS"); - unsupported = 1; - break; + case XSETSDRMASKS: + LOG_ERROR("unsupported XSETSDRMASKS"); + unsupported = 1; + break; - case XSDRINC: - LOG_ERROR("unsupported XSDRINC"); - unsupported = 1; - break; + case XSDRINC: + LOG_ERROR("unsupported XSDRINC"); + unsupported = 1; + break; - case XSDRB: - LOG_ERROR("unsupported XSDRB"); - unsupported = 1; - break; + case XSDRB: + LOG_ERROR("unsupported XSDRB"); + unsupported = 1; + break; - case XSDRC: - LOG_ERROR("unsupported XSDRC"); - unsupported = 1; - break; + case XSDRC: + LOG_ERROR("unsupported XSDRC"); + unsupported = 1; + break; - case XSDRE: - LOG_ERROR("unsupported XSDRE"); - unsupported = 1; - break; + case XSDRE: + LOG_ERROR("unsupported XSDRE"); + unsupported = 1; + break; - case XSDRTDOB: - LOG_ERROR("unsupported XSDRTDOB"); - unsupported = 1; - break; + case XSDRTDOB: + LOG_ERROR("unsupported XSDRTDOB"); + unsupported = 1; + break; - case XSDRTDOC: - LOG_ERROR("unsupported XSDRTDOC"); - unsupported = 1; - break; + case XSDRTDOC: + LOG_ERROR("unsupported XSDRTDOC"); + unsupported = 1; + break; - case XSDRTDOE: - LOG_ERROR("unsupported XSDRTDOE"); - unsupported = 1; - break; + case XSDRTDOE: + LOG_ERROR("unsupported XSDRTDOE"); + unsupported = 1; + break; - case XSTATE: + case XSTATE: { enum tap_state mystate; @@ -606,50 +603,48 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XENDIR: - - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } - - /* see page 22 of XSVF spec */ - if (uc == 0) - xendir = TAP_IDLE; - else if (uc == 1) - xendir = TAP_IRPAUSE; - else { - LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); - unsupported = 1; - break; - } - - LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); + case XENDIR: + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; break; + } - case XENDDR: + /* see page 22 of XSVF spec */ + if (uc == 0) { + xendir = TAP_IDLE; + } else if (uc == 1) { + xendir = TAP_IRPAUSE; + } else { + LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); + unsupported = 1; + break; + } - if (read(xsvf_fd, &uc, 1) < 0) { - do_abort = 1; - break; - } + LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); + break; - /* see page 22 of XSVF spec */ - if (uc == 0) - xenddr = TAP_IDLE; - else if (uc == 1) - xenddr = TAP_DRPAUSE; - else { - LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); - unsupported = 1; - break; - } + case XENDDR: + if (read(xsvf_fd, &uc, 1) < 0) { + do_abort = 1; + break; + } - LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); + /* see page 22 of XSVF spec */ + if (uc == 0) { + xenddr = TAP_IDLE; + } else if (uc == 1) { + xenddr = TAP_DRPAUSE; + } else { + LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); + unsupported = 1; break; + } + + LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); + break; - case XSIR: - case XSIR2: + case XSIR: + case XSIR2: { uint8_t short_buf[2]; uint8_t *ir_buf; @@ -675,9 +670,9 @@ COMMAND_HANDLER(handle_xsvf_command) ir_buf = malloc((bitcount + 7) / 8); - if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) + if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) { do_abort = 1; - else { + } else { struct scan_field field; field.num_bits = bitcount; @@ -712,7 +707,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XCOMMENT: + case XCOMMENT: { unsigned int ndx = 0; char comment[128]; @@ -734,7 +729,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XWAIT: + case XWAIT: { /* expected in stream: XWAIT @@ -762,9 +757,9 @@ COMMAND_HANDLER(handle_xsvf_command) LOG_DEBUG("XWAIT %s %s usecs:%d", tap_state_name( wait_state), tap_state_name(end_state), delay); - if (runtest_requires_tck && wait_state == TAP_IDLE) + if (runtest_requires_tck && wait_state == TAP_IDLE) { jtag_add_runtest(delay, end_state); - else { + } else { /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) @@ -777,7 +772,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XWAITSTATE: + case XWAITSTATE: { /* expected in stream: * XWAITSTATE @@ -838,7 +833,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case LCOUNT: + case LCOUNT: { /* expected in stream: * LCOUNT @@ -855,7 +850,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case LDELAY: + case LDELAY: { /* expected in stream: * LDELAY @@ -881,10 +876,10 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which - * comes with clocks !AND! sleep requirements. - */ - case LSDR: + /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which + * comes with clocks !AND! sleep requirements. + */ + case LSDR: { int limit = loop_count; int matched = 0; @@ -948,7 +943,7 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - case XTRST: + case XTRST: { uint8_t trst_mode; @@ -974,9 +969,9 @@ COMMAND_HANDLER(handle_xsvf_command) } break; - default: - LOG_ERROR("unknown xsvf command (0x%02X)", uc); - unsupported = 1; + default: + LOG_ERROR("unknown xsvf command (0x%02X)", uc); + unsupported = 1; } if (do_abort || unsupported || tdo_mismatch) { diff --git a/tcl/board/digilent_zybo.cfg b/tcl/board/digilent_zybo.cfg new file mode 100644 index 0000000000..8573399f84 --- /dev/null +++ b/tcl/board/digilent_zybo.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Digilent Zybo +# https://digilent.com/reference/programmable-logic/zybo/start + +# Tested with the Zybo board from Digilent (older). +# Not tested with the Zybo Z7 board from Digilent (newer). + + +adapter driver ftdi +ftdi channel 0 +#ftdi_device_desc "Digilent Adept USB Device" +ftdi vid_pid 0x0403 0x6010 +ftdi layout_init 0x3088 0x1f8b +ftdi layout_signal nSRST -data 0x3000 -oe 0x1000 +ftdi layout_signal LED -data 0x0010 +reset_config srst_pulls_trst +transport select jtag + +source [find target/zynq_7000.cfg] + +adapter speed 10000 + +# "ipdbg create-hub zynq.ipdbghub -pld zynq_pl.pld" -c init -c "zynq.ipdbghub ipdbg start -tool 0 -port 5555" diff --git a/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg b/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg new file mode 100644 index 0000000000..30cfb5797d --- /dev/null +++ b/tcl/board/easydevkits/esp32-wrover-e-ftdi-jtag-devkit.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E FTDI JTAG DevKit. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-e-ftdi-jtag-devkit.cfg +# + +# Select the FTDI JTAG driver +adapter driver ftdi + +# Identify the device +ftdi device_desc "EasyDevKit" +ftdi vid_pid 0x0403 0x6010 +# interface 0 is JTAG; interface 1 is the uart +ftdi channel 0 + +# TCK, TDI, TDO, TMS: ADBUS0-3 +# activity LED: ADBUS4 +ftdi layout_init 0x0008 0x001b +ftdi layout_signal LED -data 0x0010 + +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# --------------------------------------------------------------------------- +# JTAG speed (in kHz) +# +# If you encounter DSR/DIR errors that are not caused by OpenOCD +# attempting to read unmapped memory regions, try lowering this value. +# +# Recommended settings for EasyDevKits: +# - Do not exceed 20 MHz. +# - Best results are typically achieved at 20 MHz. +# --------------------------------------------------------------------------- +adapter speed 20000 diff --git a/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg b/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg new file mode 100644 index 0000000000..76f1435beb --- /dev/null +++ b/tcl/board/easydevkits/esp32-wrover-e-wch-jtag-devkit.cfg @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Example OpenOCD configuration file for the EasyDevKits ESP32-WROVER-E WCH JTAG DevKit. +# +# For example, OpenOCD can be started for ESP32 debugging on +# +# openocd -f board/esp32-wrover-e-wch-jtag-devkit.cfg +# + +# Select the CH347 JTAG driver +adapter driver ch347 + +# Identify the device +ch347 device_desc "EasyDevKit" +ch347 vid_pid 0x1a86 0x55dd + +# Configure activity LED +# Note: The LED is active-low on GPIO4. +adapter gpio led 4 -active-low + +# Source the ESP32 configuration file +source [find target/esp32.cfg] + +# --------------------------------------------------------------------------- +# JTAG speed (in kHz) +# +# If you encounter DSR/DIR errors that are not caused by OpenOCD +# attempting to read unmapped memory regions, try lowering this value. +# +# Recommended settings for EasyDevKits: +# - Do not exceed 30 MHz. +# - Best results are typically achieved at 15 MHz. +# +# Supported frequencies (kHz): +# 469, 938, 1875, 3750, 7500, 15000, 30000, 60000 +# --------------------------------------------------------------------------- +adapter speed 15000 diff --git a/tcl/board/microchip/pic64gx-curiosity-kit.cfg b/tcl/board/microchip/pic64gx-curiosity-kit.cfg new file mode 100644 index 0000000000..e7e67ea4bd --- /dev/null +++ b/tcl/board/microchip/pic64gx-curiosity-kit.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Microchip RISC-V board +# +# https://www.microchip.com/en-us/products/microprocessors/64-bit-mpus/pic64gx +# +adapter speed 6000 + +source [find interface/microchip/embedded_flashpro5.cfg] +source [find target/microchip/pic64gx.cfg] diff --git a/tcl/board/mikroe/clicker4-stm32f745vg.cfg b/tcl/board/mikroe/clicker4-stm32f745vg.cfg new file mode 100644 index 0000000000..9ccd948801 --- /dev/null +++ b/tcl/board/mikroe/clicker4-stm32f745vg.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is a MikroElektronika Click 4 board with a single STM32F745VG chip +# and an on-board CODEGRIP debugger. +# https://www.mikroe.com/clicker-4-for-stm32f745vgt6 + +source [find interface/cmsis-dap.cfg] +transport select jtag +adapter speed 4000 + +source [find target/stm32f7x.cfg] diff --git a/tcl/board/nordic_nrf51_dk.cfg b/tcl/board/nordic/nrf51-dk.cfg similarity index 81% rename from tcl/board/nordic_nrf51_dk.cfg rename to tcl/board/nordic/nrf51-dk.cfg index 7ddae2d438..4ccd3272e5 100644 --- a/tcl/board/nordic_nrf51_dk.cfg +++ b/tcl/board/nordic/nrf51-dk.cfg @@ -8,4 +8,4 @@ source [find interface/jlink.cfg] transport select swd -source [find target/nrf51.cfg] +source [find target/nordic/nrf51.cfg] diff --git a/tcl/board/nordic_nrf51822_mkit.cfg b/tcl/board/nordic/nrf51822-mkit.cfg similarity index 79% rename from tcl/board/nordic_nrf51822_mkit.cfg rename to tcl/board/nordic/nrf51822-mkit.cfg index 266d710704..fd32271789 100644 --- a/tcl/board/nordic_nrf51822_mkit.cfg +++ b/tcl/board/nordic/nrf51822-mkit.cfg @@ -5,4 +5,4 @@ # source [find interface/cmsis-dap.cfg] -source [find target/nrf51.cfg] +source [find target/nordic/nrf51.cfg] diff --git a/tcl/board/nordic_nrf52_dk.cfg b/tcl/board/nordic/nrf52-dk.cfg similarity index 81% rename from tcl/board/nordic_nrf52_dk.cfg rename to tcl/board/nordic/nrf52-dk.cfg index 7366bf94af..9b2390a624 100644 --- a/tcl/board/nordic_nrf52_dk.cfg +++ b/tcl/board/nordic/nrf52-dk.cfg @@ -8,4 +8,4 @@ source [find interface/jlink.cfg] transport select swd -source [find target/nrf52.cfg] +source [find target/nordic/nrf52.cfg] diff --git a/tcl/board/nordic/nrf5340-dk.cfg b/tcl/board/nordic/nrf5340-dk.cfg new file mode 100644 index 0000000000..fd7a40d666 --- /dev/null +++ b/tcl/board/nordic/nrf5340-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic Semiconductor nRF5340 Development Kit +# https://www.nordicsemi.com/Products/Development-hardware/nRF5340-DK +# + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/nordic/nrf53.cfg] diff --git a/tcl/board/nordic/nrf9160-dk.cfg b/tcl/board/nordic/nrf9160-dk.cfg new file mode 100644 index 0000000000..dc456202c1 --- /dev/null +++ b/tcl/board/nordic/nrf9160-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Nordic Semiconductor nRF9160 Development Kit +# https://www.nordicsemi.com/Products/Development-hardware/nRF9160-DK +# + +source [find interface/jlink.cfg] + +transport select swd + +source [find target/nordic/nrf91.cfg] diff --git a/tcl/board/nordic_nrf52_ftx232.cfg b/tcl/board/nordic_nrf52_ftx232.cfg index c3c69a89a5..772d176d6f 100644 --- a/tcl/board/nordic_nrf52_ftx232.cfg +++ b/tcl/board/nordic_nrf52_ftx232.cfg @@ -5,9 +5,11 @@ # or any FT232H/FT2232H/FT4232H based board/module # +echo "WARNING: 'board/nordic_nrf52_ftx232.cfg' is deprecated, use '-f interface/ftdi/ft232h-module-swd.cfg -f target/nordic/nrf52.cfg' instead" + source [find interface/ftdi/ft232h-module-swd.cfg] #source [find interface/ftdi/minimodule-swd.cfg] transport select swd -source [find target/nrf52.cfg] +source [find target/nordic/nrf52.cfg] diff --git a/tcl/board/orange_pi_zero_3.cfg b/tcl/board/orange_pi_zero_3.cfg new file mode 100644 index 0000000000..2af983c650 --- /dev/null +++ b/tcl/board/orange_pi_zero_3.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Orange Pi Zero 3 board with Allwinner H618 chip +# http://www.orangepi.org/html/hardWare/computerAndMicrocontrollers/details/Orange-Pi-Zero-3.html +# +# Accessing JTAG signals on Orange Pi Zero 3 board requires connection to pins +# on the microSD card slot. +# 1 - DAT2 - TCK +# 2 - CD/DAT3 - NC +# 3 - CMD - TDO +# 4 - VDD - NC +# 5 - CLK - NC +# 6 - VSS - NC +# 7 - DAT0 - TDI +# 8 - DAT1 - TMS +# +# PF Configure Register 0 at address 0x0300b0b4 must be set 0x07373733 to set +# the JTAG function on these pins (which is what the factory installed image on +# the SPI flash does when the board is powered without a microSD inserted). + +source [find target/allwinner_h618.cfg] + +# To this contributor's knowledge, the board neither exposes TRST nor SRST. +reset_config none diff --git a/tcl/board/pico-debug.cfg b/tcl/board/pico-debug.cfg index ba59f860a3..8139663f23 100644 --- a/tcl/board/pico-debug.cfg +++ b/tcl/board/pico-debug.cfg @@ -6,5 +6,5 @@ source [find interface/cmsis-dap.cfg] adapter speed 4000 -set CHIPNAME rp2040 -source [find target/rp2040-core0.cfg] +set USE_CORE 0 +source [find target/rp2040.cfg] diff --git a/tcl/board/pico2-debug.cfg b/tcl/board/pico2-debug.cfg new file mode 100644 index 0000000000..d0a4c6af5a --- /dev/null +++ b/tcl/board/pico2-debug.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# pico2-debug is a virtual CMSIS-DAP debug adapter +# it runs on the very same RP2350 target being debugged without additional hardware +# https://github.com/majbthrd/pico2-debug + +source [find interface/cmsis-dap.cfg] +adapter speed 4000 + +set USE_CORE 0 +source [find target/rp2350.cfg] diff --git a/tcl/board/rpi3.cfg b/tcl/board/rpi3.cfg index fd93a9d9d8..a08bfeb12e 100644 --- a/tcl/board/rpi3.cfg +++ b/tcl/board/rpi3.cfg @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 3 board with BCM2837 chip -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837/README.md +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2837.cfg] transport select jtag diff --git a/tcl/board/rpi4b.cfg b/tcl/board/rpi4b.cfg index 5b046af7b5..7d937e8c05 100644 --- a/tcl/board/rpi4b.cfg +++ b/tcl/board/rpi4b.cfg @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later # This is the Raspberry Pi 4 model B board with BCM2711 chip -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/README.md +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 # # Enable JTAG GPIO on Raspberry Pi boards -# https://www.raspberrypi.org/documentation/configuration/config-txt/gpio.md +# https://www.raspberrypi.com/documentation/computers/legacy_config_txt.html#enable_jtag_gpio source [find target/bcm2711.cfg] transport select jtag diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive/e31-arty.cfg similarity index 94% rename from tcl/board/sifive-e51arty.cfg rename to tcl/board/sifive/e31-arty.cfg index 3133c39023..bdf79dae61 100644 --- a/tcl/board/sifive-e51arty.cfg +++ b/tcl/board/sifive/e31-arty.cfg @@ -3,7 +3,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive/e31-arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive/e51-arty.cfg similarity index 94% rename from tcl/board/sifive-e31arty.cfg rename to tcl/board/sifive/e51-arty.cfg index b3e980f408..1476d503e2 100644 --- a/tcl/board/sifive-e31arty.cfg +++ b/tcl/board/sifive/e51-arty.cfg @@ -3,7 +3,7 @@ # # Be sure you include the speed and interface before this file # Example: -# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" +# -c "adapter speed 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive/e51-arty.cfg" set _CHIPNAME riscv jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 diff --git a/tcl/board/sifive-hifive1-revb.cfg b/tcl/board/sifive/hifive1-rev-b.cfg similarity index 100% rename from tcl/board/sifive-hifive1-revb.cfg rename to tcl/board/sifive/hifive1-rev-b.cfg diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive/hifive1.cfg similarity index 100% rename from tcl/board/sifive-hifive1.cfg rename to tcl/board/sifive/hifive1.cfg diff --git a/tcl/board/st/nucleo-u083rc.cfg b/tcl/board/st/nucleo-u083rc.cfg index 7b878adbc0..03e9569305 100644 --- a/tcl/board/st/nucleo-u083rc.cfg +++ b/tcl/board/st/nucleo-u083rc.cfg @@ -5,7 +5,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32u0x.cfg] diff --git a/tcl/board/stm32mp13x_dk.cfg b/tcl/board/st/stm32mp135f-dk.cfg similarity index 83% rename from tcl/board/stm32mp13x_dk.cfg rename to tcl/board/st/stm32mp135f-dk.cfg index 8ece24844c..2259e0425b 100644 --- a/tcl/board/stm32mp13x_dk.cfg +++ b/tcl/board/st/stm32mp135f-dk.cfg @@ -7,6 +7,6 @@ source [find interface/stlink.cfg] transport select swd -source [find target/stm32mp13x.cfg] +source [find target/st/stm32mp13x.cfg] reset_config srst_only diff --git a/tcl/board/stm32mp15x_dk2.cfg b/tcl/board/st/stm32mp157f-dk2.cfg similarity index 72% rename from tcl/board/stm32mp15x_dk2.cfg rename to tcl/board/st/stm32mp157f-dk2.cfg index ba1c7f78a6..b193ae3a0c 100644 --- a/tcl/board/stm32mp15x_dk2.cfg +++ b/tcl/board/st/stm32mp157f-dk2.cfg @@ -3,11 +3,12 @@ # board MB1272B # http://www.st.com/en/evaluation-tools/stm32mp157a-dk1.html # http://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html +# http://www.st.com/en/evaluation-tools/stm32mp157f-dk2.html source [find interface/stlink.cfg] transport select swd -source [find target/stm32mp15x.cfg] +source [find target/st/stm32mp15x.cfg] reset_config srst_only diff --git a/tcl/board/st/stm32mp235f-dk.cfg b/tcl/board/st/stm32mp235f-dk.cfg new file mode 100644 index 0000000000..1f660f19ed --- /dev/null +++ b/tcl/board/st/stm32mp235f-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# MB1605 with stm32mp23x +# https://www.st.com/en/evaluation-tools/stm32mp257f-dk.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/st/stm32mp23x.cfg] + +reset_config srst_only diff --git a/tcl/board/st/stm32mp257f-dk.cfg b/tcl/board/st/stm32mp257f-dk.cfg new file mode 100644 index 0000000000..182f1d00ce --- /dev/null +++ b/tcl/board/st/stm32mp257f-dk.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# MB1605 +# https://www.st.com/en/evaluation-tools/stm32mp257f-dk.html + +source [find interface/stlink.cfg] + +transport select swd + +source [find target/st/stm32mp25x.cfg] + +reset_config srst_only diff --git a/tcl/board/st_nucleo_c0.cfg b/tcl/board/st_nucleo_c0.cfg index 7d07675920..845b7b50e9 100644 --- a/tcl/board/st_nucleo_c0.cfg +++ b/tcl/board/st_nucleo_c0.cfg @@ -2,7 +2,7 @@ source [find interface/stlink.cfg] -transport select dapdirect_swd +transport select swd source [find target/stm32c0x.cfg] diff --git a/tcl/board/ti/launchxl2-tms57012.cfg b/tcl/board/ti/launchxl2-tms57012.cfg new file mode 100644 index 0000000000..99cb26e204 --- /dev/null +++ b/tcl/board/ti/launchxl2-tms57012.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Hercules TMS570LS12x LaunchPad Development Kit +# https://www.ti.com/tool/LAUNCHXL2-TMS57012 + +source [find interface/xds110.cfg] + +transport select jtag + +source [find target/ti_tms570ls1x.cfg] diff --git a/tcl/board/ti_am625_swd_native.cfg b/tcl/board/ti_am625_swd_native.cfg index dc4b20579d..65314fe5dc 100644 --- a/tcl/board/ti_am625_swd_native.cfg +++ b/tcl/board/ti_am625_swd_native.cfg @@ -14,6 +14,7 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am625 diff --git a/tcl/board/ti_am62a7_swd_native.cfg b/tcl/board/ti_am62a7_swd_native.cfg index 99fc0b0b38..3d5e892289 100644 --- a/tcl/board/ti_am62a7_swd_native.cfg +++ b/tcl/board/ti_am62a7_swd_native.cfg @@ -14,6 +14,7 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am62a7 diff --git a/tcl/board/ti_am62p_swd_native.cfg b/tcl/board/ti_am62p_swd_native.cfg index fa549f3585..a8c6bd1204 100644 --- a/tcl/board/ti_am62p_swd_native.cfg +++ b/tcl/board/ti_am62p_swd_native.cfg @@ -14,6 +14,7 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC am62p diff --git a/tcl/board/ti_j721e_swd_native.cfg b/tcl/board/ti_j721e_swd_native.cfg index 3041c3c345..38316387af 100644 --- a/tcl/board/ti_j721e_swd_native.cfg +++ b/tcl/board/ti_j721e_swd_native.cfg @@ -14,6 +14,7 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC j721e diff --git a/tcl/board/ti_j722s_swd_native.cfg b/tcl/board/ti_j722s_swd_native.cfg index bbe0d508c8..a171ec3586 100644 --- a/tcl/board/ti_j722s_swd_native.cfg +++ b/tcl/board/ti_j722s_swd_native.cfg @@ -15,6 +15,7 @@ # We are using dmem, which uses dapdirect_swd transport adapter driver dmem +transport select swd if { ![info exists SOC] } { set SOC j722s diff --git a/tcl/board/vd_a75x4_jtag.cfg b/tcl/board/vd_a75x4_jtag.cfg index c94a71972d..a91f8b8cfc 100644 --- a/tcl/board/vd_a75x4_jtag.cfg +++ b/tcl/board/vd_a75x4_jtag.cfg @@ -17,7 +17,7 @@ set CPUTAPID 0x4ba06477 transport select jtag # JTAG reset config, frequency and reset delay -reset_config trst_and_srst +reset_config trst_only adapter speed 1500000 adapter srst delay 5 diff --git a/tcl/board/vd_pulpissimo_jtag.cfg b/tcl/board/vd_pulpissimo_jtag.cfg index a3f5a84886..5a6725fd62 100644 --- a/tcl/board/vd_pulpissimo_jtag.cfg +++ b/tcl/board/vd_pulpissimo_jtag.cfg @@ -4,9 +4,9 @@ source [find interface/vdebug.cfg] -set _CHIPNAME ibex -set _HARTID 0x20 -set _CPUTAPID 0x249511c3 +set CHIPNAME ibex +set HARTID 0x20 +set CPUTAPID 0x249511c3 # vdebug select transport transport select jtag @@ -25,7 +25,7 @@ vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2_pri\[1\].sram_i.mem_ar vdebug mem_path tbench.soc_domain_i.pulp_soc_i.gen_mem_l2\[0\].sram_i.mem_array 0x1c010000 0x80000 # need to explicitly define riscv tap, autoprobing does not work for icapture != 0x01 -jtag newtap $_CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $_CPUTAPID +jtag newtap $CHIPNAME cpu -irlen 5 -ircapture 0x05 -irmask 0x1f -expected-id $CPUTAPID jtag arp_init-reset diff --git a/tcl/file_renaming.cfg b/tcl/file_renaming.cfg new file mode 100644 index 0000000000..79932473ea --- /dev/null +++ b/tcl/file_renaming.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This file is used to remap configuration files that has been +# renamed, except simple renames that are taken care automatically +# like: +# .../file.cfg ==> .../${vendor}/file.cfg +# .../vendor-file.cfg ==> .../vendor/file.cfg +# .../vendor_file.cfg ==> .../vendor/file.cfg +# +# The formatting below is a TCL dict, so pairs of key-value +# in a simple TCL list, using for each line +# old_name new_name +# including in each name one of the prefix folder between +# board, chip, cpld, cpu, fpga, interface, target, test, tools + +set _file_renaming { + board/nordic_nrf51822_mkit.cfg board/nordic/nrf51822-mkit.cfg + board/nordic_nrf51_dk.cfg board/nordic/nrf51-dk.cfg + board/nordic_nrf52_dk.cfg board/nordic/nrf52-dk.cfg + board/stm32mp13x_dk.cfg board/st/stm32mp135f-dk.cfg + board/stm32mp15x_dk2.cfg board/st/stm32mp157f-dk2.cfg + board/sifive-hifive1-revb.cfg board/sifive/hifive1-rev-b.cfg + interface/chameleon.cfg interface/parport/chameleon.cfg + interface/flashlink.cfg interface/parport/flashlink.cfg +} diff --git a/tcl/interface/chameleon.cfg b/tcl/interface/chameleon.cfg deleted file mode 100644 index b73d129f02..0000000000 --- a/tcl/interface/chameleon.cfg +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# Amontec Chameleon POD -# -# http://www.amontec.com/chameleon.shtml -# - -adapter driver parport -parport cable chameleon diff --git a/tcl/interface/cmsis-dap-tcp.cfg b/tcl/interface/cmsis-dap-tcp.cfg new file mode 100644 index 0000000000..7889fb9444 --- /dev/null +++ b/tcl/interface/cmsis-dap-tcp.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# cmsis-dap-tcp - CMSIS-DAP protocol over TCP/IP. +# + +adapter driver cmsis-dap +cmsis-dap backend tcp + +# Specify the hostname or IP address of your programmer. +# cmsis-dap tcp host 192.168.1.4 + +# Optionally specify a port number. Default port is 4441. +# cmsis-dap tcp port 4441 + +# Optionally set a lower bound on packet timeouts (milliseconds), if using a +# slow network. +# cmsis-dap tcp min_timeout 300 diff --git a/tcl/interface/flashlink.cfg b/tcl/interface/flashlink.cfg deleted file mode 100644 index d552c50a6b..0000000000 --- a/tcl/interface/flashlink.cfg +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -# -# ST FlashLINK JTAG parallel cable -# -# http://www.st.com/internet/evalboard/product/94023.jsp -# http://www.st.com/stonline/products/literature/um/7889.pdf -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} - -adapter driver parport -parport port $_PARPORTADDR -parport cable flashlink diff --git a/tcl/interface/microchip/embedded_flashpro5.cfg b/tcl/interface/microchip/embedded_flashpro5.cfg new file mode 100644 index 0000000000..117a54458e --- /dev/null +++ b/tcl/interface/microchip/embedded_flashpro5.cfg @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Embedded FlashPro5 +# +# https://www.microchip.com/en-us/development-tool/flashpro5 +# + +adapter driver ftdi + +# vidpid 1514:2008 = embedded flashpro5 +# vidpid 1514:200a = pic64gx +ftdi vid_pid 0x1514 0x2008 0x1514 0x200a + +# That FTDI has 4 channels (channel 0 and 1 are MPSSE-capable, 2 and 3 are bitbang +ftdi channel 0 + +# Initial Layout - data[0..15] direction[0..15] +ftdi layout_init 0x0018 0xfdfb +# Signal Data Direction Notes +# AD0 TCK 0 1 (out) Port A TCK +# AD1 TDI 0 1 (out) Port A TDI +# AD2 TDO 0 0 (in) PORT A TDO +# AD3 TMS 1 1 (out) Port A TMS +# AD4 GPIOL0 1 1 (out) Port A TRST +# AD5 GPIOL1 0 1 (out) (unused) +# AD6 GPIOL2 0 1 (out) (unused) +# AD7 GPIOL3 0 1 (out) (unused) + +# BD0 TCK 0 1 (out) FTDI_UART_B_TXD +# BD1 TDI 0 0 (in) FTDI_UART_B_RXD +# BD2 TDO 0 1 (out) (unused) +# BD3 TMS 0 1 (out) (unused) +# BD4 GPIOL0 0 1 (out) (unused) +# BD5 GPIOL1 0 1 (out) (unused) +# BD6 GPIOL2 0 1 (out) (unused) +# BD7 GPIOL2 0 1 (out) (unused) + +# Signals definition +ftdi layout_signal nTRST -data 0x0010 -oe 0x0010 diff --git a/tcl/interface/parport/altium.cfg b/tcl/interface/parport/altium.cfg new file mode 100644 index 0000000000..9389d47ef1 --- /dev/null +++ b/tcl/interface/parport/altium.cfg @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: +# +# HARD TCK - Target TCK +# HARD TMS - Target TMS +# HARD TDI - Target TDI +# HARD TDO - Target TDO +# SOFT TCK - Target TRST +# SOFT TDI - Target SRST + +adapter driver parport + +adapter gpio tdo 13 -exit-inactive +adapter gpio trst 7 -active-high -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive +adapter gpio srst 9 -active-high -exit-inactive +adapter gpio led 5 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 6 -init-active -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/amt-wiggler-old.cfg b/tcl/interface/parport/amt-wiggler-old.cfg new file mode 100644 index 0000000000..bba30c8b21 --- /dev/null +++ b/tcl/interface/parport/amt-wiggler-old.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 2 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 6 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/arm-jtag.cfg b/tcl/interface/parport/arm-jtag.cfg new file mode 100644 index 0000000000..3b2a10daac --- /dev/null +++ b/tcl/interface/parport/arm-jtag.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 2 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 6 -active-high -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/aspo.cfg b/tcl/interface/parport/aspo.cfg new file mode 100644 index 0000000000..0d14719dba --- /dev/null +++ b/tcl/interface/parport/aspo.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 13 -exit-inactive +adapter gpio trst 2 -init-active -exit-active +adapter gpio tms 4 -active-low -exit-active +adapter gpio tck 5 -exit-inactive +adapter gpio tdi 3 -active-low -init-active -exit-active +adapter gpio srst 6 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/chameleon.cfg b/tcl/interface/parport/chameleon.cfg new file mode 100644 index 0000000000..f0ebcdd50c --- /dev/null +++ b/tcl/interface/parport/chameleon.cfg @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 3 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/dlc5.cfg b/tcl/interface/parport/dlc5.cfg index 24acea7a95..fb84943213 100644 --- a/tcl/interface/parport/dlc5.cfg +++ b/tcl/interface/parport/dlc5.cfg @@ -1,17 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# # Xilinx Parallel Cable III 'DLC 5' (and various clones) -# -# http://www.xilinx.com/itp/xilinx4/data/docs/pac/appendixb.html -# - -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - set _PARPORTADDR 0 -} adapter driver parport -parport port $_PARPORTADDR -parport cable dlc5 + +adapter gpio tdo 13 -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 6 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/flashlink.cfg b/tcl/interface/parport/flashlink.cfg new file mode 100644 index 0000000000..b1a261d0bb --- /dev/null +++ b/tcl/interface/parport/flashlink.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 12 -active-low -exit-inactive +adapter gpio trst 6 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 4 -exit-inactive +adapter gpio srst 7 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/lattice.cfg b/tcl/interface/parport/lattice.cfg new file mode 100644 index 0000000000..aa7322812d --- /dev/null +++ b/tcl/interface/parport/lattice.cfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 10 -exit-inactive +adapter gpio trst 6 -active-high -init-active -exit-active +adapter gpio tms 4 -exit-inactive +adapter gpio tck 3 -exit-inactive +adapter gpio tdi 2 -exit-inactive +adapter gpio srst 5 -active-high -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/triton.cfg b/tcl/interface/parport/triton.cfg new file mode 100644 index 0000000000..b24d223a91 --- /dev/null +++ b/tcl/interface/parport/triton.cfg @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 5 -active-high -exit-inactive +adapter gpio tms 4 -exit-inactive +adapter gpio tck 2 -exit-inactive +adapter gpio tdi 3 -exit-inactive + +transport select jtag diff --git a/tcl/interface/parport/wiggler-ntrst-inverted.cfg b/tcl/interface/parport/wiggler-ntrst-inverted.cfg new file mode 100644 index 0000000000..3b2fc0f289 --- /dev/null +++ b/tcl/interface/parport/wiggler-ntrst-inverted.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/wiggler.cfg b/tcl/interface/parport/wiggler.cfg index b9fceeb852..84c1c83026 100644 --- a/tcl/interface/parport/wiggler.cfg +++ b/tcl/interface/parport/wiggler.cfg @@ -1,21 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# -# Parallel port wiggler (many clones available) on port 0x378 -# -# Addresses: 0x378/LPT1 or 0x278/LPT2 ... -# +adapter driver parport -if { [info exists PARPORTADDR] } { - set _PARPORTADDR $PARPORTADDR -} else { - if {$tcl_platform(platform) eq "windows"} { - set _PARPORTADDR 0x378 - } { - set _PARPORTADDR 0 - } -} +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -active-high -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive -adapter driver parport -parport port $_PARPORTADDR -parport cable wiggler +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-active + +transport select jtag diff --git a/tcl/interface/parport/wiggler2.cfg b/tcl/interface/parport/wiggler2.cfg new file mode 100644 index 0000000000..839e7f9b46 --- /dev/null +++ b/tcl/interface/parport/wiggler2.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +adapter driver parport + +adapter gpio tdo 11 -active-low -exit-inactive +adapter gpio trst 6 -active-high -exit-inactive +adapter gpio tms 3 -exit-inactive +adapter gpio tck 4 -exit-inactive +adapter gpio tdi 5 -exit-inactive +adapter gpio srst 2 -exit-inactive +adapter gpio led 7 -exit-inactive + +# Non-JTAG signal that is only necessary for the functionality of the adapter. +# For details, refer to the documentation of the adapter. +adapter gpio user0 9 -init-active -exit-inactive + +transport select jtag diff --git a/tcl/interface/vdebug.cfg b/tcl/interface/vdebug.cfg index 63a5955067..27a8aafd7b 100644 --- a/tcl/interface/vdebug.cfg +++ b/tcl/interface/vdebug.cfg @@ -30,4 +30,4 @@ tcl port disabled vdebug batching 1 # Polling values -vdebug polling 100 1000 +vdebug polling 100 500 diff --git a/tcl/target/allwinner_h618.cfg b/tcl/target/allwinner_h618.cfg new file mode 100644 index 0000000000..98d3ace0de --- /dev/null +++ b/tcl/target/allwinner_h618.cfg @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# This is the Allwinner H618 chip. It is an updated version of the Allwinner H616. + +# Information is available on linux-sunxi.org: +# Datasheet: https://linux-sunxi.org/images/b/b9/H616_Datasheet_V1.0_cleaned.pdf +# Manual: https://linux-sunxi.org/images/2/24/H616_User_Manual_V1.0_cleaned.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME h618 +} + +if { [info exists USE_SMP] } { + set _USE_SMP $USE_SMP +} else { + set _USE_SMP 0 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +set _cores 4 +jtag newtap $_CHIPNAME cpu -expected-id $_DAP_TAPID -irlen 4 +adapter speed 4000 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# MEM-AP for direct access +target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 1 + +# these addresses are obtained from the ROM table via 'dap info 1' command +set _DBGBASE {0x81410000 0x81510000 0x81610000 0x81710000} +set _CTIBASE {0x81420000 0x81520000 0x81620000 0x81720000} + +set _smp_command "target smp" + +for { set _core 0 } { $_core < $_cores } { incr _core } { + set _CTINAME $_CHIPNAME.cti$_core + set _TARGETNAME $_CHIPNAME.cpu$_core + + cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 1 -baseaddr [lindex $_CTIBASE $_core] + target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 1 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME + + set _smp_command "$_smp_command $_TARGETNAME" +} + +if {$_USE_SMP} { + eval $_smp_command +} + +# default target is cpu0 +targets $_CHIPNAME.cpu0 diff --git a/tcl/target/artery/at32f4x.cfg b/tcl/target/artery/at32f4x.cfg new file mode 100644 index 0000000000..c299aa9040 --- /dev/null +++ b/tcl/target/artery/at32f4x.cfg @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Configuration file for Artery AT32F4x family. +# +# https://www.arterychip.com/en/product/ +# + +# AT32F4x devices support JTAG and SWD transport. +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME at32f4x +} + +# Work-area is a space in RAM used for flash programming, by default use 4 KiB. +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x4ba00477 + } { + set _CPUTAPID 0x1ba01477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME artery 0x08000000 0 0 0 $_TARGETNAME + +adapter speed 1000 + +if {![using_hla]} { + cortex_m reset_config sysresetreq +} diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg index 7e9f6c57ef..9fd89795b6 100644 --- a/tcl/target/atsamv.cfg +++ b/tcl/target/atsamv.cfg @@ -41,6 +41,11 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20400000 -work-area-size $_WORKAREASIZE -work-area-backup 0 +$_TARGETNAME configure -event reset-init { + # WDT_MR = WDDIS (disable watchdog) + mww 0x400E1854 0x8000 +} + adapter speed 1800 if {![using_hla]} { @@ -58,4 +63,6 @@ if {![using_hla]} { } set _FLASHNAME $_CHIPNAME.flash +set _SIGNATURENAME $_CHIPNAME.usersignature flash bank $_FLASHNAME atsamv 0x00400000 0 0 0 $_TARGETNAME +flash bank $_SIGNATURENAME atsamv 0x100000000 0 0 0 $_TARGETNAME diff --git a/tcl/target/bcm2711.cfg b/tcl/target/bcm2711.cfg index f8d2b3a65b..9704daf812 100644 --- a/tcl/target/bcm2711.cfg +++ b/tcl/target/bcm2711.cfg @@ -3,8 +3,8 @@ # The Broadcom BCM2711 used in Raspberry Pi 4 # No documentation was found on Broadcom website -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/ +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2711 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2835.cfg b/tcl/target/bcm2835.cfg index 32a03666c4..645588730d 100644 --- a/tcl/target/bcm2835.cfg +++ b/tcl/target/bcm2835.cfg @@ -3,8 +3,8 @@ # This is the Broadcom chip used in the Raspberry Pi Model A, B, B+, # the Compute Module, and the Raspberry Pi Zero. -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2835 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2836.cfg b/tcl/target/bcm2836.cfg index 04921315ed..695426e7a8 100644 --- a/tcl/target/bcm2836.cfg +++ b/tcl/target/bcm2836.cfg @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# The Broadcom chip used in the Raspberry Pi 2 Model B +# The Broadcom chip used in the Raspberry Pi 2 Model B v1.1 -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2836 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bcm2837.cfg b/tcl/target/bcm2837.cfg index 749de31037..d41892c431 100644 --- a/tcl/target/bcm2837.cfg +++ b/tcl/target/bcm2837.cfg @@ -3,9 +3,9 @@ # This is the Broadcom chip used in the Raspberry Pi 3, # and in later models of the Raspberry Pi 2. -# Partial information is available in raspberry pi website: -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837 -# https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2837b0 +# Partial information is available on the Raspberry Pi website: +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837 +# https://www.raspberrypi.com/documentation/computers/processors.html#bcm2837b0 if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME diff --git a/tcl/target/bl616.cfg b/tcl/target/bl616.cfg new file mode 100644 index 0000000000..ee59f18508 --- /dev/null +++ b/tcl/target/bl616.cfg @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Author: Marek Kraus + +# +# Bouffalo Labs BL616 and BL618 target +# +# Default JTAG pins: (if not changed by eFuse configuration) +# TMS - GPIO0 +# TCK - GPIO1 +# TDO - GPIO2 +# TDI - GPIO3 +# + +source [find mem_helper.tcl] + +transport select jtag + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME bl616 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10000b6f + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME + +riscv set_mem_access progbuf +riscv set_enable_virt2phys off + +$_TARGETNAME configure -work-area-phys 0x40000000 -work-area-size 0x10000 -work-area-backup 1 + +adapter speed 4000 + +# Useful functions +set dmcontrol 0x10 +set dmcontrol_dmactive [expr {1 << 0}] +set dmcontrol_haltreq [expr {1 << 31}] + +# By spec, ndmreset should reset whole chip. This implementation resets only few parts of the chip. +# CTRL_PWRON_RESET register in GLB core triggers full "power-on like" reset, so we use it instead +# for full software reset. +$_TARGETNAME configure -event reset-assert { + halt + + # To stay in BootROM until JTAG re-attaches, we are using BootROM functionality + # to force ISP mode, so BootROM looks out for external ISP communication. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 1 (ISP) + mww 0x2000f108 0x44000000 + + # Switch clock to internal RC32M + # In HBN_GLB, set ROOT_CLK_SEL = 0 + mmw 0x2000f030 0x0 0x00000002 + + # In GLB_SYS_CFG0, set REG_BCLK_DIV and REG_HCLK_DIV = 0 + mmw 0x20000090 0x0 0x00FFFF00 + + # Trigger BCLK ACT pulse + # In GLB_SYS_CFG1, set BCLK_DIV_ACT_PULSE = 1 + mmw 0x20000094 0x1 0x00000001 + # In GLB_SYS_CFG1, wait for GLB_STS_BCLK_PROT_DONE to become 1 + while { [expr {[mrw 0x20000094] & 4}] == 0 } { sleep 1 } + + # In GLB_SWRST_CFG2, clear CTRL_PWRON_RESET + mmw 0x20000548 0x0 0x00000001 + + # This Software reset method resets everything, so CPU as well. + # It does that in not much good way, resulting in Debug Module being reset as well. + # This also means, that right after CPU and Debug Module are turned on, we need to + # enable Debug Module and halt CPU if needed. Additionally, we trigger this SW reset + # through program buffer access directly with DMI commands, to avoid errors printed by + # OpenOCD about unsuccessful register write. + + # In GLB_SWRST_CFG2, set CTRL_PWRON_RESET to 1 + set_reg {fp 0x20000548 s1 0x01} + riscv dmi_write 0x20 0x00942023 + riscv dmi_write 0x17 0x40000 + + # We need to wait for chip to finish reset and execute BootROM + sleep 10 + + # JTAG Debug Transport Module is reset as well, so we need to get into RUN/IDLE state + runtest 10 + + # We need to enable Debug Module and halt the CPU, so we can reset Program Counter + # and to do additional clean-ups. If reset was called without halt, resume is handled + # by reset-deassert-post event handler. + + # In Debug Module Control (dmcontrol), set dmactive to 1 and then haltreq to 1 + riscv dmi_write $::dmcontrol $::dmcontrol_dmactive + riscv dmi_write $::dmcontrol [ expr {$::dmcontrol_dmactive | $::dmcontrol_haltreq} ] +} + +$_TARGETNAME configure -event reset-deassert-post { + # Set Program Counter to start of BootROM and execute one instruction + step 0x90000000 + + # When using default JTAG pinout, BOOT pin is the same as JTAG TDO pin. + # Since after reset we set PC to start of the BootROM, + # BootROM will execute also check of BOOT pin, which will disable TDO pin, + # to check the BOOT pin state. This leads to temporary loss of JTAG access + # and causes (recoverable) errors in OpenOCD. We can bypass the BOOT pin check + # function, by forcing booting from Media/SPI Flash. + + # In HBN_RSV2, set HBN_RELEASE_CORE to HBN_RELEASE_CORE_FLAG (4) + # and HBN_USER_BOOT_SEL to 2 (Media/SPI Flash) + mww 0x2000f108 0x48000000 + + # Resume the processor if reset was triggered without halt request + if {$halt == 0} { + resume + } +} + +# According to JTAG spec (IEEE 1149.1), when chip enters "Test-Logic-Reset" state, +# the IR instruction should be set to "IDCODE" or "BYPASS" (when chip does not have IDCODE). +# This is done so automatic chain scan can detect all the chips within JTAG chain without knowing IDCODE. +# JTAG Debug Transport Module (DTM) used in this chip, developed by T-Head (formerly C-Sky) +# does not implement this, so OpenOCD can't detect the chip anymore after the IR instruction is changed. +# This workaround gets chip into known state, and manually set IR instruction to IDCODE, +# which is 0x01, standardized by RISC-V Debug Specification. +proc init_reset { mode } { + if {[using_jtag]} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + jtag arp_init-reset + } +} + +proc jtag_init {} { + # Get JTAG SM to known state + runtest 10 + # Set IR to IDCODE + irscan $::_CHIPNAME.cpu 0x01 + + if {[catch {jtag arp_init} err]!=0} { + # try resetting additionally + init_reset startup + } +} diff --git a/tcl/target/lsch3_common.cfg b/tcl/target/lsch3_common.cfg index f48d59b9d8..ad88b2e1b3 100644 --- a/tcl/target/lsch3_common.cfg +++ b/tcl/target/lsch3_common.cfg @@ -51,8 +51,8 @@ proc release_cpu {cpu} { } # Release the cpu; it will start executing something bogus - mem2array regs 32 $RST_BRRL 1 - mww $RST_BRRL [expr {$regs(0) | 1 << $cpu}] + set reg [read_memory $RST_BRRL 32 1] + mww $RST_BRRL [expr {$reg | 1 << $cpu}] if {$not_halted} { resume diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg index f3a9f84c88..807f8145e0 100644 --- a/tcl/target/max32620.cfg +++ b/tcl/target/max32620.cfg @@ -1,32 +1,20 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX32620 OpenOCD target configuration file -# www.maximintegrated.com -# adapter speed -adapter speed 4000 - -# reset pin configuration +# Set the reset pin configuration reset_config srst_only +adapter srst delay 200 -if {[using_jtag]} { - jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version -} else { - swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version -} - -dap create max32620.dap -chain-position max32620.cpu +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x200000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -# target configuration -target create max32620.cpu cortex_m -dap max32620.dap -max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 +# Setup the reserved TAP +set RSV_TAP 1 -# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] -# flash bank max32xxx 0 0 -# max32620 flash base address 0x00000000 -# max32620 flash size 0x200000 (2MB) -# max32620 FLC base address 0x40002000 -# max32620 sector (page) size 0x2000 (8kB) -# max32620 clock speed 96 (MHz) -flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96 +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg index 90eb392668..8d9479c39b 100644 --- a/tcl/target/max32625.cfg +++ b/tcl/target/max32625.cfg @@ -1,32 +1,20 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX32625 OpenOCD target configuration file -# www.maximintegrated.com -# adapter speed -adapter speed 4000 - -# reset pin configuration +# Set the reset pin configuration reset_config srst_only +adapter srst delay 200 -if {[using_jtag]} { - jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version -} else { - swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version -} - -dap create max32625.dap -chain-position max32625.cpu +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -# target configuration -target create max32625.cpu cortex_m -dap max32625.dap -max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 +# Setup the reserved TAP +set RSV_TAP 1 -# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] -# flash bank max32xxx 0 0 -# max32625 flash base address 0x00000000 -# max32625 flash size 0x80000 (512k) -# max32625 FLC base address 0x40002000 -# max32625 sector (page) size 0x2000 (8kB) -# max32625 clock speed 96 (MHz) -flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96 +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg index 852e04af1e..413c49188b 100644 --- a/tcl/target/max3263x.cfg +++ b/tcl/target/max3263x.cfg @@ -1,32 +1,40 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Maxim Integrated MAX3263X OpenOCD target configuration file -# www.maximintegrated.com -# adapter speed -adapter speed 4000 +# Set the reset pin configuration +reset_config none -# reset pin configuration -reset_config srst_only +# Set flash parameters +set FLASH_BASE 0x0 +set FLASH_SIZE 0x200000 +set FLC_BASE 0x40002000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x00 -if {[using_jtag]} { - jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version - jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version -} else { - swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version -} +# Setup the reserved TAP +set RSV_TAP 1 + +source [find target/max32xxx_common.cfg] + +# Create custom reset sequence +$_CHIPNAME.cpu configure -event reset-init { -dap create max3263x.dap -chain-position max3263x.cpu + # Reset the peripherals + mww 0x40000848 0xFFFFFFFF + mww 0x4000084C 0xFFFFFFFF -# target configuration -target create max3263x.cpu cortex_m -dap max3263x.dap -max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000 + sleep 10 -# Config Command: flash bank name driver base size chip_width bus_width target [driver_options] -# flash bank max32xxx 0 0 -# max3263x flash base address 0x00000000 -# max3263x flash size 0x200000 (2MB) -# max3263x FLC base address 0x40002000 -# max3263x sector (page) size 0x2000 (8kB) -# max3263x clock speed 96 (MHz) -flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96 + mww 0x40000848 0x0 + mww 0x4000084C 0x0 + + # Reset the SP + set SP_ADDR [mrw 0x0] + reg sp $SP_ADDR + + # Reset the PC to the Reset_Handler + set RESET_HANDLER_ADDR [mrw 0x4] + reg pc $RESET_HANDLER_ADDR +} diff --git a/tcl/target/max32670.cfg b/tcl/target/max32670.cfg new file mode 100644 index 0000000000..b8c76af5e1 --- /dev/null +++ b/tcl/target/max32670.cfg @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# maxim Integrated OpenOCD target configuration file + +# reset pin configuration +reset_config none +adapter_nsrst_delay 200 +adapter_nsrst_assert_width 200 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x60000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx.cfg] + +# Early revisions of the MAX32670 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} {catch {bp 0x00002174 2 hw}} +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x00002174 + } +} diff --git a/tcl/target/max32672.cfg b/tcl/target/max32672.cfg new file mode 100644 index 0000000000..26c7c82dbc --- /dev/null +++ b/tcl/target/max32672.cfg @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# maxim Integrated OpenOCD target configuration file + +# reset pin configuration +reset_config none +adapter_nsrst_delay 200 +adapter_nsrst_assert_width 200 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx.cfg] + +# Add additional flash bank +set FLASH_BASE 0x10080000 +set FLC_BASE 0x40029400 + +flash bank $_CHIPNAME.flash1 max32xxx $FLASH_BASE $FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$FLC_BASE $FLASH_SECTOR $FLASH_CLK $FLASH_OPTIONS diff --git a/tcl/target/max32675.cfg b/tcl/target/max32675.cfg new file mode 100644 index 0000000000..cbc718c9c7 --- /dev/null +++ b/tcl/target/max32675.cfg @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# maxim Integrated OpenOCD target configuration file + +# reset pin configuration +reset_config none +adapter_nsrst_delay 200 +adapter_nsrst_assert_width 200 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x60000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 96 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx.cfg] + +# Early revisions of the MAX3275 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} {catch {bp 0x00002174 2 hw}} +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x00002174 + } +} diff --git a/tcl/target/max32680.cfg b/tcl/target/max32680.cfg new file mode 100644 index 0000000000..9c3ad24bdd --- /dev/null +++ b/tcl/target/max32680.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32655 OpenOCD target configuration file + +adapter speed 500 + +# Set the reset pin configuration +reset_config srst_only +adapter srst delay 2 +adapter srst pulse_width 2 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x80000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x2000 +set FLASH_CLK 100 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx_common.cfg] diff --git a/tcl/target/max32690.cfg b/tcl/target/max32690.cfg new file mode 100644 index 0000000000..63f987458a --- /dev/null +++ b/tcl/target/max32690.cfg @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated MAX32690 OpenOCD target configuration file + +# Set the reset pin configuration +reset_config srst_only +adapter srst delay 2 +adapter srst pulse_width 2 + +# Set flash parameters +set FLASH_BASE 0x10000000 +set FLASH_SIZE 0x300000 +set FLC_BASE 0x40029000 +set FLASH_SECTOR 0x4000 +set FLASH_CLK 60 +set FLASH_OPTIONS 0x01 + +# Use Serial Wire Debug +transport select swd + +source [find target/max32xxx.cfg] + +# Add additional flash bank +set FLASH_BASE 0x10300000 +set FLASH_SIZE 0x40000 +set FLC_BASE 0x40029400 +set FLASH_SECTOR 0x2000 + +flash bank $_CHIPNAME.flash1 max32xxx $FLASH_BASE $FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$FLC_BASE $FLASH_SECTOR $FLASH_CLK $FLASH_OPTIONS + +# Early revisions of the MAX32690 will disable SWD upon reset. There are reserved address locations +# in the ROM code that can be used to insert breakpoints. +# This workaround will enable SWD for affected revisions. +$_CHIPNAME.cpu configure -event reset-assert-pre { + if {$halt} { + catch {bp 0x0000FFF4 2 hw} + } +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + if {$halt} { + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_poll + $::_CHIPNAME.cpu arp_halt + rbp 0x0000FFF4 + } +} diff --git a/tcl/target/max32xxx_common.cfg b/tcl/target/max32xxx_common.cfg new file mode 100644 index 0000000000..50a7d85e9b --- /dev/null +++ b/tcl/target/max32xxx_common.cfg @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Maxim Integrated max32xxx OpenOCD driver configuration file. +# Contains common settings for max32xxx devices. + +source [find mem_helper.tcl] +source [find target/swj-dp.tcl] + +# Set the adapter speed +if { [info exists ADAPTER_KHZ] } { + set _ADAPTER_KHZ $ADAPTER_KHZ +} else { + set _ADAPTER_KHZ 2000 +} +adapter speed $_ADAPTER_KHZ + +# Target configuration +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME max32xxx +} + +# Add reserved TAP +if { [using_jtag] && [info exists RSV_TAP] } { + jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -ignore-version + jtag newtap rsvtap tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version +} else { + swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -ignore-version +} + + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +target create $_CHIPNAME.cpu cortex_m -dap $_CHIPNAME.dap + +# Enable thread-aware debugging +$_CHIPNAME.cpu configure -rtos hwthread + +# Setup working area +if { [info exists WORK_START] } { + set _WORK_START $WORK_START +} else { + set _WORK_START 0x20005000 +} + +if { [info exists WORK_SIZE] } { + set _WORK_SIZE $WORK_SIZE +} else { + set _WORK_SIZE 0x8000 +} + +$_CHIPNAME.cpu configure -work-area-phys $_WORK_START -work-area-size $_WORK_SIZE + +# Configure flash driver +if { [info exists FLASH_BASE] } { + set _FLASH_BASE $FLASH_BASE +} else { + set _FLASH_BASE 0x10000000 +} + +if { [info exists FLASH_SIZE] } { + set _FLASH_SIZE $FLASH_SIZE +} else { + set _FLASH_SIZE 0x10000 +} + +if { [info exists FLC_BASE] } { + set _FLC_BASE $FLC_BASE +} else { + set _FLC_BASE 0x40029000 +} + +if { [info exists FLASH_SECTOR] } { + set _FLASH_SECTOR $FLASH_SECTOR +} else { + set _FLASH_SECTOR 0x2000 +} + +if { [info exists FLASH_CLK] } { + set _FLASH_CLK $FLASH_CLK +} else { + set _FLASH_CLK 96 +} + +# OPTIONS_128 0x01 /* Perform 128 bit flash writes */ +# OPTIONS_ENC 0x02 /* Encrypt the flash contents */ +# OPTIONS_AUTH 0x04 /* Authenticate the flash contents */ +# OPTIONS_COUNT 0x08 /* Add counter values to authentication */ +# OPTIONS_INTER 0x10 /* Interleave the authentication and count values*/ +# OPTIONS_RELATIVE_XOR 0x20 /* Only XOR the offset of the address when encrypting */ +# OPTIONS_KEYSIZE 0x40 /* Use a 256 bit KEY */ + +if { [info exists FLASH_OPTIONS] } { + set _FLASH_OPTIONS $FLASH_OPTIONS +} else { + set _FLASH_OPTIONS 0 +} + +flash bank $_CHIPNAME.flash max32xxx $_FLASH_BASE $_FLASH_SIZE 0 0 $_CHIPNAME.cpu \ +$_FLC_BASE $_FLASH_SECTOR $_FLASH_CLK $_FLASH_OPTIONS + +# call allow_low_pwr_dbg to set this to 1 +set ALLOW_LOW_PWR_DBG 0 + +proc allow_low_pwr_dbg {} { + global ALLOW_LOW_PWR_DBG + + # set our low-power debug flag + set ALLOW_LOW_PWR_DBG 1 +} + +# enable debug in case of low-power mode +proc enable_debug {} { + set DBGKEY 0xA05F0000 + set C_DEBUGEN 0x00000001 + set C_HALT 0x00000002 + + echo "Enable debug to connect in low-power mode" + + # enable debug + mww 0xE000EDF0 [expr {$DBGKEY | $C_HALT | $C_DEBUGEN}] + + # allow for time waking up + sleep 500 +} + +$_CHIPNAME.cpu configure -event reset-deassert-post { + global ALLOW_LOW_PWR_DBG + + if { $ALLOW_LOW_PWR_DBG == 1 } { + enable_debug + } +} diff --git a/tcl/target/microchip/mpfs.cfg b/tcl/target/microchip/mpfs.cfg new file mode 100644 index 0000000000..3a63e3d3b4 --- /dev/null +++ b/tcl/target/microchip/mpfs.cfg @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: MPFS PolarFire SoC-series processors by Microchip Technologies +# +# https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/polarfire-soc-fpgas +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME mpfs +} + +# Process COREID variable +if { ![exists COREID] } { + set COREID -1 +} + +transport select jtag + +# PolarFire SoC (MPFS) hart id to name lookup table +array set hart_names { + 0 e51 + 1 u54_1 + 2 u54_2 + 3 u54_3 + 4 u54_4 +} + +# MPFS devices table +set mpfs_cpu_tap_info { + MPFS025 0x0f8531cf + MPFS095 0x0f8181cf + MPFS160 0x0f8191cf + MPFS250 0x0f81a1cf + MPFS460 0x0f81b1cf + RTPFS160 0x0f8991cf + RTPFS460 0x0f89b1cf +} + +proc expected_ids {tap_list} { + set str "" + dict for {key value} $tap_list { + append str "-expected-id" " " $value " " + } + + return $str +} + +set irlen 8 +set expected_ids [expected_ids $mpfs_cpu_tap_info] +eval jtag newtap $_CHIPNAME cpu -irlen $irlen $expected_ids -ignore-version + +if {$COREID == -1} { + # Single debug connection to all HART's + set _TARGETNAME_0 $_CHIPNAME.$hart_names(0) + set _TARGETNAME_1 $_CHIPNAME.$hart_names(1) + set _TARGETNAME_2 $_CHIPNAME.$hart_names(2) + set _TARGETNAME_3 $_CHIPNAME.$hart_names(3) + set _TARGETNAME_4 $_CHIPNAME.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $_CHIPNAME.cpu -coreid 1 -rtos hwthread + target create $_TARGETNAME_2 riscv -chain-position $_CHIPNAME.cpu -coreid 2 -rtos hwthread + target create $_TARGETNAME_3 riscv -chain-position $_CHIPNAME.cpu -coreid 3 -rtos hwthread + target create $_TARGETNAME_4 riscv -chain-position $_CHIPNAME.cpu -coreid 4 -rtos hwthread + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 +} else { + # Debug connection to a specific hart + set _TARGETNAME_0 $_CHIPNAME.$hart_names($COREID) + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid $COREID +} + +# Only TRSTn supported +reset_config trst_only diff --git a/tcl/target/microchip/pic64gx.cfg b/tcl/target/microchip/pic64gx.cfg new file mode 100644 index 0000000000..25cef6b237 --- /dev/null +++ b/tcl/target/microchip/pic64gx.cfg @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Target: Pic64gx processor by Microchip Technologies +# +# https://www.microchip.com/en-us/products/microprocessors/64-bit-mpus/pic64gx +# + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME pic64gx +} + +# Process COREID variable +if {![exists COREID]} { + set COREID -1 +} + +transport select jtag + +# PIC64GX hart id to name lookup table +array set hart_names { + 0 e51 + 1 u54_1 + 2 u54_2 + 3 u54_3 + 4 u54_4 +} + +# PIC64GX table +set pic64gx_tap_info { + PIC64GX1000 0x0f8531cf +} + +proc expected_ids {tap_list} { + set str "" + dict for {key value} $tap_list { + append str "-expected-id" " " $value " " + } + + return $str +} + +set irlen 8 +set expected_ids [expected_ids $pic64gx_tap_info] +eval jtag newtap $_CHIPNAME cpu -irlen $irlen $expected_ids -ignore-version + +if {$COREID == -1} { + # Single debug connection to all harts + set _TARGETNAME_0 $_CHIPNAME.$hart_names(0) + set _TARGETNAME_1 $_CHIPNAME.$hart_names(1) + set _TARGETNAME_2 $_CHIPNAME.$hart_names(2) + set _TARGETNAME_3 $_CHIPNAME.$hart_names(3) + set _TARGETNAME_4 $_CHIPNAME.$hart_names(4) + + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid 0 -rtos hwthread + target create $_TARGETNAME_1 riscv -chain-position $_CHIPNAME.cpu -coreid 1 -rtos hwthread + target create $_TARGETNAME_2 riscv -chain-position $_CHIPNAME.cpu -coreid 2 -rtos hwthread + target create $_TARGETNAME_3 riscv -chain-position $_CHIPNAME.cpu -coreid 3 -rtos hwthread + target create $_TARGETNAME_4 riscv -chain-position $_CHIPNAME.cpu -coreid 4 -rtos hwthread + target smp $_TARGETNAME_0 $_TARGETNAME_1 $_TARGETNAME_2 $_TARGETNAME_3 $_TARGETNAME_4 +} else { + # Debug connection to a specific hart + set _TARGETNAME_0 $_CHIPNAME.$hart_names($COREID) + target create $_TARGETNAME_0 riscv -chain-position $_CHIPNAME.cpu -coreid $COREID +} + +# Only TRSTn supported +reset_config trst_only diff --git a/tcl/target/ngultra.cfg b/tcl/target/ngultra.cfg index 9f9814fd75..99dcef81a5 100644 --- a/tcl/target/ngultra.cfg +++ b/tcl/target/ngultra.cfg @@ -48,3 +48,14 @@ for { set _core 0 } { $_core < $_cores } { incr _core } { # Create direct APB and AXI interfaces target create APB mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 0 target create AXI mem_ap -dap $_CHIPNAME.coresight.dap -ap-num 1 + +lappend post_init_commands { + foreach t [target names] { + set dap [$t cget -dap] + set ap [$t cget -ap-num] + $dap apsel $ap + # speed up firmware upload by reducing nb of RUNTEST cycles + echo "NGUltra post-init: $dap AP.$ap set memaccess to 5" + $dap memaccess 5 + } +} diff --git a/tcl/target/nrf_common.cfg b/tcl/target/nordic/common.cfg similarity index 100% rename from tcl/target/nrf_common.cfg rename to tcl/target/nordic/common.cfg diff --git a/tcl/target/nrf51.cfg b/tcl/target/nordic/nrf51.cfg similarity index 100% rename from tcl/target/nrf51.cfg rename to tcl/target/nordic/nrf51.cfg diff --git a/tcl/target/nrf52.cfg b/tcl/target/nordic/nrf52.cfg similarity index 100% rename from tcl/target/nrf52.cfg rename to tcl/target/nordic/nrf52.cfg diff --git a/tcl/target/nrf53.cfg b/tcl/target/nordic/nrf53.cfg similarity index 99% rename from tcl/target/nrf53.cfg rename to tcl/target/nordic/nrf53.cfg index 307df902c2..0dcfd55eca 100644 --- a/tcl/target/nrf53.cfg +++ b/tcl/target/nordic/nrf53.cfg @@ -60,7 +60,7 @@ if { ![using_hla] } { # Keep adapter speed less or equal 2000 kHz or flash programming fails! adapter speed 1000 -source [find target/nrf_common.cfg] +source [find target/nordic/common.cfg] flash bank $_CHIPNAME.app.flash nrf5 0x00000000 0 0 0 $_TARGETNAME_APP flash bank $_CHIPNAME.app.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME_APP diff --git a/tcl/target/nrf91.cfg b/tcl/target/nordic/nrf91.cfg similarity index 97% rename from tcl/target/nrf91.cfg rename to tcl/target/nordic/nrf91.cfg index e0ff4e5460..64ed864e75 100644 --- a/tcl/target/nrf91.cfg +++ b/tcl/target/nordic/nrf91.cfg @@ -45,7 +45,7 @@ adapter speed 1000 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -source [find target/nrf_common.cfg] +source [find target/nordic/common.cfg] flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME flash bank $_CHIPNAME.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME diff --git a/tcl/target/qualcomm/qcs6490.cfg b/tcl/target/qualcomm/qcs6490.cfg new file mode 100644 index 0000000000..d12708c8a2 --- /dev/null +++ b/tcl/target/qualcomm/qcs6490.cfg @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# The QCS6490/QCM6490 is a 6nm processor designed for enterprise and Internet of Things (IOT) applications, +# featuring global 5G and Wi-Fi 6E support +# +# Product Page: +# https://www.qualcomm.com/products/internet-of-things/industrial/building-enterprise/qcs6490 +# https://www.qualcomm.com/products/internet-of-things/industrial/building-enterprise/qcm6490 + +source [find target/swj-dp.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME QCS6490 +} + +if { [info exists ENDIAN] } { + set _ENDIAN $ENDIAN +} else { + set _ENDIAN little +} + +adapter speed 500 +reset_config trst_and_srst + +# Set CUP TAP ID based on protocol selection +if { [using_jtag] } { + set _CPUTAPID 0x5ba00477 +} else { + set _CPUTAPID 0x5ba02477 +} + +swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID -irlen 4 + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -ignore-syspwrupack + +cti create $_CHIPNAME.cti -dap $_CHIPNAME.dap -baseaddr 0x87020000 -ap-num 1 + +target create $_CHIPNAME.cpu0 aarch64 -endian $_ENDIAN -dap $_CHIPNAME.dap -coreid 0 \ + -dbgbase 0x87010000 -cti $_CHIPNAME.cti -event reset-assert-post { dap init } + +$_CHIPNAME.cpu0 configure -event examine-end { + eval $_CHIPNAME.cpu0 arp_halt +} + +# Default breakpoints to hardware breakpoints +gdb_breakpoint_override hard diff --git a/tcl/target/rk3588.cfg b/tcl/target/rk3588.cfg new file mode 100644 index 0000000000..7b470268a1 --- /dev/null +++ b/tcl/target/rk3588.cfg @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Rockchip RK3588 Target +# https://www.rock-chips.com/a/en/products/RK35_Series/2022/0926/1660.html +# Andreas Dannenberg + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME rk3588 +} + +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x2ba01477 +} + +adapter speed 4000 + +transport select swd + +# Declare the one SWD tap to access the DAP +swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID + +# Create the DAP +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +# Create target to allow accessing system memory directly +target create $_CHIPNAME.ahb mem_ap -dap $_CHIPNAME.dap -ap-num 0 + +# Declare the 8 main application cores (4 little cores + 4 big cores) + +# Little cluster (cores 0..3) +set _TARGETNAME $_CHIPNAME.lcore +set $_TARGETNAME.base(0) 0x81004000 +set $_TARGETNAME.base(1) 0x81005000 +set $_TARGETNAME.base(2) 0x81006000 +set $_TARGETNAME.base(3) 0x81007000 +set $_TARGETNAME.cti(0) 0x81014000 +set $_TARGETNAME.cti(1) 0x81015000 +set $_TARGETNAME.cti(2) 0x81016000 +set $_TARGETNAME.cti(3) 0x81017000 + +# Big cluster (cores 4..7) +set _TARGETNAME $_CHIPNAME.bcore +set $_TARGETNAME.base(4) 0x81024000 +set $_TARGETNAME.base(5) 0x81025000 +set $_TARGETNAME.base(6) 0x81026000 +set $_TARGETNAME.base(7) 0x81027000 +set $_TARGETNAME.cti(4) 0x81034000 +set $_TARGETNAME.cti(5) 0x81035000 +set $_TARGETNAME.cti(6) 0x81036000 +set $_TARGETNAME.cti(7) 0x81037000 + +# Build string used to enable SMP mode +set _smp_command "target smp" + +set _cores 8 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + if {$_core < 4} { + set _TARGETNAME $_CHIPNAME.lcore + } else { + set _TARGETNAME $_CHIPNAME.bcore + } + + cti create cti$_core -dap $_CHIPNAME.dap -baseaddr [set $_TARGETNAME.cti($_core)] -ap-num 0 + + target create ${_TARGETNAME}$_core aarch64 \ + -dap $_CHIPNAME.dap -coreid $_core -cti cti$_core \ + -dbgbase [set $_TARGETNAME.base($_core)] + + if { $_core != 0 } { + # non-boot core examination may fail + ${_TARGETNAME}$_core configure -defer-examine + } else { + # uncomment to use hardware threads pseudo rtos + # ${_TARGETNAME}$_core configure -rtos hwthread + } + + set _smp_command "$_smp_command ${_TARGETNAME}$_core" +} + +eval $_smp_command + +# Set default target to boot core +targets $_CHIPNAME.lcore0 diff --git a/tcl/target/rp2040.cfg b/tcl/target/rp2040.cfg index f64d4322b1..262de44186 100644 --- a/tcl/target/rp2040.cfg +++ b/tcl/target/rp2040.cfg @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # RP2040 is a microcontroller with dual Cortex-M0+ core. -# https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2040 # The device requires multidrop SWD for debug. transport select swd @@ -83,9 +83,9 @@ if { $_USE_CORE != 1 } { # srst does not exist; use SYSRESETREQ to perform a soft reset $_TARGETNAME_0 cortex_m reset_config sysresetreq - # After a rescue reset and fi BOOTSEL is halted connect the flash to enable + # After a rescue reset or if halted in BOOTSEL connect the flash to enable # reads from the XIP cached mapping area - $_TARGETNAME_0 configure -event reset-init { rp2xxx rom_api_call 0 CX } + $_TARGETNAME_0 configure -event reset-init { rp2xxx rom_api_call CX } } # core 1 diff --git a/tcl/target/rp2350.cfg b/tcl/target/rp2350.cfg index b7617acd4c..96bb9298fb 100644 --- a/tcl/target/rp2350.cfg +++ b/tcl/target/rp2350.cfg @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # RP2350 is a microcontroller with dual Cortex-M33 cores or dual Hazard3 RISC-V cores. -# https://www.raspberrypi.com/documentation/microcontrollers/rp2350.html +# https://www.raspberrypi.com/documentation/microcontrollers/silicon.html#rp2350 transport select swd diff --git a/tcl/target/stm32mp13x.cfg b/tcl/target/st/stm32mp13x.cfg similarity index 67% rename from tcl/target/stm32mp13x.cfg rename to tcl/target/st/stm32mp13x.cfg index bcf25c9049..164e0ff1fa 100644 --- a/tcl/target/stm32mp13x.cfg +++ b/tcl/target/st/stm32mp13x.cfg @@ -46,7 +46,7 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 -target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 +target create $_CHIPNAME.cpu cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -defer-examine $_CHIPNAME.cpu cortex_a maskisr on $_CHIPNAME.cpu cortex_a dacrfixup on @@ -76,27 +76,59 @@ proc axi_nsecure {} { axi_secure -proc dbgmcu_enable_debug {} { +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP1 +proc _enable_debug {} { # keep clock enabled in low-power - ## catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} + catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000004} # freeze watchdog 1 and 2 on core halted catch {$::_CHIPNAME.ap1 mww 0xe008102c 0x00000004} catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } -proc toggle_cpu_dbg_claim0 {} { - # toggle CPU0 DBG_CLAIM[0] - $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 - $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP1 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap1 read_memory 0xe0081004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0xe00d0300 0 + target_mmw $::_CHIPNAME.ap1 0xe00d0088 0x00004000 0 + } + + $::_CHIPNAME.ap1 mww 0xe0081004 0x7 } # FIXME: most of handlers below will be removed once reset framework get merged +$_CHIPNAME.ap1 configure -event reset-assert-post { + adapter assert srst +} + $_CHIPNAME.ap1 configure -event reset-deassert-pre { adapter deassert srst deassert trst - catch {dap init} - catch {$::_CHIPNAME.dap apid 1} + $::_CHIPNAME.ap1 arp_examine + _handshake_with_wrapper $halt + _enable_debug + $::_CHIPNAME.cpu arp_examine + if { $halt } { + $::_CHIPNAME.cpu arp_halt + } +} + +$_CHIPNAME.ap1 configure -event examine-end { + _enable_debug + $::_CHIPNAME.cpu arp_examine } -$_CHIPNAME.cpu configure -event reset-deassert-pre {$::_CHIPNAME.cpu arp_examine} -$_CHIPNAME.cpu configure -event reset-deassert-post {toggle_cpu_dbg_claim0; dbgmcu_enable_debug} -$_CHIPNAME.ap1 configure -event examine-start {dap init} -$_CHIPNAME.ap1 configure -event examine-end {dbgmcu_enable_debug} diff --git a/tcl/target/stm32mp15x.cfg b/tcl/target/st/stm32mp15x.cfg similarity index 59% rename from tcl/target/stm32mp15x.cfg rename to tcl/target/st/stm32mp15x.cfg index bcdda73e90..979a5a491e 100644 --- a/tcl/target/stm32mp15x.cfg +++ b/tcl/target/st/stm32mp15x.cfg @@ -18,6 +18,17 @@ if { [info exists CHIPNAME] } { set _CHIPNAME stm32mp15x } +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA7_0] } { + set EN_CA7_0 1 +} +if { ! [info exists EN_CA7_1] } { + set EN_CA7_1 1 +} +if { ! [info exists EN_CM4] } { + set EN_CM4 1 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -42,20 +53,21 @@ if { [using_jtag] } { dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap -ignore-syspwrupack -# FIXME: Cortex-M code requires target accessible during reset, but this is not possible in STM32MP1 -# so defer-examine it until the reset framework get merged # NOTE: keep ap-num and dbgbase to speed-up examine after reset # NOTE: do not change the order of target create target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 0 -target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 +target create $_CHIPNAME.cpu0 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 0 -dbgbase 0xE00D0000 -defer-examine +target create $_CHIPNAME.cpu1 cortex_a -dap $_CHIPNAME.dap -ap-num 1 -coreid 1 -dbgbase 0xE00D2000 -defer-examine target create $_CHIPNAME.cm4 cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine targets $_CHIPNAME.cpu0 target smp $_CHIPNAME.cpu0 $_CHIPNAME.cpu1 +$_CHIPNAME.cpu0 configure -rtos hwthread +$_CHIPNAME.cpu1 configure -rtos hwthread + $_CHIPNAME.cpu0 cortex_a maskisr on $_CHIPNAME.cpu1 cortex_a maskisr on $_CHIPNAME.cpu0 cortex_a dacrfixup on @@ -96,7 +108,16 @@ proc axi_nsecure {} { axi_secure -proc dbgmcu_enable_debug {} { +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP1 +proc _enable_debug {} { # set debug enable bits in DBGMCU_CR to get ap2 and cm4 visible catch {$::_CHIPNAME.ap1 mww 0xe0081004 0x00000007} # freeze watchdog 1 and 2 on cores halted @@ -104,30 +125,97 @@ proc dbgmcu_enable_debug {} { catch {$::_CHIPNAME.ap1 mww 0xe008104c 0x00000008} } -proc toggle_cpu0_dbg_claim0 {} { - # toggle CPU0 DBG_CLAIM[0] - $::_CHIPNAME.ap1 mww 0xe00d0fa0 1 - $::_CHIPNAME.ap1 mww 0xe00d0fa4 1 +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP1 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap1 read_memory 0xe0081004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + $::_CHIPNAME.ap1 arp_halt + if { $::EN_CA7_0 } { + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0xe00d0300 0 + target_mmw $::_CHIPNAME.ap1 0xe00d0088 0x00004000 0 + } + } + + $::_CHIPNAME.ap1 mww 0xe0081004 0x7 } -proc detect_cpu1 {} { +lappend _telnet_autocomplete_skip _detect_cpu1 +# Uses AP1 +proc _detect_cpu1 {} { + if { !$::EN_CA7_1 } { + return + } + set cpu1_prsr [$::_CHIPNAME.ap1 read_memory 0xE00D2314 32 1] set dual_core [expr {$cpu1_prsr & 1}] - if {! $dual_core} {$::_CHIPNAME.cpu1 configure -defer-examine} + if { !$dual_core } { + set ::EN_CA7_1 0 + } } -proc rcc_enable_traceclk {} { +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +proc _rcc_enable_traceclk {} { $::_CHIPNAME.ap2 mww 0x5000080c 0x301 } # FIXME: most of handler below will be removed once reset framework get merged -$_CHIPNAME.ap1 configure -event reset-deassert-pre {adapter deassert srst deassert trst;catch {dap init};catch {$::_CHIPNAME.dap apid 1}} -$_CHIPNAME.ap2 configure -event reset-deassert-pre {dbgmcu_enable_debug;rcc_enable_traceclk} -$_CHIPNAME.cpu0 configure -event reset-deassert-pre {$::_CHIPNAME.cpu0 arp_examine} -$_CHIPNAME.cpu1 configure -event reset-deassert-pre {$::_CHIPNAME.cpu1 arp_examine allow-defer} -$_CHIPNAME.cpu0 configure -event reset-deassert-post {toggle_cpu0_dbg_claim0} -$_CHIPNAME.cm4 configure -event reset-deassert-post {$::_CHIPNAME.cm4 arp_examine;if {[$::_CHIPNAME.ap2 curstate] == "halted"} {$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_poll;$::_CHIPNAME.cm4 arp_halt}} -$_CHIPNAME.ap1 configure -event examine-start {dap init} -$_CHIPNAME.ap2 configure -event examine-start {dbgmcu_enable_debug} -$_CHIPNAME.cpu0 configure -event examine-end {detect_cpu1} -$_CHIPNAME.ap2 configure -event examine-end {rcc_enable_traceclk;$::_CHIPNAME.cm4 arp_examine} +$_CHIPNAME.cm4 configure -event reset-assert { } + +$_CHIPNAME.ap1 configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.ap1 configure -event reset-deassert-pre { + adapter deassert srst deassert trst + $::_CHIPNAME.ap1 arp_examine + _handshake_with_wrapper $halt + if { $::EN_CA7_0 } { + $::_CHIPNAME.cpu0 arp_examine + if { $halt } { + $::_CHIPNAME.cpu0 arp_halt + } + } + if { $::EN_CA7_1 } { + $::_CHIPNAME.cpu1 arp_examine + if { $halt } { + $::_CHIPNAME.cpu1 arp_halt + } + } + _enable_debug +} + +$_CHIPNAME.ap2 configure -event reset-deassert-pre { + _rcc_enable_traceclk + if { $::EN_CM4 } { + $::_CHIPNAME.cm4 arp_examine + if { $halt } { + $::_CHIPNAME.cm4 arp_halt + } + } +} + +$_CHIPNAME.ap1 configure -event examine-end { + _enable_debug + _detect_cpu1 + if { $::EN_CA7_0 } { + $::_CHIPNAME.cpu0 arp_examine + } + if { $::EN_CA7_1 } { + $::_CHIPNAME.cpu1 arp_examine + } +} + +$_CHIPNAME.ap2 configure -event examine-end { + _rcc_enable_traceclk + if { $::EN_CM4 } { + $::_CHIPNAME.cm4 arp_examine + } +} diff --git a/tcl/target/st/stm32mp21x.cfg b/tcl/target/st/stm32mp21x.cfg new file mode 100644 index 0000000000..f4073a9f5c --- /dev/null +++ b/tcl/target/st/stm32mp21x.cfg @@ -0,0 +1,222 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP21x +# STM32MP21x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp21x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35] } { + set EN_CA35 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16503041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.ap1 mem_ap -dap $_CHIPNAME.dap -ap-num 1 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 2 +target create $_CHIPNAME.ap3 mem_ap -dap $_CHIPNAME.dap -ap-num 3 -defer-examine + +# define the Cortex-A35 +cti create $_CHIPNAME.cti.a35 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80220000 +target create $_CHIPNAME.a35 aarch64 -dap $_CHIPNAME.dap -ap-num 1 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 3 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 3 -baseaddr 0xe0042000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80080000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80090000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x800A0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 1 -baseaddr 0x80040000 + +targets $_CHIPNAME.a35 + +reset_config srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 2 +$_CHIPNAME.dap apcsw 0x12800000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # Enable DBGMCU clock in RC + $::_CHIPNAME.axi mww 0x44200520 0x500 + + # set debug enable bits in DBGMCU_CR to get ap3/cm33 visible + $::_CHIPNAME.ap0 mww 0x80001004 0x7 + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x440a003c 0x00000026 + $::_CHIPNAME.axi mww 0x440a0040 0x00000038 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0, AP1 and AP3 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80001004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return + } + + if { $halt } { + if { $::EN_CA35 } { + $::_CHIPNAME.ap1 arp_examine + $::_CHIPNAME.ap1 arp_halt + $::_CHIPNAME.ap1 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap1 0x80210088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.ap3 arp_halt + $::_CHIPNAME.ap3 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80001004 0x07 +} + +lappend _telnet_autocomplete_skip _enable_dbgmcu_on_devboot +# In DEV BOOT the BootROM does not completes the sequence to enable the +# visibility of DBGMCU on AP0. +# Write a value in DBGMCU_DBG_AUTH_DEV from CID1. +# Returns 1 if DEV BOOT is detected +# Uses AP2 (AXI bus) +proc _enable_dbgmcu_on_devboot {} { + $::_CHIPNAME.axi mww 0x44230004 0 + set boot_pins [expr {[$::_CHIPNAME.axi read_memory 0x44230000 32 1] & 0xf}] + if {$boot_pins != 0x3 && $boot_pins != 0xc} { + return 0 + } + + set rifsc_rimc_cr [$::_CHIPNAME.axi read_memory 0x42080c00 32 1] + if {$rifsc_rimc_cr != 0x00008710} { + echo "RIFSC_RIMC_CR modified, skip activation of DBGMCU" + return 1 + } + + # Enable DBGMCU clock in RC + $::_CHIPNAME.axi mww 0x44200520 0x500 + + # Change DAP (AXI) CID, write in DBGMCU, set back DAP CID + $::_CHIPNAME.axi mww 0x42080c00 0x00008110 + $::_CHIPNAME.axi mww 0x440A0104 1 + $::_CHIPNAME.axi mww 0x42080c00 0x00008710 + return 1 +} + +$_CHIPNAME.m33 configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + $::_CHIPNAME.axi arp_examine + set is_dev_boot [_enable_dbgmcu_on_devboot] + if { !$is_dev_boot } { + _handshake_with_wrapper $halt + } + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35 } { + $::_CHIPNAME.a35 arp_examine + if { $halt } { + $::_CHIPNAME.a35 arp_halt + } + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.ap3 arp_halt + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.axi configure -event examine-end { + set is_dev_boot [_enable_dbgmcu_on_devboot] + if { $is_dev_boot } { + echo "Dev boot detected" + } + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35 } { + $::_CHIPNAME.a35 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap3 arp_examine + $::_CHIPNAME.m33 arp_examine + } +} diff --git a/tcl/target/st/stm32mp23x.cfg b/tcl/target/st/stm32mp23x.cfg new file mode 100644 index 0000000000..015f816e43 --- /dev/null +++ b/tcl/target/st/stm32mp23x.cfg @@ -0,0 +1,215 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP23x +# STM32MP23x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp23x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35_0] } { + set EN_CA35_0 1 +} +if { ! [info exists EN_CA35_1] } { + set EN_CA35_1 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16505041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 4 +target create $_CHIPNAME.ap8 mem_ap -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + +# define the first Cortex-A35 +cti create $_CHIPNAME.cti.a35_0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80220000 +target create $_CHIPNAME.a35_0 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35_0 -defer-examine + +# define the second Cortex-A35 +cti create $_CHIPNAME.cti.a35_1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80320000 +target create $_CHIPNAME.a35_1 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80310000 \ + -cti $_CHIPNAME.cti.a35_1 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr 0xe0042000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80090000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800a0000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800b0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80050000 + +targets $_CHIPNAME.a35_0 + +target smp $_CHIPNAME.a35_0 $_CHIPNAME.a35_1 +$_CHIPNAME.a35_0 configure -rtos hwthread +$_CHIPNAME.a35_1 configure -rtos hwthread + +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 4 +$_CHIPNAME.dap apcsw 0x12800000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # set debug enable bits in DBGMCU_CR to get ap8/cm33 visible + $::_CHIPNAME.ap0 mww 0x80010004 0x17 + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x4a010008 0x00000000 + $::_CHIPNAME.axi mww 0x4a01003c 0x00000026 + $::_CHIPNAME.axi mww 0x4a010040 0x00000038 + $::_CHIPNAME.axi mww 0x4a010044 0x00000400 + $::_CHIPNAME.axi mww 0x4a010048 0x00000400 + $::_CHIPNAME.axi mww 0x4a01004c 0x00000600 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80010004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return; + } + + if { $halt } { + if { $::EN_CA35_0 || $::EN_CA35_1 } { + $::_CHIPNAME.ap0 arp_examine + $::_CHIPNAME.ap0 arp_halt + } + if { $::EN_CA35_0 } { + $::_CHIPNAME.ap0 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap0 0x80210088 0x00004000 0 + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.ap0 mww 0x80310300 0 + target_mmw $::_CHIPNAME.ap0 0x80310088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.ap8 arp_halt + $::_CHIPNAME.ap8 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80010004 0x17 +} + +$_CHIPNAME.m33 configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + + $::_CHIPNAME.ap0 arp_examine + _handshake_with_wrapper $halt + + $::_CHIPNAME.axi arp_examine + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + if { $halt } { + $::_CHIPNAME.a35_0 arp_halt + } + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + if { $halt } { + $::_CHIPNAME.a35_1 arp_halt + } + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.axi configure -event examine-end { + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + } +} diff --git a/tcl/target/st/stm32mp25x.cfg b/tcl/target/st/stm32mp25x.cfg new file mode 100644 index 0000000000..6807d64a1d --- /dev/null +++ b/tcl/target/st/stm32mp25x.cfg @@ -0,0 +1,247 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# STMicroelectronics STM32MP25x +# STM32MP25x devices support both JTAG and SWD transports. + +# HLA does not support multi-cores nor custom CSW nor AP other than 0 +if { [using_hla] } { + echo "ERROR: HLA transport cannot work with this target." + shutdown +} + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32mp25x +} + +# Set to 0 to prevent CPU examine. Default examine them +if { ! [info exists EN_CA35_0] } { + set EN_CA35_0 1 +} +if { ! [info exists EN_CA35_1] } { + set EN_CA35_1 1 +} +if { ! [info exists EN_CM33] } { + set EN_CM33 1 +} +if { ! [info exists EN_CM0P] } { + set EN_CM0P 1 +} + +set _ENDIAN little + +# jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +# Chip Level TAP Controller, only in jtag mode +if { [info exists CLCTAPID] } { + set _CLCTAPID $CLCTAPID +} else { + set _CLCTAPID 0x16505041 +} + +swj_newdap $_CHIPNAME tap -expected-id $_CPUTAPID -irlen 4 -ircapture 0x01 -irmask 0x0f +if { [using_jtag] } { + swj_newdap $_CHIPNAME.clc tap -expected-id $_CLCTAPID -irlen 5 +} + +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.tap + +# define AXI & APB Memory Access Ports +# NOTE: do not change the order of target create +target create $_CHIPNAME.ap0 mem_ap -dap $_CHIPNAME.dap -ap-num 0 +target create $_CHIPNAME.axi mem_ap -dap $_CHIPNAME.dap -ap-num 4 +target create $_CHIPNAME.ap2 mem_ap -dap $_CHIPNAME.dap -ap-num 2 -defer-examine +target create $_CHIPNAME.ap8 mem_ap -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + +# define the first Cortex-A35 +cti create $_CHIPNAME.cti.a35_0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80220000 +target create $_CHIPNAME.a35_0 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80210000 \ + -cti $_CHIPNAME.cti.a35_0 -defer-examine + +# define the second Cortex-A35 +cti create $_CHIPNAME.cti.a35_1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80320000 +target create $_CHIPNAME.a35_1 aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase 0x80310000 \ + -cti $_CHIPNAME.cti.a35_1 -defer-examine + +# define the Cortex-M33 +target create $_CHIPNAME.m33 cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine +cti create $_CHIPNAME.cti.m33 -dap $_CHIPNAME.dap -ap-num 8 -baseaddr 0xe0042000 + +# define the Cortex-M0+ +target create $_CHIPNAME.m0p cortex_m -dap $_CHIPNAME.dap -ap-num 2 -defer-examine +cti create $_CHIPNAME.cti.m0p -dap $_CHIPNAME.dap -ap-num 2 -baseaddr 0xf0000000 + +# define the system CTIs +cti create $_CHIPNAME.cti.sys0 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80090000 +cti create $_CHIPNAME.cti.sys1 -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800a0000 + +swo create $_CHIPNAME.swo -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x800b0000 +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0x80050000 + +targets $_CHIPNAME.a35_0 + +target smp $_CHIPNAME.a35_0 $_CHIPNAME.a35_1 +$_CHIPNAME.a35_0 configure -rtos hwthread +$_CHIPNAME.a35_1 configure -rtos hwthread + +reset_config srst_gates_jtag srst_pulls_trst + +adapter speed 5000 +adapter srst pulse_width 200 +# wait 1 seconds for bootrom +adapter srst delay 1000 + +# set CSW for AXI +$_CHIPNAME.dap apsel 4 +$_CHIPNAME.dap apcsw 0x12800000 + +# mmw with target selection +proc target_mmw {target reg setbits clearbits} { + set val [eval $target read_memory $reg 32 1] + set val [expr {($val & ~$clearbits) | $setbits}] + eval $target mww $reg $val +} + +lappend _telnet_autocomplete_skip _enable_ap2_cm0p +proc _enable_ap2_cm0p {} { + # set bits C3LPEN and C3EN in RCC_C3CFGR to enable AP2 and CM0+ clock + target_mmw $::_CHIPNAME.axi 0x54200490 6 0 +} + +lappend _telnet_autocomplete_skip _enable_debug +# Uses AP0 and AXI +proc _enable_debug {} { + # set debug enable bits in DBGMCU_CR to get ap2/cm0+ and ap8/cm33 visible + # set DBG_SWD_SEL_N bit in DBGMCU_CR to get ap2/cm0+ on main debug interface + $::_CHIPNAME.ap0 mww 0x80010004 0x17 + + if { $::EN_CM0P } { + _enable_ap2_cm0p + } + + # Freeze watchdogs on CPU halt + $::_CHIPNAME.axi mww 0x4a010008 0x00000000 + $::_CHIPNAME.axi mww 0x4a01003c 0x00000026 + $::_CHIPNAME.axi mww 0x4a010040 0x00000038 + $::_CHIPNAME.axi mww 0x4a010044 0x00000400 + $::_CHIPNAME.axi mww 0x4a010048 0x00000400 + $::_CHIPNAME.axi mww 0x4a01004c 0x00000600 +} + +lappend _telnet_autocomplete_skip _rcc_enable_traceclk +# Uses AXI +proc _rcc_enable_traceclk {} { + # set bit TRACEEN in RCC_DBGCFGR to clock TPIU + target_mmw $::_CHIPNAME.axi 0x44200520 0x200 0 +} + +lappend _telnet_autocomplete_skip _handshake_with_wrapper +# Uses AP0 +proc _handshake_with_wrapper { halt } { + set dbgmcu_cr 0 + catch {set dbgmcu_cr [eval $::_CHIPNAME.ap0 read_memory 0x80010004 32 1]} + if {[expr {($dbgmcu_cr & 0x07) == 0x00}]} { + echo "\nWARNING: FSBL wrapper not detected. Board in dev boot mode?\n" + return; + } + + if { $halt } { + if { $::EN_CA35_0 || $::EN_CA35_1 } { + $::_CHIPNAME.ap0 arp_examine + $::_CHIPNAME.ap0 arp_halt + } + if { $::EN_CA35_0 } { + $::_CHIPNAME.ap0 mww 0x80210300 0 + target_mmw $::_CHIPNAME.ap0 0x80210088 0x00004000 0 + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.ap0 mww 0x80310300 0 + target_mmw $::_CHIPNAME.ap0 0x80310088 0x00004000 0 + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.ap8 arp_halt + $::_CHIPNAME.ap8 mww 0xe000edf0 0xa05f0001 + } + } + + # alert wrapper that debugger is ready + $::_CHIPNAME.ap0 mww 0x80010004 0x17 +} + +$_CHIPNAME.m33 configure -event reset-assert { } +$_CHIPNAME.m0p configure -event reset-assert { } + +$_CHIPNAME.axi configure -event reset-assert-post { + adapter assert srst +} + +$_CHIPNAME.axi configure -event reset-deassert-pre { + adapter deassert srst deassert trst + + $::_CHIPNAME.ap0 arp_examine + _handshake_with_wrapper $halt + + $::_CHIPNAME.axi arp_examine + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + if { $halt } { + $::_CHIPNAME.a35_0 arp_halt + } + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + if { $halt } { + $::_CHIPNAME.a35_1 arp_halt + } + } + if { $::EN_CM0P } { + $::_CHIPNAME.ap2 arp_examine + $::_CHIPNAME.m0p arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + if { $halt } { + $::_CHIPNAME.m33 arp_halt + } + } +} + +$_CHIPNAME.m0p configure -event examine-start { + _enable_ap2_cm0p +} + +$_CHIPNAME.axi configure -event examine-end { + _enable_debug + _rcc_enable_traceclk + if { $::EN_CA35_0 } { + $::_CHIPNAME.a35_0 arp_examine + } + if { $::EN_CA35_1 } { + $::_CHIPNAME.a35_1 arp_examine + } + if { $::EN_CM33 } { + $::_CHIPNAME.ap8 arp_examine + $::_CHIPNAME.m33 arp_examine + } + if { $::EN_CM0P } { + $::_CHIPNAME.ap2 arp_examine + $::_CHIPNAME.m0p arp_examine + } +} diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 35d8275b55..a77527c46d 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -98,6 +98,9 @@ proc _proc_pre_enable_$_CHIPNAME.tpiu {_chipname} { targets $_chipname.cpu if { [$_chipname.tpiu cget -protocol] eq "sync" } { + # Enable the GPIOE clock. + mmw 0x40023830 0x00000010 0x00000010 + switch [$_chipname.tpiu cget -port-width] { 1 { # Set TRACE_IOEN; TRACE_MODE to sync 1 bit; GPIOE[2-3] to AF0 diff --git a/tcl/target/stm32u3x.cfg b/tcl/target/stm32u3x.cfg new file mode 100644 index 0000000000..449c04217b --- /dev/null +++ b/tcl/target/stm32u3x.cfg @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# script for stm32u3x family +# stm32u3x devices support both JTAG and SWD transports. + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32u3x +} + +source [find target/stm32x5x_common.cfg] + +# In order to allow the flash program and erase operations, +# we need to set the voltage scale to range 1 + +proc config_voltage_range {} { + set offset [expr {[stm32x5x_is_secure] ? 0x10000000 : 0}] + # PWR voltage scaling register + set PWR_VOSR [expr {0x4003080C + $offset}] + # PWR supply voltage monitoring control register + set PWR_SVMCR [expr {0x40030810 + $offset}] + # RCC AHB1 peripheral clock enable register 2 + # RCC_AHB1ENR2 = PWREN + mww [expr {0x40030C94 + $offset}] 0x4 + if {(([mrw $PWR_VOSR] & 0x10001) != 0x10001)} { + # PWR_SVMCR = IO2SV + mmw $PWR_SVMCR 0x20000000 0 + # PWR_VOSR : R1EN: Voltage scaling range 1 + mmw $PWR_VOSR 1 3 + # while !(PWR_VOSR & R1RDY) + while {([mrw $PWR_VOSR] & 0x10001) != 0x10001} {} + # Enable EPOD Booster + mmw $PWR_VOSR 0x00000100 0 + # while !(PWR_VOSR & BOOSTRDY) + while {([mrw $PWR_VOSR] & 0x1000000) != 0} {} + } +} + +$_TARGETNAME configure -event reset-init { + config_voltage_range +} diff --git a/tcl/target/stm32x5x_common.cfg b/tcl/target/stm32x5x_common.cfg index fb3aeb18c1..b6370e4936 100644 --- a/tcl/target/stm32x5x_common.cfg +++ b/tcl/target/stm32x5x_common.cfg @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# common script for stm32l5x and stm32u5x families +# common script for stm32l5x, stm32u3x and stm32u5x families # Work-area is a space in RAM used for flash programming # By default use 64kB @@ -16,6 +16,7 @@ if { [info exists CPUTAPID] } { } else { if { [using_jtag] } { # STM32L5x: RM0438 Rev5, Section 52.2.8 JTAG debug port - Table 425. JTAG-DP data registers + # STM32U3x: RM0487 Rev1, Section 53.3.1 JTAG debug port - Table 569. JTAG-DP data registers # STM32U5x: RM0456 Rev1, Section 65.2.8 JTAG debug port - Table 661. JTAG-DP data registers # Corresponds to Cortex®-M33 JTAG debug port ID code set _CPUTAPID 0x0ba04477 diff --git a/tcl/target/ti_tms570ls1x.cfg b/tcl/target/ti_tms570ls1x.cfg new file mode 100644 index 0000000000..3c25777578 --- /dev/null +++ b/tcl/target/ti_tms570ls1x.cfg @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# TMS570LS1114, TMS570LS1115 +# TMS570LS1224, TMS570LS1225, TMS570LS1227 +set DAP_TAPID 0x0B95502F +set JRC_TAPID 0x0B95502F + +source [find target/ti_tms570.cfg] diff --git a/tcl/target/u8500.cfg b/tcl/target/u8500.cfg index 1fdc11fe34..ea3c7218ee 100644 --- a/tcl/target/u8500.cfg +++ b/tcl/target/u8500.cfg @@ -133,7 +133,7 @@ proc enable_apetap {} { set status [$_TARGETNAME_1 curstate] if {[string equal "unknown" $status]} { $_TARGETNAME_1 arp_examine - cache_config l2x 0xa0412000 8 + cache l2x conf 0xa0412000 8 } set status [$_TARGETNAME_2 curstate] diff --git a/tcl/target/vd_riscv.cfg b/tcl/target/vd_riscv.cfg index f08cb1ac8b..44a80524a6 100644 --- a/tcl/target/vd_riscv.cfg +++ b/tcl/target/vd_riscv.cfg @@ -2,15 +2,15 @@ # Cadence virtual debug interface # RISCV core -if {![info exists _HARTID]} { - set _HARTID 0x00 +if {![info exists HARTID]} { + set HARTID 0x00 } -if {![info exists _CHIPNAME]} { - set _CHIPNAME riscv +if {![info exists CHIPNAME]} { + set CHIPNAME riscv } -set _TARGETNAME $_CHIPNAME.cpu +set _TARGETNAME $CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $_HARTID +target create $_TARGETNAME riscv -chain-position $_TARGETNAME -coreid $HARTID riscv set_reset_timeout_sec 120 riscv set_command_timeout_sec 120 diff --git a/testing/Makefile.am b/testing/Makefile.am new file mode 100644 index 0000000000..22778a4c21 --- /dev/null +++ b/testing/Makefile.am @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +SUBDIRS = tcl_commands +DIST_SUBDIRS = tcl_commands diff --git a/testing/tcl_commands/Makefile.am b/testing/tcl_commands/Makefile.am new file mode 100644 index 0000000000..fe8d150707 --- /dev/null +++ b/testing/tcl_commands/Makefile.am @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +TESTS = + +if DUMMY +TESTS += \ + test-target-create-command.cfg \ + test-target-configure-cget-command.cfg +endif + +EXTRA_DIST = utils.tcl $(TESTS) + +TEST_EXTENSIONS = .cfg +CFG_LOG_COMPILER = $(top_builddir)/src/openocd +AM_CFG_LOG_FLAGS = -f $(abs_srcdir)/utils.tcl -f diff --git a/testing/tcl_commands/test-target-configure-cget-command.cfg b/testing/tcl_commands/test-target-configure-cget-command.cfg new file mode 100644 index 0000000000..2d546c83da --- /dev/null +++ b/testing/tcl_commands/test-target-configure-cget-command.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace import testing_helpers::* +namespace import configure_testing::* + +adapter driver dummy +jtag newtap tap cpu -irlen 5 + +{*}[target_create_first_args] {*}[simple_configure_options] + +set target_name [lindex [target names] 0] + +check_matches testee {$target_name cget -type} + +foreach {opt arg} [simple_configure_options] { + check_syntax_err {$target_name cget $opt extra_arg} + check_matches [dict get [simple_configure_options] $opt] \ + {$target_name cget $opt} +} + +check_error_matches .*-event.* {$target_name cget -event} +$target_name cget -event examine-start +check_syntax_err {$target_name cget -event examine-start extra_arg} + +check_syntax_err {$target_name configure} + +foreach {opt arg} [simple_configure_options] { + $target_name configure $opt [$target_name cget $opt] +} + +shutdown diff --git a/testing/tcl_commands/test-target-create-command.cfg b/testing/tcl_commands/test-target-create-command.cfg new file mode 100644 index 0000000000..11264316c3 --- /dev/null +++ b/testing/tcl_commands/test-target-create-command.cfg @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace import testing_helpers::* +namespace import configure_testing::* + +adapter driver dummy +jtag newtap tap cpu -irlen 5 + +check_syntax_err {target create} +check_syntax_err {target create} +check_syntax_err {target create test.target} +check_error_matches -chain-position {target create test.target testee} + +{*}[target_create_first_args] {*}[simple_configure_options] + +foreach {opt arg} [simple_configure_options] { + check_error_matches ".*${opt}.*" {{*}[target_create_first_args] $opt} +} + +foreach {opt1 arg1} [simple_configure_options] { + foreach {opt2 arg2} [simple_configure_options] { + check_error_matches ".*${opt2}.*" \ + {{*}[target_create_first_args] $opt1 $arg1 $opt2} + check_error_matches {} \ + {{*}[target_create_first_args] $opt1 $opt2 $arg2} + } +} + +check_error_matches ".*-type.*" \ + {{*}[target_create_first_args] -type} + +check_error_matches ".*-type.*" \ + {{*}[target_create_first_args] {*}[simple_configure_options] -type} + +check_error_matches {.*-event [^ ]+ .*} \ + {{*}[target_create_first_args] -event} + +check_error_matches {.*not-an-event.*} \ + {{*}[target_create_first_args] -event not-an-event} + +check_error_matches {.*-event examine-start [^ ]+.*} \ + {{*}[target_create_first_args] -event examine-start} + +{*}[target_create_first_args] {*}[simple_configure_options] \ + -event examine-start body +{*}[target_create_first_args] {*}[simple_configure_options] \ + -event examine-start body \ + -event examine-end another-body \ + -event examine-start new-body +{*}[target_create_first_args] -event examine-start body {*}[simple_configure_options] + +{*}[target_create_first_args] {*}[simple_configure_options] -defer-examine + +shutdown diff --git a/testing/tcl_commands/utils.tcl b/testing/tcl_commands/utils.tcl new file mode 100644 index 0000000000..65e52d2fe0 --- /dev/null +++ b/testing/tcl_commands/utils.tcl @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +namespace eval testing_helpers { + + proc test_failure message { + echo $message + shutdown error + } + + proc check_for_error {expctd_code msg_ptrn script} { + set code [catch {uplevel $script} msg] + set expanded_script [uplevel subst \"$script\"] + if {!$code} { + test_failure \ + "'$expanded_script' finished successfully. \ + Was expecting an error." + } + if {$expctd_code ne "" && $code != $expctd_code} { + test_failure \ + "'$expanded_script' returned unexpected error code $code. \ + Was expecting $expctd_code. Error message: '$msg'" + } + if {$msg_ptrn ne "" && ![regexp -- $msg_ptrn $msg]} { + test_failure \ + "'$expanded_script' returned unexpected error message '$msg'. \ + Was expecting '$msg_ptrn'. Error code: $code" + } + } + + proc check_error_matches {pattern script} { + tailcall check_for_error {} $pattern $script + } + + proc check_syntax_err script { + tailcall check_for_error 1 {} $script + } + + proc check_matches {pattern script} { + set result [uplevel $script] + if {[regexp $pattern $result]} {return} + test_failure \ + "'$script' produced unexpected result '$result'. \ + Was expecting '$pattern'." + } + + namespace export check_error_matches check_syntax_err check_matches +} + +namespace eval configure_testing { + + variable target_idx 0 + + proc unique_tgt_name {} { + variable target_idx + incr target_idx + return test_target$target_idx + } + + proc target_create_first_args {} { + return "target create [unique_tgt_name] testee" + } + + proc simple_configure_options {} { + return { + -work-area-virt 0 + -work-area-phys 0 + -work-area-size 1 + -work-area-backup 0 + -endian little + -coreid 1 + -chain-position tap.cpu + -dbgbase 0 + -rtos hwthread + -gdb-port 0 + -gdb-max-connections 1 + } + } + + namespace export target_create_first_args simple_configure_options +} diff --git a/tools/scripts/camelcase.txt b/tools/scripts/camelcase.txt index 6c6c28daa5..1c782ee351 100644 --- a/tools/scripts/camelcase.txt +++ b/tools/scripts/camelcase.txt @@ -87,20 +87,14 @@ Jim_AppendString Jim_AppendStrings Jim_Cmd Jim_CmdPrivData -Jim_CmdProc -Jim_CompareStringImmediate -Jim_ConcatObj Jim_CreateCommand Jim_CreateInterp Jim_DecrRefCount -Jim_DelCmdProc Jim_DeleteAssocData Jim_DeleteCommand -Jim_DictAddElement Jim_DictPairs Jim_DuplicateObj Jim_Eval -Jim_EvalExpression Jim_EvalObj Jim_EvalObjPrefix Jim_EvalSource @@ -113,46 +107,31 @@ Jim_GetDouble Jim_GetEnum Jim_GetExitCode Jim_GetGlobalVariableStr -Jim_GetIntRepPtr -Jim_GetLong Jim_GetResult Jim_GetString -Jim_GetVariable Jim_GetWide Jim_IncrRefCount Jim_InitStaticExtensions Jim_Interp -Jim_Length -Jim_ListAppendElement Jim_ListGetIndex Jim_ListLength Jim_MakeErrorMessage -Jim_NewDictObj Jim_NewEmptyStringObj Jim_NewIntObj -Jim_NewListObj Jim_NewStringObj -Jim_NewWideObj Jim_Obj Jim_ProcessEvents Jim_RegisterCoreCommands Jim_SetAssocData Jim_SetEmptyResult Jim_SetResult -Jim_SetResultBool Jim_SetResultFormatted -Jim_SetResultInt Jim_SetResultString -Jim_SetVariable Jim_String Jim_WrongNumArgs cmdProc -currentScriptObj -delProc -emptyObj privData returnCode -typePtr # from elf.h Elf32_Addr @@ -193,6 +172,7 @@ Sleep WaitForSingleObject WSACleanup WSAGetLastError +WSASetLastError WSAStartup dwHighDateTime dwLowDateTime diff --git a/tools/scripts/spdxcheck.py b/tools/scripts/spdxcheck.py index f882943790..9180f61fa6 100755 --- a/tools/scripts/spdxcheck.py +++ b/tools/scripts/spdxcheck.py @@ -50,7 +50,7 @@ def read_spdxdata(repo): # The subdirectories of LICENSES in the kernel source # Note: exceptions needs to be parsed as last directory. # OpenOCD specific: Begin - license_dirs = [ "preferred", "stand-alone", "exceptions" ] + license_dirs = [ "preferred", "dual", "exceptions", "stand-alone" ] # OpenOCD specific: End lictree = repo.head.commit.tree['LICENSES']