diff --git a/.checkpatch.conf b/.checkpatch.conf
index f432503e1a..b95dbe2711 100644
--- a/.checkpatch.conf
+++ b/.checkpatch.conf
@@ -14,7 +14,6 @@
--ignore ENOSYS
--ignore FILE_PATH_CHANGES
--ignore GERRIT_CHANGE_ID
---ignore LINE_SPACING
--ignore LOGICAL_CONTINUATIONS
--ignore MACRO_WITH_FLOW_CONTROL
--ignore PARENTHESIS_ALIGNMENT
@@ -23,6 +22,5 @@
--ignore PREFER_KERNEL_TYPES
--ignore SPLIT_STRING
--ignore SSCANF_TO_KSTRTO
---ignore SWITCH_CASE_INDENT_LEVEL
--ignore TRACING_LOGGING
--ignore VOLATILE
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..3ab5668a51
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,17 @@
+# EditorConfig: https://editorconfig.org/
+
+# top-most EditorConfig file
+root = true
+
+# All (Defaults)
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = tab
+indent_size = 4
+tab_width = 4
+
+[*.patch,*.diff]
+trim_trailing_whitespace = false
diff --git a/HACKING b/HACKING
index b1d224dbf6..785179efe9 100644
--- a/HACKING
+++ b/HACKING
@@ -77,32 +77,6 @@ patch:
src/openocd -s ../tcl -f /path/to/openocd.cfg
@endcode
-- Runtime coverage testing
-
- Apply the following patch to prevent OpenOCD from killing itself:
- @code
---- a/src/openocd.c
-+++ b/src/openocd.c
-@@ -372,8 +372,6 @@ int openocd_main(int argc, char *argv[])
-
- if (ERROR_FAIL == ret)
- return EXIT_FAILURE;
-- else if (ERROR_OK != ret)
-- exit_on_signal(ret);
-
- return ret;
- }
- @endcode
-
- Configure your OpenOCD binary with coverage support as follows:
- @code
- LDFLAGS="-fprofile-arcs -ftest-coverage"
- CFLAGS="-fprofile-arcs -ftest-coverage" ./configure
- @endcode
-
- Now every time OpenOCD is run, coverage info in your build directory is
- updated. Running `gcov src/path/file.c` will generate a report.
-
- Sparse Static Analyzer
Using this tool allows identifying some bug in C code.
@@ -195,7 +169,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 +248,12 @@ doc: fix typos
@code
git pull --rebase origin master
@endcode
+
+-# When you create a new version of an old patch, check that the new patch
+ keeps the same 'Change-Id:' field of the old patch.
+ This allows the Gerrit server to recognize the patch as a new version of
+ the older one and keeps track of the history and the review process.
+
-# Send the patches to the Gerrit server for review:
@code
git push review
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 0884c07878..b6aa282215 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 = foreign 1.14
.DELETE_ON_ERROR:
@@ -28,12 +26,12 @@ dist_man_MANS =
EXTRA_DIST =
DISTCLEANFILES =
-SUBDIRS += testing
-DIST_SUBDIRS += testing
-
SUBDIRS += tools/syntacore
DIST_SUBDIRS += tools/syntacore
+SUBDIRS += testing
+DIST_SUBDIRS += testing
+
# common flags used in openocd build
AM_CFLAGS = $(GCC_WARNINGS)
AM_LDFLAGS =
@@ -54,11 +52,12 @@ EXTRA_DIST += \
BUGS \
HACKING \
NEWTAPS \
- README.Windows \
- README.macOS \
+ README.Windows.md \
+ README.macOS.md \
$(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.Windows b/README.Windows.md
similarity index 60%
rename from README.Windows
rename to README.Windows.md
index 64bf5c0c6f..9b6f770f6b 100644
--- a/README.Windows
+++ b/README.Windows.md
@@ -1,29 +1,19 @@
-Building OpenOCD for Windows
-----------------------------
+# OpenOCD for Windows
+
+This README contains instructions that are specific to Windows.
+
+## Building
You can build OpenOCD for Windows natively with either MinGW-w64/MSYS
-or Cygwin (plain MinGW might work with --disable-werror but is not
+or Cygwin (plain MinGW might work with `--disable-werror` but is not
recommended as it doesn't provide enough C99 compatibility).
Alternatively, one can cross-compile it using MinGW-w64 on a *nix
-host. See README for the generic instructions.
+host. See [README](README.md) 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
-------------
+## USB adapters
For the adapters that use a HID-based protocol, e.g. CMSIS-DAP, you do
not need to perform any additional configuration.
@@ -31,9 +21,7 @@ not need to perform any additional configuration.
For all the others you usually need to have WinUSB.sys (or
libusbK.sys) driver installed. Some vendor software (e.g. for
ST-LINKv2) does it on its own. For the other cases the easiest way to
-assign WinUSB to a device is to use the latest Zadig installer:
-
- http://zadig.akeo.ie
+assign WinUSB to a device is to use the latest Zadig installer:
When using a composite USB device, it's often necessary to assign
WinUSB.sys to the composite parent instead of the specific
@@ -42,7 +30,7 @@ Zadig installer.
If you need to use the same adapter with other applications that may
require another driver, a solution for Windows Vista and above is to
-activate the IgnoreHWSerNum registry setting for the USB device.
+activate the `IgnoreHWSerNum` registry setting for the USB device.
That setting forces Windows to associate the driver per port instead of
per serial number, the same behaviour as when the device does not contain
@@ -52,5 +40,5 @@ port depending on which application to use.
For more information, see:
- https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-device-specific-registry-settings
- http://www.ftdichip.com/Support/Knowledgebase/index.html?ignorehardwareserialnumber.htm
+-
+-
diff --git a/README.macOS b/README.macOS
deleted file mode 100644
index 91d5e9261b..0000000000
--- a/README.macOS
+++ /dev/null
@@ -1,54 +0,0 @@
-Building OpenOCD for macOS
---------------------------
-
-There are a few prerequisites you will need first:
-
-- Xcode (install from the AppStore)
-- Command Line Tools (install from Xcode -> Preferences -> Downloads)
-- Gentoo Prefix (http://www.gentoo.org/proj/en/gentoo-alt/prefix/bootstrap.xml)
- or
-- Homebrew (http://mxcl.github.io/homebrew/)
- or
-- MacPorts (http://www.macports.org/install.php)
-
-
-If you're building manually you need Texinfo version 5.0 or later. The
-simplest way to get it is to use Homebrew (brew install texinfo) and
-then ``export PATH=/usr/local/opt/texinfo/bin:$PATH``.
-
-
-With Gentoo Prefix you can build the release version or the latest
-devel version (-9999) the usual way described in the Gentoo
-documentation. Alternatively, install the prerequisites and build
-manually from the sources.
-
-
-With Homebrew you can either run:
- brew install [--HEAD] openocd (where optional --HEAD asks brew to
- install the current git version)
- or
- brew install libtool automake libusb [hidapi] [libftdi]
- (to install the needed dependencies and then proceed with the
- manual building procedure)
-
-
-For building with MacPorts you need to run:
- sudo port install libtool automake autoconf pkgconfig \
- libusb [libftdi1]
-
-You should also specify LDFLAGS and CPPFLAGS to allow configure to use
-MacPorts' libraries, so run configure like this:
- LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options]
-
-
-See README for the generic building instructions.
-
-If you're using a USB adapter and have a driver kext matched to it,
-you will need to unload it prior to running OpenOCD. E.g. with Apple
-driver (OS X 10.9 or later) for FTDI run:
- sudo kextunload -b com.apple.driver.AppleUSBFTDI
-for FTDI vendor driver use:
- sudo kextunload FTDIUSBSerialDriver.kext
-
-To learn more on the topic please refer to the official libusb FAQ:
-https://github.com/libusb/libusb/wiki/FAQ
diff --git a/README.macOS.md b/README.macOS.md
new file mode 100644
index 0000000000..a531024d9f
--- /dev/null
+++ b/README.macOS.md
@@ -0,0 +1,72 @@
+# OpenOCD for macOS
+
+This README contains instructions that are specific to macOS.
+
+## Building
+
+There are a few prerequisites you will need first:
+
+- Xcode (install from the AppStore)
+- Command Line Tools (install from Xcode -> Preferences -> Downloads)
+- One of the following tools:
+ - Gentoo Prefix ()
+ - Homebrew ()
+ - MacPorts ()
+
+If you're building manually you need Texinfo version 5.0 or later. The
+simplest way to get it is to use Homebrew (`brew install texinfo`) and
+then `export PATH=/usr/local/opt/texinfo/bin:$PATH`.
+
+With Gentoo Prefix you can build the release version or the latest
+devel version (-9999) the usual way described in the Gentoo
+documentation. Alternatively, install the prerequisites and build
+manually from the sources.
+
+With Homebrew you can either run:
+
+```sh
+brew install [--HEAD] open-ocd
+```
+
+Where ``--HEAD`` asks ``brew`` to install the current Git version instead of the
+lastest release.
+
+You can also run:
+
+```sh
+brew install libtool automake libusb [hidapi] [libftdi]
+```
+
+to install the needed dependencies and then proceed with the manual building
+procedure.
+
+For building with MacPorts you need to run:
+
+```sh
+sudo port install libtool automake autoconf pkgconfig libusb [libftdi1]
+```
+
+You should also specify LDFLAGS and CPPFLAGS to allow `configure` to use
+MacPorts' libraries, so run configure like this:
+
+```sh
+LDFLAGS=-L/opt/local/lib CPPFLAGS=-I/opt/local/include ./configure [options]
+```
+
+See [README](README.md) for the generic building instructions.
+
+If you're using a USB adapter and have a driver kext matched to it,
+you will need to unload it prior to running OpenOCD. E.g. with Apple
+driver (OS X 10.9 or later) for FTDI run:
+
+```sh
+sudo kextunload -b com.apple.driver.AppleUSBFTDI
+```
+
+for FTDI vendor driver use:
+
+```sh
+sudo kextunload FTDIUSBSerialDriver.kext
+```
+
+To learn more on the topic please refer to the official libusb FAQ:
diff --git a/README b/README.md
similarity index 72%
rename from README
rename to README.md
index 875c85de3b..bf26d59038 100644
--- a/README
+++ b/README.md
@@ -1,4 +1,4 @@
-# Welcome to OpenOCD!
+# Welcome to OpenOCD
OpenOCD provides on-chip programming and debugging support with a
layered architecture of JTAG interface and TAP support including:
@@ -24,53 +24,119 @@ This README file contains an overview of the following topics:
- the installation and build process,
- packaging tips.
-
-# Quickstart for the impatient
+## Quickstart for the impatient
If you have a popular board then just start OpenOCD with its config,
e.g.:
- openocd -f board/stm32f4discovery.cfg
+```sh
+openocd -f board/stm32f4discovery.cfg
+```
If you are connecting a particular adapter with some specific target,
you need to source both the jtag interface and the target configs,
e.g.:
-```
+```sh
openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \
- -f target/ti_calypso.cfg
+ -f target/ti/calypso.cfg
```
-```
+```sh
openocd -f interface/stlink.cfg -c "transport select swd" \
-f target/stm32l0.cfg
```
After OpenOCD startup, connect GDB with
- (gdb) target extended-remote localhost:3333
+```gdb
+(gdb) target extended-remote localhost:3333
+```
+
+## Installing OpenOCD
+
+The easiest way to install OpenOCD is through your operating system's package
+manager.
+
+- Debian / Ubuntu
+
+ ```sh
+ sudo apt install openocd
+ ```
+
+- Fedora
+
+ ```sh
+ sudo dnf install openocd
+ ```
+
+- macOS (via Homebrew)
+
+ ```sh
+ brew install open-ocd
+ ```
+
+- Windows (via MSYS2)
+
+ ```sh
+ pacman -S mingw-w64-x86_64-openocd
+ ```
+
+These packages are often more stable than the bleeding-edge Git mainline, where
+active development happens.
+"Packagers" create binary releases of OpenOCD after the developers publish new
+source code releases.
+Older OpenOCD versions are not suitable for diagnosing issues in the current
+release.
+Users should stay in touch with their distribution maintainers or interface
+vendors to ensure that appropriate updates are provided regularly.
+
+If you use one of these binary packages, you must contact the Packager for
+support or for newer binary versions.
+The OpenOCD developers do not provide direct support for packaged binaries.
+
+## A Note to OpenOCD Packagers
+
+You are a PACKAGER of OpenOCD if you:
+
+- Sell dongles and include pre-built binaries;
+- Supply tools or IDEs (a development solution integrating OpenOCD);
+- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution).
+
+As a PACKAGER, you will experience first reports of most issues.
+When you fix those problems for your users, your solution may help
+prevent hundreds (if not thousands) of other questions from other users.
+
+If something does not work for you, please work to inform the OpenOCD
+developers know how to improve the system or documentation to avoid
+future problems, and follow-up to help us ensure the issue will be fully
+resolved in our future releases.
+
+That said, the OpenOCD developers would also like you to follow a few
+suggestions:
+- Send patches, including config files, upstream, participate in the
+ discussions;
+- Enable all the options OpenOCD supports, even those unrelated to your
+ particular hardware;
+- Use "ftdi" interface adapter driver for the FTDI-based devices.
-# OpenOCD Documentation
+## OpenOCD Documentation
In addition to the in-tree documentation, the latest manuals may be
viewed online at the following URLs:
- OpenOCD User's Guide:
- http://openocd.org/doc/html/index.html
+- OpenOCD User's Guide:
- OpenOCD Developer's Manual:
- http://openocd.org/doc/doxygen/html/index.html
+- OpenOCD Developer's Manual:
These reflect the latest development versions, so the following section
introduces how to build the complete documentation from the package.
For more information, refer to these documents or contact the developers
-by subscribing to the OpenOCD developer mailing list:
-
- openocd-devel@lists.sourceforge.net
+by subscribing to the OpenOCD developer mailing list: openocd-devel@lists.sourceforge.net
-## Building the OpenOCD Documentation
+### Building the OpenOCD Documentation
By default the OpenOCD build process prepares documentation in the
"Info format" and installs it the standard way, so that `info openocd`
@@ -81,23 +147,28 @@ following different formats:
If `PDFVIEWER` is set, this creates and views the PDF User Guide.
- make pdf && ${PDFVIEWER} doc/openocd.pdf
+```sh
+make pdf && ${PDFVIEWER} doc/openocd.pdf
+```
If `HTMLVIEWER` is set, this creates and views the HTML User Guide.
- make html && ${HTMLVIEWER} doc/openocd.html/index.html
+```sh
+make html && ${HTMLVIEWER} doc/openocd.html/index.html
+```
The OpenOCD Developer Manual contains information about the internal
architecture and other details about the code:
Note: make sure doxygen is installed, type doxygen --version
- make doxygen && ${HTMLVIEWER} doxygen/index.html
-
+```sh
+make doxygen && ${HTMLVIEWER} doxygen/index.html
+```
-# Supported hardware
+## Supported hardware
-## JTAG adapters
+### JTAG adapters
AM335x, ARM-JTAG-EW, ARM-USB-OCD, ARM-USB-TINY, AT91RM9200, axm0432, BCM2835,
Bus Blaster, Buspirate, Cadence DPI, Cadence vdebug, Chameleon, CMSIS-DAP,
@@ -114,7 +185,7 @@ sysfsgpio, Tigard, TI XDS110, TUMPA, Turtelizer, ULINK, USB-A9260, USB-Blaster,
USB-JTAG, USBprog, VPACLink, VSLLink, Wiggler, XDS100v2, Xilinx XVC/PCIe,
Xverve.
-## Debug targets
+### Debug targets
ARM: AArch64, ARM11, ARM7, ARM9, Cortex-A/R (v7-A/R), Cortex-M (ARMv{6/7/8}-M),
FA526, Feroceon/Dragonite, XScale.
@@ -122,7 +193,7 @@ ARCv2, AVR32, DSP563xx, DSP5680xx, EnSilica eSi-RISC, EJTAG (MIPS32, MIPS64),
ESP32, ESP32-S2, ESP32-S3, Intel Quark, LS102x-SAP, RISC-V, ST STM8,
Xtensa.
-## Flash drivers
+### Flash drivers
ADUC702x, AT91SAM, AT91SAM9 (NAND), ATH79, ATmega128RFA1, Atmel SAM, AVR, CFI,
DSP5680xx, EFM32, EM357, eSi-RISC, eSi-TSMC, EZR32HG, FM3, FM4, Freedom E SPI,
@@ -135,66 +206,22 @@ STM32 QUAD/OCTO-SPI for Flash/FRAM/EEPROM, STMSMI, STR7x, STR9x, SWM050,
TI CC13xx, TI CC26xx, TI CC32xx, TI MSP432, Winner Micro w600, Xilinx XCF,
XMC1xxx, XMC4xxx.
-
-# Installing OpenOCD
-
-## A Note to OpenOCD Users
-
-If you would rather be working "with" OpenOCD rather than "on" it, your
-operating system or JTAG interface supplier may provide binaries for
-you in a convenient-enough package.
-
-Such packages may be more stable than git mainline, where
-bleeding-edge development takes place. These "Packagers" produce
-binary releases of OpenOCD after the developers produces new "release"
-versions of the source code. Previous versions of OpenOCD cannot be
-used to diagnose problems with the current release, so users are
-encouraged to keep in contact with their distribution package
-maintainers or interface vendors to ensure suitable upgrades appear
-regularly.
-
-Users of these binary versions of OpenOCD must contact their Packager to
-ask for support or newer versions of the binaries; the OpenOCD
-developers do not support packages directly.
-
-## A Note to OpenOCD Packagers
-
-You are a PACKAGER of OpenOCD if you:
-
-- Sell dongles and include pre-built binaries;
-- Supply tools or IDEs (a development solution integrating OpenOCD);
-- Build packages (e.g. RPM or DEB files for a GNU/Linux distribution).
-
-As a PACKAGER, you will experience first reports of most issues.
-When you fix those problems for your users, your solution may help
-prevent hundreds (if not thousands) of other questions from other users.
-
-If something does not work for you, please work to inform the OpenOCD
-developers know how to improve the system or documentation to avoid
-future problems, and follow-up to help us ensure the issue will be fully
-resolved in our future releases.
-
-That said, the OpenOCD developers would also like you to follow a few
-suggestions:
-
-- Send patches, including config files, upstream, participate in the
- discussions;
-- Enable all the options OpenOCD supports, even those unrelated to your
- particular hardware;
-- Use "ftdi" interface adapter driver for the FTDI-based devices.
-
-
-# Building OpenOCD
+## Building OpenOCD
The INSTALL file contains generic instructions for running `configure`
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.
-## OpenOCD Dependencies
+### OpenOCD Dependencies
GCC or Clang is currently required to build OpenOCD. The developers
have begun to enforce strict code warnings (-Wall, -Werror, -Wextra,
@@ -211,7 +238,7 @@ You'll also need:
- pkg-config >= 0.23 or pkgconf
- libjim >= 0.79
-Additionally, for building from git:
+Additionally, for building from Git:
- autoconf >= 2.69
- automake >= 1.14
@@ -219,9 +246,8 @@ Additionally, for building from git:
Optional USB-based adapter drivers need libusb-1.0.
-Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter
-drivers need:
- - libftdi: http://www.intra2net.com/en/developer/libftdi/index.php
+Optional USB-Blaster, ASIX Presto and OpenJTAG interface adapter drivers need
+[libftdi](http://www.intra2net.com/en/developer/libftdi/index.php) library.
Optional CMSIS-DAP adapter driver needs HIDAPI library.
@@ -236,64 +262,49 @@ Optional development script checkpatch needs:
- perl
- python
- python-ply
+- pymarkdownlnt
-## Permissions delegation
-
-Running OpenOCD with root/administrative permissions is strongly
-discouraged for security reasons.
-
-For USB devices on GNU/Linux you should use the contrib/60-openocd.rules
-file. It probably belongs somewhere in /etc/udev/rules.d, but
-consult your operating system documentation to be sure. Do not forget
-to add yourself to the "plugdev" group.
-
-For parallel port adapters on GNU/Linux and FreeBSD please change your
-"ppdev" (parport* or ppi*) device node permissions accordingly.
-
-For parport adapters on Windows you need to run install_giveio.bat
-(it's also possible to use "ioperm" with Cygwin instead) to give
-ordinary users permissions for accessing the "LPT" registers directly.
-
-## Compiling OpenOCD
+### Compiling OpenOCD
To build OpenOCD, use the following sequence of commands:
- ./bootstrap
- ./configure [options]
- make
- sudo make install
+```sh
+./bootstrap
+./configure [options]
+make
+sudo make install
+```
-The `bootstrap` command is only necessary when building from the Git repository. The `configure` step generates the Makefiles required to build
-OpenOCD, usually with one or more options provided to it. The first
-'make' step will build OpenOCD and place the final executable in
-'./src/'. The final (optional) step, `make install`, places all of
-the files in the required location.
+The `bootstrap` command is only necessary when building from the Git repository.
+The `configure` step generates the Makefiles required to build OpenOCD, usually
+with one or more options provided to it.
+The first 'make' step will build OpenOCD and place the final executable in './src/'.
+The final (optional) step, `make install`, places all of the files in the
+required location.
To see the list of all the supported options, run `./configure --help`
-## Cross-compiling Options
+### Cross-compiling Options
Cross-compiling is supported the standard autotools way, you just need
to specify the cross-compiling target triplet in the --host option,
e.g. for cross-building for Windows 32-bit with MinGW on Debian:
- ./configure --host=i686-w64-mingw32 [options]
-
-To make pkg-config work nicely for cross-compiling, you might need an
-additional wrapper script as described at
+```sh
+./configure --host=i686-w64-mingw32 [options]
+```
- https://autotools.io/pkgconfig/cross-compiling.html
+To make pkg-config work nicely for cross-compiling, you might need an additional
+wrapper script as described at .
This is needed to tell pkg-config where to look for the target
libraries that OpenOCD depends on. Alternatively, you can specify
`*_CFLAGS` and `*_LIBS` environment variables directly, see `./configure
--help` for the details.
-For a more or less complete script that does all this for you, see
+For a more or less complete script that does all this for you, see `contrib/cross-build.sh`.
- contrib/cross-build.sh
-
-## Parallel Port Dongles
+### Parallel Port Dongles
If you want to access the parallel port using the PPDEV interface you
have to specify both `--enable-parport` and `--enable-parport-ppdev`, since
@@ -304,31 +315,45 @@ use both the `--enable-parport` and the `--enable-parport-giveio` option
if you want to use giveio instead of ioperm parallel port access
method.
+### Obtaining OpenOCD From Git
-# Obtaining OpenOCD From GIT
-
-You can download the current GIT version with a GIT client of your
-choice from the main repository:
-
- git://git.code.sf.net/p/openocd/code
+You can download the current Git version with a Git client of your
+choice from the main repository: `git://git.code.sf.net/p/openocd/code`
You may prefer to use a mirror:
- http://repo.or.cz/r/openocd.git
- git://repo.or.cz/openocd.git
+-
+- git://repo.or.cz/openocd.git
-Using the GIT command line client, you might use the following command
+Using the Git command line client, you might use the following command
to set up a local copy of the current repository (make sure there is no
directory called "openocd" in the current directory):
- git clone git://git.code.sf.net/p/openocd/code openocd
+```sh
+git clone git://git.code.sf.net/p/openocd/code openocd
+```
Then you can update that at your convenience using `git pull`.
-There is also a gitweb interface, which you can use either to browse
-the repository or to download arbitrary snapshots using HTTP:
-
- http://repo.or.cz/w/openocd.git
+There is also a gitweb interface, which you can use either to browse the
+repository or to download arbitrary snapshots using HTTP: .
Snapshots are compressed tarballs of the source tree, about 1.3 MBytes
each at this writing.
+
+## Permissions delegation
+
+Running OpenOCD with root/administrative permissions is strongly
+discouraged for security reasons.
+
+For USB devices on GNU/Linux you should use the contrib/60-openocd.rules
+file. It probably belongs somewhere in /etc/udev/rules.d, but
+consult your operating system documentation to be sure. Do not forget
+to add yourself to the "plugdev" group.
+
+For parallel port adapters on GNU/Linux and FreeBSD please change your
+"ppdev" (parport* or ppi*) device node permissions accordingly.
+
+For parport adapters on Windows you need to run install_giveio.bat
+(it's also possible to use "ioperm" with Cygwin instead) to give
+ordinary users permissions for accessing the "LPT" registers directly.
diff --git a/configure.ac b/configure.ac
index 390c1375b0..97a81f2456 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,7 @@ AS_IF([test "x$MAKEINFO" = "x"], [
])
AC_SUBST([MAKEINFO])
-AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip subdir-objects])
+AM_INIT_AUTOMAKE([foreign -Wall -Wno-portability dist-bzip2 dist-zip subdir-objects])
AC_CONFIG_HEADERS([config.h])
@@ -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,
@@ -49,6 +48,8 @@ AC_TYPE_LONG_LONG_INT
AC_SEARCH_LIBS([ioperm], [ioperm])
AC_SEARCH_LIBS([dlopen], [dl])
AC_SEARCH_LIBS([openpty], [util])
+# Older versions of Linux put clock_gettime in librt
+AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_HEADERS([sys/socket.h])
AC_CHECK_HEADERS([elf.h])
@@ -57,17 +58,14 @@ AC_CHECK_TYPE([Elf64_Ehdr],
AC_DEFINE([HAVE_ELF64], [1], [Define to 1 if the system has the type 'Elf64_Ehdr'.]),
[], [[#include ]])
-AC_MSG_CHECKING([for glibc])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int v = __GLIBC__;return 0;]])],
- [have_glibc=yes], [have_glibc=no])
-AC_MSG_RESULT($have_glibc)
-
AC_CHECK_HEADERS([fcntl.h])
-AC_CHECK_HEADERS([malloc.h])
+AC_CHECK_HEADERS([linux/pci.h])
+AC_CHECK_HEADERS([linux/spi/spidev.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])
@@ -97,9 +95,11 @@ AC_C_BIGENDIAN
AC_CHECK_FUNCS([strndup])
AC_CHECK_FUNCS([strnlen])
-AC_CHECK_FUNCS([gettimeofday])
+AC_CHECK_FUNCS([clock_gettime])
AC_CHECK_FUNCS([usleep])
AC_CHECK_FUNCS([realpath])
+AC_CHECK_FUNCS([mallinfo])
+AC_CHECK_FUNCS([mallinfo2])
# guess-rev.sh only exists in the repository, not in the released archives
AC_MSG_CHECKING([whether to build a release])
@@ -129,6 +129,8 @@ 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]],
+ [[cklink], [T-Head CK-Link JTAG Probe], [CKLINK]],
[[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]],
[[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
@@ -165,6 +167,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 +179,18 @@ 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([NETWORK_ADAPTERS],
+ [[[xvc], [Xilinx XVC TCP], [XVC]]])
+
m4_define([LINUXSPIDEV_ADAPTER],
[[[linuxspidev], [Linux spidev driver], [LINUXSPIDEV]]])
m4_define([VDEBUG_ADAPTER],
@@ -197,8 +208,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,66 +270,16 @@ 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
-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"], [
- AC_DEFINE([_DEBUG_USB_COMMS_],[1], [Print verbose USB communication messages])
-])
-
-debug_malloc=no
-AC_ARG_ENABLE([malloc_logging],
- AS_HELP_STRING([--enable-malloc-logging],
- [Include free space in logging messages (requires malloc.h).]),
- [debug_malloc=$enableval], [])
-
-AC_MSG_CHECKING([whether to enable malloc free space logging]);
-AC_MSG_RESULT([$debug_malloc])
-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 +290,7 @@ AC_ARG_ADAPTERS([
LIBFTDI_ADAPTERS,
LIBFTDI_USB1_ADAPTERS,
LIBGPIOD_ADAPTERS,
+ DMEM_ADAPTER,
SYSFSGPIO_ADAPTER,
REMOTE_BITBANG_ADAPTER,
LINUXSPIDEV_ADAPTER,
@@ -328,14 +300,26 @@ 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,
+ NETWORK_ADAPTERS
],[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 +328,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 +352,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])
])
])
@@ -410,9 +361,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
@@ -433,7 +383,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]))
])
])
@@ -496,58 +446,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.])
], [
@@ -606,10 +508,6 @@ AS_IF([test "x$enable_capstone" != xno], [
])
])
-AS_IF([test "x$enable_capstone" == xno], [
- AC_DEFINE([HAVE_CAPSTONE], [0], [0 if you don't have Capstone disassembly framework.])
-])
-
for hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
PKG_CHECK_MODULES([HIDAPI],[$hidapi_lib],[
use_hidapi=yes
@@ -627,11 +525,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])
@@ -642,21 +548,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"])
])
])
@@ -666,20 +575,33 @@ 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([LIBJAYLINK_ADAPTERS], ["x$use_libjaylink" = "xyes"], [libjaylink-0.2])
-PROCESS_ADAPTERS([PCIE_ADAPTERS], ["x$is_linux" = "xyes"], [Linux build])
+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([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])
+PROCESS_ADAPTERS([NETWORK_ADAPTERS], [true], [unused])
+
+AS_IF([test "x$enable_xvc" != "xno"], [
+ build_bitbang=yes
+])
AS_IF([test "x$enable_linuxgpiod" != "xno"], [
build_bitbang=yes
@@ -693,6 +615,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])
@@ -703,6 +645,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"])
# Presto needs the bitq module
AS_IF([test "x$enable_presto" != "xno"], [
@@ -715,13 +659,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"])
@@ -735,11 +673,11 @@ 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([HAVE_JIMTCL_PKG_CONFIG], [test "x$have_jimtcl_pkg_config" = "xyes"])
+
AM_CONDITIONAL([USE_GCOV], [test "x$enable_gcov" = "xyes"])
# Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h?
@@ -779,11 +717,13 @@ AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).])
GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow"
AS_IF([test "x${gcc_wextra}" = "xyes"], [
GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter"
+ GCC_WARNINGS="${GCC_WARNINGS} -Wno-gnu-folding-constant"
GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast"
GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align"
GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls"
GCC_WARNINGS="${GCC_WARNINGS} -Wpointer-arith"
GCC_WARNINGS="${GCC_WARNINGS} -Wundef"
+ GCC_WARNINGS="${GCC_WARNINGS} -Wsign-compare"
])
AS_IF([test "x${gcc_werror}" = "xyes"], [
GCC_WARNINGS="${GCC_WARNINGS} -Werror"
@@ -810,28 +750,52 @@ 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,
+ NETWORK_ADAPTERS,
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)'
],
@@ -843,8 +807,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..775a25f249 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"
@@ -245,11 +254,15 @@ ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="1106", MODE="660", GROUP="plugdev",
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="660", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE="660", GROUP="plugdev", TAG+="uaccess"
+# T-Head CK-Link Lite (PingTouGe Semiconductor)
+ATTRS{idVendor}=="32bf", ATTRS{idProduct}=="b210", MODE="660", GROUP="plugdev", TAG+="uaccess"
+
+# Bouffalo Lab BL616/BL702 CK-Link clones
+ATTRS{idVendor}=="42bf", ATTRS{idProduct}=="b210", MODE="660", GROUP="plugdev", TAG+="uaccess"
+
# 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..a8817daa16 100644
--- a/contrib/firmware/angie/c/Makefile
+++ b/contrib/firmware/angie/c/Makefile
@@ -22,6 +22,8 @@ AS = $(PREFIX)sdas8051
# the OpenOCD driver, but the resulting file is smaller.
PACKIHX = $(PREFIX)packihx
+MAKEBIN = $(PREFIX)makebin
+
# GNU binutils size. Used to print the size of the IHX file generated by SDCC.
SIZE = size
@@ -38,10 +40,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 \
@@ -73,7 +73,7 @@ clean:
rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lk *.map *.mem
bin: angie_firmware.ihx
- makebin -p angie_firmware.ihx angie_firmware.bin
+ $(MAKEBIN) -p angie_firmware.ihx angie_firmware.bin
hex: angie_firmware.ihx
$(PACKIHX) angie_firmware.ihx > fx2.hex
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..fb4067d621 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,13 +125,7 @@ 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;
+extern volatile __xdata __at(0xE6B8) struct setup_data setup_data;
/*
* USB Request Types (bmRequestType): See USB 2.0 Spec
@@ -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..8729b3ecba 100644
--- a/contrib/firmware/angie/c/src/main.c
+++ b/contrib/firmware/angie/c/src/main.c
@@ -11,13 +11,12 @@
*****************************************************************************/
#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;
+extern void sudav_isr(void)__interrupt(SUDAV_ISR);
extern void sof_isr(void)__interrupt;
extern void sutok_isr(void)__interrupt;
extern void suspend_isr(void)__interrupt;
@@ -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..4b3db0a60f 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;
+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,156 +135,146 @@ __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
+void sudav_isr(void)__interrupt(SUDAV_ISR)
{
EXIF &= ~0x10; /* Clear USBINT: Main global interrupt */
USBIRQ = SUDAVI;
EP0CS |= HSNAK;
usb_handle_setup_data();
}
-void sof_isr(void)__interrupt SOF_ISR
+void sof_isr(void)__interrupt(SOF_ISR)
{
}
-void sutok_isr(void)__interrupt SUTOK_ISR
+void sutok_isr(void)__interrupt(SUTOK_ISR)
{
}
-void suspend_isr(void)__interrupt SUSPEND_ISR
+void suspend_isr(void)__interrupt(SUSPEND_ISR)
{
}
-void usbreset_isr(void)__interrupt USBRESET_ISR
+void usbreset_isr(void)__interrupt(USBRESET_ISR)
{
}
-void highspeed_isr(void)__interrupt HIGHSPEED_ISR
+void highspeed_isr(void)__interrupt(HIGHSPEED_ISR)
{
}
-void ep0ack_isr(void)__interrupt EP0ACK_ISR
+void ep0ack_isr(void)__interrupt(EP0ACK_ISR)
{
}
-void stub_isr(void)__interrupt STUB_ISR
+void stub_isr(void)__interrupt(STUB_ISR)
{
}
-void ep0in_isr(void)__interrupt EP0IN_ISR
+void ep0in_isr(void)__interrupt(EP0IN_ISR)
{
}
-void ep0out_isr(void)__interrupt EP0OUT_ISR
+void ep0out_isr(void)__interrupt(EP0OUT_ISR)
{
}
-void ep1in_isr(void)__interrupt EP1IN_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
+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
+void ep2_isr(void)__interrupt(EP2_ISR)
{
}
-void ep4_isr(void)__interrupt EP4_ISR
+void ep4_isr(void)__interrupt(EP4_ISR)
{
}
-void ep6_isr(void)__interrupt EP6_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
+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
+void ibn_isr(void)__interrupt(IBN_ISR)
{
}
-void ep0pingnak_isr(void)__interrupt EP0PINGNAK_ISR
+void ep0pingnak_isr(void)__interrupt(EP0PINGNAK_ISR)
{
}
-void ep1pingnak_isr(void)__interrupt EP1PINGNAK_ISR
+void ep1pingnak_isr(void)__interrupt(EP1PINGNAK_ISR)
{
}
-void ep2pingnak_isr(void)__interrupt EP2PINGNAK_ISR
+void ep2pingnak_isr(void)__interrupt(EP2PINGNAK_ISR)
{
}
-void ep4pingnak_isr(void)__interrupt EP4PINGNAK_ISR
+void ep4pingnak_isr(void)__interrupt(EP4PINGNAK_ISR)
{
}
-void ep6pingnak_isr(void)__interrupt EP6PINGNAK_ISR
+void ep6pingnak_isr(void)__interrupt(EP6PINGNAK_ISR)
{
}
-void ep8pingnak_isr(void)__interrupt EP8PINGNAK_ISR
+void ep8pingnak_isr(void)__interrupt(EP8PINGNAK_ISR)
{
}
-void errorlimit_isr(void)__interrupt ERRORLIMIT_ISR
+void errorlimit_isr(void)__interrupt(ERRORLIMIT_ISR)
{
}
-void ep2piderror_isr(void)__interrupt EP2PIDERROR_ISR
+void ep2piderror_isr(void)__interrupt(EP2PIDERROR_ISR)
{
}
-void ep4piderror_isr(void)__interrupt EP4PIDERROR_ISR
+void ep4piderror_isr(void)__interrupt(EP4PIDERROR_ISR)
{
}
-void ep6piderror_isr(void)__interrupt EP6PIDERROR_ISR
+void ep6piderror_isr(void)__interrupt(EP6PIDERROR_ISR)
{
}
-void ep8piderror_isr(void)__interrupt EP8PIDERROR_ISR
+void ep8piderror_isr(void)__interrupt(EP8PIDERROR_ISR)
{
}
-void ep2pflag_isr(void)__interrupt EP2PFLAG_ISR
+void ep2pflag_isr(void)__interrupt(EP2PFLAG_ISR)
{
}
-void ep4pflag_isr(void)__interrupt EP4PFLAG_ISR
+void ep4pflag_isr(void)__interrupt(EP4PFLAG_ISR)
{
}
-void ep6pflag_isr(void)__interrupt EP6PFLAG_ISR
+void ep6pflag_isr(void)__interrupt(EP6PFLAG_ISR)
{
}
-void ep8pflag_isr(void)__interrupt EP8PFLAG_ISR
+void ep8pflag_isr(void)__interrupt(EP8PFLAG_ISR)
{
}
-void ep2eflag_isr(void)__interrupt EP2EFLAG_ISR
+void ep2eflag_isr(void)__interrupt(EP2EFLAG_ISR)
{
}
-void ep4eflag_isr(void)__interrupt EP4EFLAG_ISR
+void ep4eflag_isr(void)__interrupt(EP4EFLAG_ISR)
{
}
-void ep6eflag_isr(void)__interrupt EP6EFLAG_ISR
+void ep6eflag_isr(void)__interrupt(EP6EFLAG_ISR)
{
}
-void ep8eflag_isr(void)__interrupt EP8EFLAG_ISR
+void ep8eflag_isr(void)__interrupt(EP8EFLAG_ISR)
{
}
-void ep2fflag_isr(void)__interrupt EP2FFLAG_ISR
+void ep2fflag_isr(void)__interrupt(EP2FFLAG_ISR)
{
}
-void ep4fflag_isr(void)__interrupt EP4FFLAG_ISR
+void ep4fflag_isr(void)__interrupt(EP4FFLAG_ISR)
{
}
-void ep6fflag_isr(void)__interrupt EP6FFLAG_ISR
+void ep6fflag_isr(void)__interrupt(EP6FFLAG_ISR)
{
}
-void ep8fflag_isr(void)__interrupt EP8FFLAG_ISR
+void ep8fflag_isr(void)__interrupt(EP8FFLAG_ISR)
{
}
-void gpifcomplete_isr(void)__interrupt GPIFCOMPLETE_ISR
+void gpifcomplete_isr(void)__interrupt(GPIFCOMPLETE_ISR)
{
}
-void gpifwaveform_isr(void)__interrupt GPIFWAVEFORM_ISR
+void gpifwaveform_isr(void)__interrupt(GPIFWAVEFORM_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/hpmicro/Makefile b/contrib/loaders/flash/hpmicro/Makefile
new file mode 100644
index 0000000000..304363171a
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/Makefile
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright (c) 2023 HPMicro
+#
+BIN2C = ../../../../src/helper/bin2char.sh
+
+
+PROJECT=hpm_xpi_flash
+CROSS_COMPILE ?= riscv32-unknown-elf-
+CC=$(CROSS_COMPILE)gcc
+AS=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+LD=$(CROSS_COMPILE)ld
+LDSCRIPT=linker.ld
+
+OPT=-O3
+
+ASFLAGS=
+CFLAGS=$(OPT) -fomit-frame-pointer -Wall
+LDFLAGS=-nostartfiles -T$(LDSCRIPT) -Wl,-Map=$(PROJECT).map -static -Wl,--gc-sections
+OBJS=$(ASRC:.S=.o) $(SRC:.c=.o)
+
+SRC=openocd_flash_algo.c
+ASRC=func_table.S
+
+all: $(OBJS) $(PROJECT).elf $(PROJECT).bin $(PROJECT).lst $(PROJECT).inc
+
+%o: %c
+ @$(CC) -c $(CFLAGS) -I . $< -o $@
+
+%o: %S
+ @$(AS) -c $(ASFLAGS) -I . $< -o $@
+
+%elf: $(OBJS)
+ @$(CC) $(OBJS) $(LDFLAGS) -o $@
+
+%lst: %elf
+ @$(OBJDUMP) -h -S $< > $@
+
+%bin: %elf
+ @$(OBJCOPY) -Obinary $< $@
+
+%inc: %bin
+ $(BIN2C) < $< > $@
+
+clean:
+ @-rm -f *.o *.elf *.lst *.bin *.inc
+
+.PHONY: all clean
+
+.INTERMEDIATE: $(patsubst %.S,%.o,$(SRCS)) $(patsubst %.S,%.elf,$(SRCS)) $(patsubst %.S,%.bin,$(SRCS))
diff --git a/contrib/loaders/flash/hpmicro/README b/contrib/loaders/flash/hpmicro/README
new file mode 100644
index 0000000000..a6c047a11f
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/README
@@ -0,0 +1,7 @@
+The loader relies on the romapi provided by HPMicro devices.
+
+- hpm_common.h and all the hpm_romapi_*.c/h are reused from hpm_sdk
+(v1.9.0 https://github.com/hpmicro/hpm_sdk/releases).
+
+Due to different coding rules, these source code needs to be updated
+accordingly to pass the coding rule check for openocd.
diff --git a/contrib/loaders/flash/hpmicro/func_table.S b/contrib/loaders/flash/hpmicro/func_table.S
new file mode 100644
index 0000000000..d5f34265ec
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/func_table.S
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021 HPMicro
+ */
+ .section .func_table, "ax"
+ .global _init
+_init:
+ jal flash_init
+ ebreak
+ jal flash_erase
+ ebreak
+ jal flash_program
+ ebreak
+ jal flash_read
+ ebreak
+ jal flash_get_info
+ ebreak
+ jal flash_erase_chip
+ ebreak
+ jal flash_deinit
+ ebreak
diff --git a/contrib/loaders/flash/hpmicro/hpm_common.h b/contrib/loaders/flash/hpmicro/hpm_common.h
new file mode 100644
index 0000000000..8190fbfed5
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/hpm_common.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/*
+ * Copyright (c) 2021-2023 HPMicro
+ */
+
+#ifndef _HPM_COMMON_H
+#define _HPM_COMMON_H
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ *
+ * @brief COMMON driver APIs
+ * @defgroup common_interface COMMON driver APIs
+ * @{
+ *
+ */
+
+#define __R volatile const /* Define "read-only" permission */
+#define __RW volatile /* Define "read-write" permission */
+#define __W volatile /* Define "write-only" permission */
+
+#ifndef __I
+#define __I __R
+#endif
+
+#ifndef __IO
+#define __IO __RW
+#endif
+
+#ifndef __O
+#define __O __W
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#define HPM_BITSMASK(val, offset) ((uint32_t)(val) << (offset))
+#define IS_HPM_BITMASK_SET(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) != 0U)
+#define IS_HPM_BIT_SET(val, offset) (((uint32_t)(val) & (1UL << (offset))) != 0U)
+#define IS_HPM_BITMASK_CLR(val, mask) (((uint32_t)(val) & (uint32_t)(mask)) == 0U)
+#define IS_HPM_BIT_CLR(val, offset) (((uint32_t)(val) & (1UL << (offset))) == 0U)
+
+#define HPM_BREAK_IF(cond) do {if (cond) break; } while (0)
+#define HPM_CONTINUE_IF(cond) do {if (cond) continue; } while (0)
+
+#define HPM_CHECK_RET(x) \
+ do { \
+ stat = (x); \
+ if (status_success != stat) { \
+ return stat; \
+ } \
+ } while (false)
+
+#define SIZE_1KB (1024UL)
+#define SIZE_1MB (1048576UL)
+
+typedef uint32_t hpm_stat_t;
+
+/* @brief Enum definition for the Status group
+ * Rule:
+ * [Group] 0-999 for the SoC driver and the corresponding components
+ * 1000 or above for the application status group
+ * [Code] Valid value: 0-999
+ *
+ */
+#define MAKE_STATUS(group, code) ((uint32_t)(group) * 1000U + (uint32_t)(code))
+/* @brief System status group definitions */
+enum {
+ status_group_common = 0,
+ status_group_uart = 1,
+ status_group_i2c = 2,
+ status_group_spi = 3,
+ status_group_usb = 4,
+ status_group_i2s = 5,
+ status_group_xpi = 6,
+ status_group_l1c,
+ status_group_dma,
+ status_group_femc,
+ status_group_sdp,
+ status_group_xpi_nor,
+ status_group_otp,
+ status_group_lcdc,
+ status_group_mbx,
+ status_group_rng,
+ status_group_pdma,
+ status_group_wdg,
+ status_group_pmic_sec,
+ status_group_can,
+ status_group_sdxc,
+ status_group_pcfg,
+ status_group_clk,
+ status_group_pllctl,
+ status_group_pllctlv2,
+ status_group_ffa,
+ status_group_mcan,
+
+ status_group_middleware_start = 500,
+ status_group_sdmmc = status_group_middleware_start,
+ status_group_audio_codec,
+ status_group_dma_manager,
+};
+
+/* @brief Common status code definitions */
+enum {
+ status_success = MAKE_STATUS(status_group_common, 0),
+ status_fail = MAKE_STATUS(status_group_common, 1),
+ status_invalid_argument = MAKE_STATUS(status_group_common, 2),
+ status_timeout = MAKE_STATUS(status_group_common, 3),
+};
+
+#if defined(__GNUC__)
+
+/* alway_inline */
+#define ATTR_ALWAYS_INLINE __attribute__((always_inline))
+
+/* weak */
+#define ATTR_WEAK __attribute__((weak))
+
+/* alignment */
+#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment)))
+
+/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */
+#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name)))
+
+#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \
+ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment)
+
+#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss")
+#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment)
+
+#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss")
+#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment)
+
+/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */
+#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init")
+#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment)
+
+#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast")
+#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \
+ ATTR_RAMFUNC ATTR_ALIGN(alignment)
+
+#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem")
+
+#define NOP() __asm volatile("nop")
+#define WFI() __asm volatile("wfi")
+
+#define HPM_ATTR_MACHINE_INTERRUPT __attribute__ ((section(".isr_vector"), interrupt("machine"), aligned(4)))
+
+#elif defined(__ICCRISCV__)
+
+/* alway_inline */
+#define ATTR_ALWAYS_INLINE __attribute__((always_inline))
+
+/* weak */
+#define ATTR_WEAK __weak
+
+/* alignment */
+#define ATTR_ALIGN(alignment) __attribute__((aligned(alignment)))
+
+/* place var_declare at section_name, e.x. PLACE_AT(".target_section", var); */
+#define ATTR_PLACE_AT(section_name) __attribute__((section(section_name)))
+
+#define ATTR_PLACE_AT_WITH_ALIGNMENT(section_name, alignment) \
+ATTR_PLACE_AT(section_name) ATTR_ALIGN(alignment)
+
+#define ATTR_PLACE_AT_NONCACHEABLE ATTR_PLACE_AT(".noncacheable.bss")
+#define ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE ATTR_ALIGN(alignment)
+
+#define ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_PLACE_AT(".noncacheable.bss")
+#define ATTR_PLACE_AT_NONCACHEABLE_BSS_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE_BSS ATTR_ALIGN(alignment)
+
+/* initialize variable x with y using PLACE_AT_NONCACHEABLE_INIT(x) = {y}; */
+#define ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_PLACE_AT(".noncacheable.init")
+#define ATTR_PLACE_AT_NONCACHEABLE_INIT_WITH_ALIGNMENT(alignment) \
+ ATTR_PLACE_AT_NONCACHEABLE_INIT ATTR_ALIGN(alignment)
+
+#define ATTR_RAMFUNC ATTR_PLACE_AT(".fast")
+#define ATTR_RAMFUNC_WITH_ALIGNMENT(alignment) \
+ ATTR_RAMFUNC ATTR_ALIGN(alignment)
+
+#define ATTR_SHARE_MEM ATTR_PLACE_AT(".sh_mem")
+
+#define NOP() __asm volatile("nop")
+#define WFI() __asm volatile("wfi")
+
+#define HPM_ATTR_MACHINE_INTERRUPT __machine __interrupt
+
+#else
+#error Unknown toolchain
+#endif
+#endif /* _HPM_COMMON_H */
diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi.h b/contrib/loaders/flash/hpmicro/hpm_romapi.h
new file mode 100644
index 0000000000..d19f551994
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/hpm_romapi.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/*
+ * Copyright (c) 2021-2023 HPMicro
+ */
+
+#ifndef HPM_ROMAPI_H
+#define HPM_ROMAPI_H
+
+/**
+ * @brief ROM APIs
+ * @defgroup romapi_interface ROM APIs
+ * @{
+ */
+
+#include "hpm_common.h"
+#include "hpm_romapi_xpi_def.h"
+#include "hpm_romapi_xpi_soc_def.h"
+#include "hpm_romapi_xpi_nor_def.h"
+
+/***********************************************************************************************************************
+ *
+ *
+ * Definitions
+ *
+ *
+ **********************************************************************************************************************/
+
+/**
+ * @brief Bootloader API table
+ */
+struct bootloader_api_table_t {
+ /**< Bootloader API table: version */
+ const uint32_t version;
+ /**< Bootloader API table: copyright string address */
+ const char *copyright;
+ /**< Bootloader API table: run_bootloader API */
+ const uint32_t reserved0;
+ /**< Bootloader API table: otp driver interface address */
+ const uint32_t reserved1;
+ /**< Bootloader API table: xpi driver interface address */
+ const struct xpi_driver_interface_t *xpi_driver_if;
+ /**< Bootloader API table: xpi nor driver interface address */
+ const struct xpi_nor_driver_interface_t *xpi_nor_driver_if;
+ /**< Bootloader API table: xpi ram driver interface address */
+ const uint32_t reserved2;
+};
+
+/**< Bootloader API table Root */
+#define ROM_API_TABLE_ROOT ((const struct bootloader_api_table_t *)0x2001FF00U)
+
+#endif /* HPM_ROMAPI_H */
diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h
new file mode 100644
index 0000000000..b4d73bd105
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_def.h
@@ -0,0 +1,254 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/*
+ * Copyright (c) 2021 HPMicro
+ */
+#ifndef HPM_ROMAPI_XPI_DEF_H
+#define HPM_ROMAPI_XPI_DEF_H
+
+/**
+ * @brief XPI ROM APIs
+ * @defgroup xpi_interface XPI driver APIs
+ * @{
+ */
+
+#include "hpm_common.h"
+
+/**
+ * @brief XPI Read Sample Clock source options
+ */
+enum xpi_rxclksrc_type_t {
+ xpi_rxclksrc_internal_loopback = 0, /**< Internal loopback */
+ xpi_rxclksrc_dqs_loopback = 1, /**< Loopback from DQS pad */
+ xpi_rxclksrc_external_dqs = 3, /**< Read is driven by External DQS pad */
+};
+
+/**
+ * @brief XPI pad definitions
+ */
+#define XPI_1PAD (0U) /**< Single pad */
+#define XPI_2PADS (1U) /**< Dual pads */
+#define XPI_4PADS (2U) /**< Quad pads */
+#define XPI_8PADS (3U) /**< Octal pads */
+
+/**
+ * @brief XPI IO pin group options
+ */
+enum xpi_io_group_t {
+ xpi_io_1st_group, /**< First/Primary group */
+ xpi_io_2nd_group, /**< Second/Secondary group */
+};
+
+/**
+ * @brief XPI Transfer Channel type definitions
+ */
+enum xpi_xfer_channel_t {
+ xpi_xfer_channel_a1, /**< The address is based on the device connected to Channel A1 */
+ xpi_xfer_channel_a2, /**< The address is based on the device connected to Channel A2 */
+ xpi_xfer_channel_b1, /**< The address is based on the device connected to Channel B1 */
+ xpi_xfer_channel_b2, /**< The address is based on the device connected to Channel B2 */
+ xpi_xfer_channel_auto, /**< The channel is auto determined */
+};
+
+/**
+ * @brief XPI Channel definitions
+ */
+enum xpi_channel_t {
+ xpi_channel_a1, /**< Port: Channel A1 */
+ xpi_channel_a2, /**< Port: Channel A2 */
+ xpi_channel_b1, /**< Port: Channel B1 */
+ xpi_channel_b2, /**< Port: Channel B2 */
+};
+
+/**
+ * @brief XPI APB Transfer type
+ */
+enum xpi_apb_xfer_type_t {
+ xpi_apb_xfer_type_cmd, /**< APB Command Type: Command only */
+ xpi_apb_xfer_type_config, /**< APB Command Type: Configuration */
+ xpi_apb_xfer_type_read, /**< APB Command Type: Read */
+ xpi_apb_xfer_type_write, /**< APB Command Type: Write */
+};
+
+/**
+ * @brief XPI Xfer Mode
+ */
+enum xpi_xfer_mode_t {
+ xpi_xfer_mode_polling, /**< Transfer mode: Polling */
+ xpi_xfer_mode_dma, /**< Transfer mode: DMA */
+ xpi_xfer_mode_interrupt, /**< Transfer mode: Interrupt */
+};
+
+/**
+ * @brief XPI Xfer context
+ */
+struct xpi_xfer_ctx_t {
+ uint32_t addr; /**< device address for XPI transfer */
+ uint8_t channel; /**< channel for XPI transfer */
+ uint8_t cmd_type; /**< command type for XPI transfer */
+ uint8_t seq_idx; /**< Sequence index for XPI transfer */
+ uint8_t seq_num; /**< Sequence number for XPI transfer */
+ uint32_t *buf; /**< Buffer for XPI transfer */
+ uint32_t xfer_size; /**< Transfer size in bytes */
+};
+
+/**
+ * @brief XPI instruction sequence
+ */
+struct xpi_instr_seq_t {
+ uint32_t entry[4];
+};
+
+/**
+ * @brief XPI Phase definitions
+ */
+#define XPI_PHASE_STOP (0x00U) /**< Phase: Stop */
+#define XPI_PHASE_CMD_SDR (0x01U) /**< Phase: Send CMD in SDR mode */
+#define XPI_PHASE_RADDR_SDR (0x02U) /**< Phase: Send Row Address in SDR Mode */
+#define XPI_PHASE_CADDR_SDR (0x03U) /**< Phase: Send Column Address in SDR Mode */
+#define XPI_PHASE_MODE4_SDR (0x06U) /**< Phase: Send Mode 4 in SDR Mode */
+#define XPI_PHASE_MODE8_SDR (0x07U) /**< Phase: Send Mode 8 in SDR Mode */
+#define XPI_PHASE_WRITE_SDR (0x08U) /**< Phase: Write data in SDR Mode */
+#define XPI_PHASE_READ_SDR (0x09U) /**< Phase: Read data in SDR Mode */
+#define XPI_PHASE_DUMMY_SDR (0X0CU) /**< Phase: Send Dummy in SDR Mode */
+#define XPI_PHASE_DUMMY_RWDS_SDR (0x0DU) /**< Phase: Send Dummy RWDS in SDR Mode */
+
+#define XPI_PHASE_CMD_DDR (0x21U) /**< Phase: Send CMD in DDR Mode */
+#define XPI_PHASE_RADDR_DDR (0x22U) /**< Phase: Send Raw Address in DDR Mode */
+#define XPI_PHASE_CADDR_DDR (0x23U) /**< Phase: Send Column address in DDR Mode */
+#define XPI_PHASE_MODE4_DDR (0x26U) /**< Phase: Send Mode 4 in DDR Mode */
+#define XPI_PHASE_MODE8_DDR (0x27U) /**< Phase: Send Mode 8 in DDR Mode */
+#define XPI_PHASE_WRITE_DDR (0x28U) /**< Phase: Write data in DDR Mode */
+#define XPI_PHASE_READ_DDR (0x29U) /**< Phase: Read data in SDR Mode */
+#define XPI_PHASE_DUMMY_DDR (0x2CU) /**< Phase: Send DUMMY in DDR Mode */
+#define XPI_PHASE_DUMMY_RWDS_DDR (0x2DU) /**< Phase: Send DUMMY RWDS in DDR Mode */
+
+/**
+ * @brief XPI API command error codes
+ */
+enum {
+ status_xpi_apb_jump_on_cs = MAKE_STATUS(status_group_xpi, 1),
+ status_xpi_apb_unknown_inst = MAKE_STATUS(status_group_xpi, 2),
+ status_xpi_apb_dummy_sdr_in_ddr_seq = MAKE_STATUS(status_group_xpi, 3),
+ status_xpi_apb_dummy_ddr_in_sdr_seq = MAKE_STATUS(status_group_xpi, 4),
+ status_xpi_apb_exceed_addr_range = MAKE_STATUS(status_group_xpi, 5),
+ status_xpi_apb_seq_timeout = MAKE_STATUS(status_group_xpi, 6),
+ status_xpi_apb_cross_boundary = MAKE_STATUS(status_group_xpi, 7),
+};
+
+/**
+ * @brief Delay line definitions
+ */
+enum {
+ xpi_dll_half_cycle = 0xFU,
+ xpi_dll_quarter_cycle = 0x7U,
+ xpi_dll_sdr_default_cycle = xpi_dll_half_cycle,
+ xpi_dll_ddr_default_cycle = xpi_dll_quarter_cycle,
+};
+
+/**
+ * @brief XPI configuration structure
+ */
+struct xpi_config_t {
+ uint8_t rxclk_src; /**< Read sample clock source */
+ uint8_t reserved0[7]; /**< Reserved */
+ uint8_t tx_watermark_in_dwords; /**< Tx watermark in double words */
+ uint8_t rx_watermark_in_dwords; /**< Rx watermark in double words */
+ uint8_t enable_differential_clk; /**< Enable differential clock */
+ uint8_t reserved1[5]; /**< Reserved */
+ uint32_t access_flags; /**< Access flags */
+};
+
+/**
+ * @brief XPI Device Configuration structure
+ */
+struct xpi_device_config_t {
+ uint32_t size_in_kbytes; /**< Device size in kbytes */
+ uint32_t serial_root_clk_freq; /**< XPI serial root clock frequency */
+
+ uint8_t enable_write_mask; /**< Enable write mask, typically for PSRAM/HyperRAM */
+ uint8_t data_valid_time; /**< Data valid time, Unit 0.1ns */
+ uint8_t reserved0[2];
+
+ uint8_t cs_hold_time; /**< CS hold time, cycles in terms of FLASH clock */
+ uint8_t cs_setup_time; /**< CS setup time, cycles in terms of FLASH clock */
+ uint16_t cs_interval; /**< CS interval, cycles in terms of FLASH clock */
+
+ uint8_t reserved1;
+ uint8_t column_addr_size; /**< Column address bits */
+ uint8_t enable_word_address; /**< Enable word address, for HyperFLASH/HyperRAM */
+ uint8_t dly_target; /**< Delay target */
+
+ uint8_t ahb_write_seq_idx; /**< AHB write sequence index */
+ uint8_t ahb_write_seq_num; /**< AHB write sequence number */
+ uint8_t ahb_read_seq_idx; /**< AHB read sequence index */
+ uint8_t ahb_read_seq_num; /**< AHB read sequence number */
+
+ uint8_t ahb_write_wait_interval; /**< AHB write wait interval, in terms of FLASH clock */
+ uint8_t reserved2[3];
+};
+
+/**
+ * @brief SUB Instruction
+ * @param [in] phase Name
+ * @param [in] pad Pad for Phase
+ * @param [in] op Operand for Phase
+ */
+#define SUB_INSTR(phase, pad, op) ((uint32_t)(((uint16_t)(phase) << 10) | ((uint16_t)(pad) << 8) | ((uint16_t)(op))))
+/**
+ * @brief Generate a single word INSTRUCTION sequence word
+ * @note Here intentionally use the MACRO because when the arguments are constant value, the compiler
+ * can generate the const entry word during pre-processing
+ */
+#define XPI_INSTR_SEQ(phase0, pad0, op0, phase1, pad1, op1) \
+ (SUB_INSTR(phase0, pad0, op0) | (SUB_INSTR(phase1, pad1, op1) << 16))
+
+struct xpi_ahb_buffer_cfg_t {
+ struct {
+ uint8_t priority; /* Offset: 0x00 */
+ uint8_t master_idx; /* Offset: 0x01 */
+ uint8_t buf_size_in_dword; /* Offset: 0x02 */
+ bool enable_prefetch; /* Offset: 0x03 */
+ } entry[8];
+};
+
+/**
+ * @brief XPI driver interface
+ */
+struct xpi_driver_interface_t {
+ /**< XPI driver interface: version */
+ uint32_t version;
+ /**< XPI driver interface: get default configuration */
+ hpm_stat_t (*get_default_config)(struct xpi_config_t *xpi_config);
+ /**< XPI driver interface: get default device configuration */
+ hpm_stat_t (*get_default_device_config)(struct xpi_device_config_t *dev_config);
+ /**< XPI driver interface: initialize the XPI using xpi_config */
+ hpm_stat_t (*init)(uint32_t *base, struct xpi_config_t *xpi_config);
+ /**< XPI driver interface: configure the AHB buffer */
+ hpm_stat_t (*config_ahb_buffer)(uint32_t *base, struct xpi_ahb_buffer_cfg_t *ahb_buf_cfg);
+ /**< XPI driver interface: configure the device */
+ hpm_stat_t (*config_device)(uint32_t *base, struct xpi_device_config_t *dev_cfg, enum xpi_channel_t channel);
+ /**< XPI driver interface: update instruction talbe */
+ hpm_stat_t (*update_instr_table)(uint32_t *base, const uint32_t *inst_base, uint32_t seq_idx, uint32_t num);
+ /**< XPI driver interface: transfer command/data using block interface */
+ hpm_stat_t (*transfer_blocking)(uint32_t *base, struct xpi_xfer_ctx_t *xfer);
+ /**< Software reset the XPI controller */
+ void (*software_reset)(uint32_t *base);
+ /**< XPI driver interface: Check whether IP is idle */
+ bool (*is_idle)(uint32_t *base);
+ /**< XPI driver interface: update delay line setting */
+ void (*update_dllcr)(uint32_t *base,
+ uint32_t serial_root_clk_freq,
+ uint32_t data_valid_time,
+ enum xpi_channel_t channel,
+ uint32_t dly_target);
+ /**< XPI driver interface: Get absolute address for APB transfer */
+ hpm_stat_t
+ (*get_abs_apb_xfer_addr)(uint32_t *base, enum xpi_xfer_channel_t channel, uint32_t in_addr, uint32_t *out_addr);
+};
+
+/**
+ * @}
+ */
+
+#endif /* HPM_ROMAPI_XPI_DEF_H */
diff --git a/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h
new file mode 100644
index 0000000000..edde8402fd
--- /dev/null
+++ b/contrib/loaders/flash/hpmicro/hpm_romapi_xpi_nor_def.h
@@ -0,0 +1,426 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/*
+ * Copyright (c) 2021 HPMicro
+ */
+#ifndef HPM_ROMAPI_XPI_NOR_DEF_H
+#define HPM_ROMAPI_XPI_NOR_DEF_H
+
+/**
+ * @brief XPI NOR ROM APIs
+ * @defgroup xpi_nor_interface XPI NOR driver APIs
+ * @ingroup romapi_interfaces
+ * @{
+ */
+
+#include "hpm_common.h"
+#include "hpm_romapi_xpi_def.h"
+
+#define XPI_NOR_CFG_TAG 0x524f4E58U /**< ASCII: "XNOR" */
+
+/**
+ * @brief XPI NOR properties
+ */
+enum {
+ xpi_nor_property_total_size, /**< Total size in bytes */
+ xpi_nor_property_page_size, /**< Page size in bytes */
+ xpi_nor_property_sector_size, /**xpi_nor_driver_if->version >= 0x56010300)
+
+struct hpm_flash_info_t {
+ uint32_t total_sz_in_bytes;
+ uint32_t sector_sz_in_bytes;
+};
+
+__attribute__ ((section(".flash_algo.data"))) struct xpi_nor_config_t nor_config;
+__attribute__ ((section(".flash_algo.data"))) bool xpi_inited = false;
+__attribute__ ((section(".flash_algo.data"))) uint32_t channel = xpi_channel_a1;
+__attribute__ ((section(".flash_algo.data"))) uint32_t *xpi_base;
+
+__attribute__ ((section(".flash_algo.text"))) void refresh_device_size(uint32_t *base,
+ struct xpi_nor_config_option_t *option)
+{
+ volatile uint32_t *dev_size = (volatile uint32_t *)((uint32_t)base + 0x60);
+ bool enable_channelb = false;
+ if (option->header.words > 1)
+ enable_channelb = option->option1.connection_sel == xpi_nor_connection_sel_chnb_cs0;
+ if (enable_channelb) {
+ dev_size[0] = 0;
+ dev_size[1] = 0;
+ }
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_init(uint32_t flash_base, uint32_t header,
+ uint32_t opt0, uint32_t opt1, uint32_t xpi_base_addr)
+{
+ uint32_t i = 0;
+ struct xpi_nor_config_option_t cfg_option;
+ hpm_stat_t stat = status_success;
+
+ xpi_base = (uint32_t *)xpi_base_addr;
+ if (xpi_inited)
+ return stat;
+
+ __asm volatile("csrc %0, %1" : : "i"(CSR_MCACHE_CTL), "r"(HPM_MCACHE_CTL_DC_EN_MASK));
+ for (i = 0; i < sizeof(cfg_option); i++)
+ *((uint8_t *)&cfg_option + i) = 0;
+ for (i = 0; i < sizeof(nor_config); i++)
+ *((uint8_t *)&nor_config + i) = 0;
+
+ cfg_option.header.U = header;
+ cfg_option.option0.U = opt0;
+ cfg_option.option1.U = opt1;
+
+ if (opt1 & XPI_USE_PORT_B_MASK)
+ channel = xpi_channel_b1;
+ else
+ channel = xpi_channel_a1;
+
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->auto_config(xpi_base, &nor_config, &cfg_option);
+ if (stat)
+ return stat;
+
+ if (ROMAPI_SUPPORTS_HYBRIDXPI())
+ ROM_API_TABLE_ROOT->xpi_nor_driver_if->enable_hybrid_xpi(xpi_base);
+
+ refresh_device_size(xpi_base, &cfg_option);
+
+ nor_config.device_info.clk_freq_for_non_read_cmd = 0;
+ if (!xpi_inited)
+ xpi_inited = true;
+ return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase(uint32_t flash_base, uint32_t address, uint32_t size)
+{
+ hpm_stat_t stat = status_success;
+ uint32_t left, start, block_size, align;
+
+ left = size;
+ start = address;
+ if (ROMAPI_SUPPORTS_HYBRIDXPI())
+ start += flash_base;
+ block_size = nor_config.device_info.block_size_kbytes * 1024;
+ if (left >= block_size) {
+ align = block_size - (start % block_size);
+ if (align != block_size) {
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, &nor_config, start, align);
+ if (stat != status_success)
+ return stat;
+ left -= align;
+ start += align;
+ }
+ while (left > block_size) {
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_block(xpi_base, channel, &nor_config, start);
+ if (stat != status_success)
+ break;
+ left -= block_size;
+ start += block_size;
+ }
+ }
+ if (stat == status_success && left)
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase(xpi_base, channel, &nor_config, start, left);
+ return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_program(uint32_t flash_base, uint32_t address,
+ uint32_t *buf, uint32_t size)
+{
+ hpm_stat_t stat;
+
+ if (ROMAPI_SUPPORTS_HYBRIDXPI())
+ address += flash_base;
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->program(xpi_base, channel, &nor_config, buf, address, size);
+ return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_read(uint32_t flash_base, uint32_t *buf,
+ uint32_t address, uint32_t size)
+{
+ hpm_stat_t stat;
+
+ if (ROMAPI_SUPPORTS_HYBRIDXPI())
+ address += flash_base;
+ stat = ROM_API_TABLE_ROOT->xpi_nor_driver_if->read(xpi_base, channel, &nor_config, buf, address, size);
+ return stat;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_get_info(uint32_t flash_base,
+ struct hpm_flash_info_t *flash_info)
+{
+ if (!flash_info)
+ return status_invalid_argument;
+
+ flash_info->total_sz_in_bytes = nor_config.device_info.size_in_kbytes << 10;
+ flash_info->sector_sz_in_bytes = nor_config.device_info.sector_size_kbytes << 10;
+ return status_success;
+}
+
+__attribute__ ((section(".flash_algo.text"))) uint32_t flash_erase_chip(uint32_t flash_base)
+{
+ return ROM_API_TABLE_ROOT->xpi_nor_driver_if->erase_chip(xpi_base, channel, &nor_config);
+}
+
+__attribute__ ((section(".flash_algo.text"))) void flash_deinit(void)
+{
+}
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/contrib/loaders/flash/silabs/Makefile b/contrib/loaders/flash/silabs/Makefile
new file mode 100644
index 0000000000..7323494ec0
--- /dev/null
+++ b/contrib/loaders/flash/silabs/Makefile
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+
+CC=$(CROSS_COMPILE)gcc
+OBJCOPY=$(CROSS_COMPILE)objcopy
+OBJDUMP=$(CROSS_COMPILE)objdump
+
+
+AFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL
+CFLAGS = -c -mthumb -nostdlib -nostartfiles -Os -g -fPIC
+
+all: silabs_s0_s1.inc silabs_s2.inc
+
+.PHONY: clean
+
+%.elf: %.S
+ $(CC) $(AFLAGS) $< -o $@
+
+%.lst: %.elf
+ $(OBJDUMP) -S $< > $@
+
+%.bin: %.elf
+ $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+ $(BIN2C) < $< > $@
+
+clean:
+ -rm -f *.elf *.lst *.bin *.inc
diff --git a/contrib/loaders/flash/efm32.S b/contrib/loaders/flash/silabs/silabs_s0_s1.S
similarity index 100%
rename from contrib/loaders/flash/efm32.S
rename to contrib/loaders/flash/silabs/silabs_s0_s1.S
diff --git a/contrib/loaders/flash/silabs/silabs_s0_s1.inc b/contrib/loaders/flash/silabs/silabs_s0_s1.inc
new file mode 100644
index 0000000000..40e616b322
--- /dev/null
+++ b/contrib/loaders/flash/silabs/silabs_s0_s1.inc
@@ -0,0 +1,7 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x01,0x26,0x86,0x60,0x16,0x68,0x00,0x2e,0x22,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,
+0x04,0x61,0x01,0x26,0xc6,0x60,0xc6,0x69,0x06,0x27,0x3e,0x42,0x16,0xd1,0xc6,0x69,
+0x08,0x27,0x3e,0x42,0xfb,0xd0,0x2e,0x68,0x86,0x61,0x08,0x26,0xc6,0x60,0x04,0x35,
+0x04,0x34,0xc6,0x69,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x46,
+0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29,0x02,0xd0,0xdb,0xe7,0x00,0x20,0x50,0x60,
+0x30,0x46,0x00,0xbe,
diff --git a/contrib/loaders/flash/silabs/silabs_s2.S b/contrib/loaders/flash/silabs/silabs_s2.S
new file mode 100644
index 0000000000..d7f43855ce
--- /dev/null
+++ b/contrib/loaders/flash/silabs/silabs_s2.S
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2011 by Andreas Fritiofson *
+ * andreas.fritiofson@gmail.com *
+ * Copyright (C) 2013 by Roman Dmitrienko *
+ * me@iamroman.org *
+ ***************************************************************************/
+
+ .text
+ .syntax unified
+ .cpu cortex-m0
+ .thumb
+ .thumb_func
+
+ /* Params:
+ * r0 - flash base (in), status (out)
+ * r1 - count (word-32bit)
+ * r2 - workarea start
+ * r3 - workarea end
+ * r4 - target address
+ * Clobbered:
+ * r5 - rp
+ * r6 - wp, tmp
+ * r7 - tmp
+ */
+
+/* offsets of registers from flash reg base */
+#define EFM32_MSC_WRITECTRL_OFFSET 0x00c
+#define EFM32_MSC_WRITECMD_OFFSET 0x010
+#define EFM32_MSC_ADDRB_OFFSET 0x014
+#define EFM32_MSC_WDATA_OFFSET 0x018
+#define EFM32_MSC_STATUS_OFFSET 0x01c
+
+ /* set WREN to 1 */
+ movs r6, #1
+ str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET]
+
+wait_fifo:
+ ldr r6, [r2, #0] /* read wp */
+ cmp r6, #0 /* abort if wp == 0 */
+ beq exit
+ ldr r5, [r2, #4] /* read rp */
+ cmp r5, r6 /* wait until rp != wp */
+ beq wait_fifo
+
+ /* store address in MSC_ADDRB */
+ str r4, [r0, #EFM32_MSC_ADDRB_OFFSET]
+ /* set LADDRIM bit */
+ movs r6, #1
+ str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
+ /* check status for INVADDR and/or LOCKED */
+ ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
+ movs r7, #6
+ tst r6, r7
+ bne error
+
+ /* wait for WDATAREADY */
+wait_wdataready:
+ ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
+ movs r7, #8
+ tst r6, r7
+ beq wait_wdataready
+
+ /* load data to WDATA */
+ ldr r6, [r5]
+ str r6, [r0, #EFM32_MSC_WDATA_OFFSET]
+ /* set WRITEONCE bit */
+ movs r6, #8
+ str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET]
+
+ adds r5, #4 /* rp++ */
+ adds r4, #4 /* target_address++ */
+
+ /* wait until BUSY flag is reset */
+busy:
+ ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET]
+ movs r7, #1
+ tst r6, r7
+ bne busy
+
+ cmp r5, r3 /* wrap rp at end of buffer */
+ bcc no_wrap
+ adds r5, r2, #0
+ adds r5, #8
+no_wrap:
+ str r5, [r2, #4] /* store rp */
+ subs r1, r1, #1 /* decrement word count */
+ cmp r1, #0
+ beq exit /* loop if not done */
+ b wait_fifo
+error:
+ movs r0, #0
+ str r0, [r2, #4] /* set rp = 0 on error */
+exit:
+ adds r0, r6, #0
+ bkpt #0
diff --git a/contrib/loaders/flash/silabs/silabs_s2.inc b/contrib/loaders/flash/silabs/silabs_s2.inc
new file mode 100644
index 0000000000..f0ef04edda
--- /dev/null
+++ b/contrib/loaders/flash/silabs/silabs_s2.inc
@@ -0,0 +1,7 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x01,0x26,0xc6,0x60,0x16,0x68,0x00,0x2e,0x22,0xd0,0x55,0x68,0xb5,0x42,0xf9,0xd0,
+0x44,0x61,0x01,0x26,0x06,0x61,0xc6,0x69,0x06,0x27,0x3e,0x42,0x16,0xd1,0xc6,0x69,
+0x08,0x27,0x3e,0x42,0xfb,0xd0,0x2e,0x68,0x86,0x61,0x08,0x26,0x06,0x61,0x04,0x35,
+0x04,0x34,0xc6,0x69,0x01,0x27,0x3e,0x42,0xfb,0xd1,0x9d,0x42,0x01,0xd3,0x15,0x1c,
+0x08,0x35,0x55,0x60,0x01,0x39,0x00,0x29,0x02,0xd0,0xdb,0xe7,0x00,0x20,0x50,0x60,
+0x30,0x1c,0x00,0xbe,
diff --git a/contrib/loaders/flash/stm32/stm32h7rx.S b/contrib/loaders/flash/stm32/stm32h7rx.S
new file mode 100644
index 0000000000..bfc4929d09
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32h7rx.S
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ * Copyright (C) 2017 by STMicroelectronics *
+ ***************************************************************************/
+
+ .text
+ .syntax unified
+ .cpu cortex-m4
+ .thumb
+
+/*
+ * Code limitations:
+ * The workarea must have size multiple of 4 bytes, since R/W
+ * operations are all at 32 bits.
+ * The workarea must be big enough to contain rp, wp and data, thus the minimum
+ * workarea size is: min_wa_size = sizeof(rp, wp, data) = 4 + 4 + sizeof(data).
+ * - for 0x450 devices: sizeof(data) = 32 bytes, thus min_wa_size = 40 bytes.
+ * - for 0x480 devices: sizeof(data) = 16 bytes, thus min_wa_size = 24 bytes.
+ * To benefit from concurrent host write-to-buffer and target
+ * write-to-flash, the workarea must be way bigger than the minimum.
+ *
+ * To avoid confusions the write word size is got from .block_size member of
+ * struct stm32h7x_part_info defined in stm32h7x.c
+*/
+
+/*
+ * Params :
+ * r0 = workarea start, status (out)
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (of write words)
+ * r4 = size of write word
+ * r5 = flash reg base
+ *
+ * Clobbered:
+ * r6 - rp
+ * r7 - wp, status, tmp
+ * r8 - loop index, tmp
+ */
+
+#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
+#define STM32_FLASH_SR_OFFSET 0x14 /* offset of SR register in FLASH struct */
+#define STM32_FLASH_ICR_OFFSET 0x28 /* offset of SR register in FLASH struct */
+#define STM32_CR_PROG 0x00000002 /* PG */
+#define STM32_SR_QW_MASK 0x00000004 /* QW */
+#define STM32_SR_ERROR_MASK 0x1F2E0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR
+ | INCERR | STRBERR | PGSERR | WRPERR */
+
+ .thumb_func
+ .global _start
+_start:
+ ldr r6, [r0, #4] /* read rp */
+
+wait_fifo:
+ ldr r7, [r0, #0] /* read wp */
+ cbz r7, exit /* abort if wp == 0, status = 0 */
+ subs r7, r7, r6 /* number of bytes available for read in r7 */
+ ittt mi /* if wrapped around */
+ addmi r7, r1 /* add size of buffer */
+ submi r7, r0
+ submi r7, #8
+ cmp r7, r4 /* wait until data buffer is full */
+ bcc wait_fifo
+
+ mov r7, #STM32_CR_PROG
+ str r7, [r5, #STM32_FLASH_CR_OFFSET]
+
+ mov r8, #4
+ udiv r8, r4, r8 /* number of words is size of write word divided by 4*/
+write_flash:
+ dsb
+ ldr r7, [r6], #0x04 /* read one word from src, increment ptr */
+ str r7, [r2], #0x04 /* write one word to dst, increment ptr */
+ dsb
+ cmp r6, r1 /* if rp >= end of buffer ... */
+ it cs
+ addcs r6, r0, #8 /* ... then wrap at buffer start */
+ subs r8, r8, #1 /* decrement loop index */
+ bne write_flash /* loop if not done */
+
+busy:
+ ldr r7, [r5, #STM32_FLASH_SR_OFFSET]
+ tst r7, #STM32_SR_QW_MASK
+ bne busy /* operation in progress, wait ... */
+
+ ldr r7, [r5, #STM32_FLASH_ICR_OFFSET]
+ ldr r8, =STM32_SR_ERROR_MASK
+ tst r7, r8
+ bne error /* fail... */
+
+ str r6, [r0, #4] /* store rp */
+ subs r3, r3, #1 /* decrement count */
+ bne wait_fifo /* loop if not done */
+ b exit
+
+error:
+ movs r8, #0
+ str r8, [r0, #4] /* set rp = 0 on error */
+
+exit:
+ mov r0, r7 /* return status in r0 */
+ bkpt #0x00
+
+ .pool
diff --git a/contrib/loaders/flash/stm32/stm32h7rx.inc b/contrib/loaders/flash/stm32/stm32h7rx.inc
new file mode 100644
index 0000000000..feecab6230
--- /dev/null
+++ b/contrib/loaders/flash/stm32/stm32h7rx.inc
@@ -0,0 +1,8 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0x46,0x68,0x07,0x68,0x77,0xb3,0xbf,0x1b,0x42,0xbf,0x7f,0x18,0x3f,0x1a,0x08,0x3f,
+0xa7,0x42,0xf6,0xd3,0x4f,0xf0,0x02,0x07,0x2f,0x61,0x4f,0xf0,0x04,0x08,0xb4,0xfb,
+0xf8,0xf8,0xbf,0xf3,0x4f,0x8f,0x56,0xf8,0x04,0x7b,0x42,0xf8,0x04,0x7b,0xbf,0xf3,
+0x4f,0x8f,0x8e,0x42,0x28,0xbf,0x00,0xf1,0x08,0x06,0xb8,0xf1,0x01,0x08,0xf0,0xd1,
+0x6f,0x69,0x17,0xf0,0x04,0x0f,0xfb,0xd1,0xaf,0x6a,0xdf,0xf8,0x1c,0x80,0x17,0xea,
+0x08,0x0f,0x03,0xd1,0x46,0x60,0x01,0x3b,0xd3,0xd1,0x03,0xe0,0x5f,0xf0,0x00,0x08,
+0xc0,0xf8,0x04,0x80,0x38,0x46,0x00,0xbe,0x00,0x00,0x2e,0x1f,
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..e8a375cddd 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.
@@ -46,7 +45,7 @@ OpenOCD project.
- use TAB characters for indentation; do NOT use spaces.
- displayed TAB width is 4 characters.
- use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n')
-- limit adjacent empty lines to at most two (2).
+- do NOT use multiple empty lines.
- remove any trailing empty lines at the end of source files
- do not "comment out" code from the tree nor put it within a block
@code
@@ -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 1a61cd3c4b..33d7bce320 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -19,7 +19,7 @@ dated @value{UPDATED},
of the Open On-Chip Debugger (OpenOCD).
@itemize @bullet
-@item Copyright @copyright{} 2008-2022 The OpenOCD Project
+@item Copyright @copyright{} 2008-2025 The OpenOCD Project
@item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk}
@item Copyright @copyright{} 2008-2010 Oyvind Harboe @email{oyvind.harboe@@zylin.com}
@item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com}
@@ -154,15 +154,15 @@ USB-based, parallel port-based, and other standalone boxes that run
OpenOCD internally. @xref{Debug Adapter Hardware}.
@b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T,
-ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M3
-(Stellaris LM3, STMicroelectronics STM32 and Energy Micro EFM32) and
+ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x), Cortex-M
+(Stellaris LM3, STMicroelectronics STM32 and Silicon Labs EFM32/EFR32) and
Intel Quark (x10xx) based cores to be debugged via the GDB protocol.
@b{Flash Programming:} Flash writing is supported for external
CFI-compatible NOR flashes (Intel and AMD/Spansion command set) and several
internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U,
-STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash
-controllers (LPC3180, Orion, S3C24xx, more) is included.
+STR7x, STR9x, LM3, STM32x and EFM32/EFR32). Preliminary support for various NAND
+flash controllers (LPC3180, Orion, S3C24xx, more) is included.
@section OpenOCD Web Site
@@ -239,7 +239,7 @@ needing a Git client:
@uref{http://repo.or.cz/w/openocd.git}
-The @file{README} file contains the instructions for building the project
+The @file{README.md} file contains the instructions for building the project
from the repository or a snapshot.
Developers that want to contribute patches to the OpenOCD system are
@@ -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,15 @@ 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{xvc}
+@* A JTAG driver using Xilinx Virtual Cable over TCP to OpenOCD as JTAG interface.
@item @b{linuxspidev}
@* A SPI based SWD driver using Linux SPI devices.
@@ -625,7 +633,11 @@ emulation model of target hardware.
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.
+@* A JTAG driver to communicate with builtin debug modules of Espressif ESP32-C3, ESP32-C6, ESP32-H2 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
@@ -804,8 +816,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.
@@ -1185,9 +1196,10 @@ monitor mode debug, only "halt mode" debug.}
@cindex ARM semihosting
When linked with a special runtime library provided with many
toolchains@footnote{See chapter 8 "Semihosting" in
-@uref{http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf,
-ARM DUI 0203I}, the "RealView Compilation Tools Developer Guide".
-The CodeSourcery EABI toolchain also includes a semihosting library.},
+@uref{https://developer.arm.com/documentation/dui0203/latest/semihosting,
+ARM DUI 0203}.
+A semihosting library if available in newlib/libgloss, in U-Boot,
+in the CodeSourcery EABI toolchain, and others.},
your target code can use I/O facilities on the debug host. That library
provides a small set of system calls which are handled by OpenOCD.
It can let the debugger provide your system console and a file system,
@@ -1382,11 +1394,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 +1444,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.
@@ -1763,10 +1774,10 @@ There are more complex examples too, with chips that have
multiple TAPs. Ones worth looking at include:
@itemize
-@item @file{target/omap3530.cfg} -- with disabled ARM and DSP,
+@item @file{target/ti/omap3530.cfg} -- with disabled ARM and DSP,
plus a JRC to enable them
@item @file{target/str912.cfg} -- with flash, CPU, and boundary scan
-@item @file{target/ti_dm355.cfg} -- with ETM, ARM, and JRC (this JRC
+@item @file{target/ti/dm355.cfg} -- with ETM, ARM, and JRC (this JRC
is not currently used)
@end itemize
@@ -2360,6 +2371,11 @@ MMU: disabled, D-Cache: disabled, I-Cache: enabled
@end example
@end deffn
+@deffn {Command} {poll_interval} [milliseconds]
+Set the polling interval of target's state.
+With no parameter, it prints out the current value of polling interval.
+@end deffn
+
@node Debug Adapter Configuration
@chapter Debug Adapter Configuration
@cindex config file, interface
@@ -2431,13 +2447,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 +2467,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,17 +2490,28 @@ 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}
Returns the name of the debug adapter driver being used.
@end deffn
+@deffn {Config Command} {adapter usb vid_pid} (vid pid)+
+Specifies the USB vendor and product IDs of the adapter to use.
+Currently, up to 16 [@var{vid}, @var{pid}] pairs may be given, e.g.
+@example
+adapter usb vid_pid 0xc251 0xf001 0x0d28 0x0204
+@end example
+@end deffn
+
@deffn {Config Command} {adapter usb location} [-[.]...]
Displays or specifies the physical USB port of the adapter to use. The path
roots at @var{bus} and walks down the physical ports, with each
@@ -2493,12 +2522,20 @@ The USB bus topology can be queried with the command @emph{lsusb -t} or @emph{dm
This command is only available if your libusb1 is at least version 1.0.16.
@end deffn
+@deffn {Config Command} {adapter usb product_name} name
+Specifies the USB product name (the @emph{iProduct} string) of the adapter to use.
+If this is not set, the product name is not used during device selection.
+@end deffn
+
@deffn {Config Command} {adapter serial} serial_string
Specifies the @var{serial_string} of the adapter to use.
If this command is not specified, serial strings are not checked.
Only the following adapter drivers use the serial string from this command:
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 +2545,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,36 +2583,109 @@ and a specific set of GPIOs is used.
@c chooses among list of bit configs ... only one option
@end deffn
-@deffn {Interface Driver} {cmsis-dap}
-ARM CMSIS-DAP compliant based adapter v1 (USB HID based)
-or v2 (USB bulk).
+@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).
-@deffn {Config Command} {cmsis-dap vid_pid} [vid pid]+
-The vendor ID and product ID of the CMSIS-DAP device. If not specified
-the driver will attempt to auto detect the CMSIS-DAP device.
-Currently, up to eight [@var{vid}, @var{pid}] pairs may be given, e.g.
-@example
-cmsis-dap vid_pid 0xc251 0xf001 0x0d28 0x0204
-@end example
+@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}}.
@end deffn
-@deffn {Config Command} {cmsis-dap backend} [@option{auto}|@option{usb_bulk}|@option{hid}]
+@deffn {Interface Driver} {cklink}
+Driver for the T-Head CK-Link Lite V2 JTAG probe and Bouffalo Lab
+BL616/BL702 clones, including the built-in debugger on Bouffalo BL618
+evaluation boards. Communication is over USB bulk endpoints using a
+T-Head DebugServer-compatible framed command protocol.
+
+The driver only supports JTAG transport and a single-TAP chain. The
+probe runs at a fixed clock; @command{adapter speed} requests are
+accepted but ignored (with a one-time warning). @command{JTAG_TMS} and
+@command{JTAG_PATHMOVE} are not supported by this probe's protocol.
+
+By default the driver matches 0x42bf/0xb210 (Bouffalo) and
+0x32bf/0xb210 (T-Head). The built-in list can be overridden via
+@command{adapter usb vid_pid}.
+@end deffn
+
+@deffn {Interface Driver} {cmsis-dap}
+ARM CMSIS-DAP compliant based adapter v1 (USB HID based)
+or v2 (USB bulk or TCP/IP).
+
+@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:
@@ -2649,20 +2761,6 @@ signal. The following output buffer configurations are supported:
These interfaces have several commands, used to configure the driver
before initializing the JTAG scan chain:
-@deffn {Config Command} {ftdi vid_pid} [vid pid]+
-The vendor ID and product ID of the adapter. Up to eight
-[@var{vid}, @var{pid}] pairs may be given, e.g.
-@example
-ftdi vid_pid 0x0403 0xcff8 0x15ba 0x0003
-@end example
-@end deffn
-
-@deffn {Config Command} {ftdi device_desc} description
-Provides the USB device description (the @emph{iProduct string})
-of the adapter. If not specified, the device description is ignored
-during device selection.
-@end deffn
-
@deffn {Config Command} {ftdi channel} channel
Selects the channel of the FTDI device to use for MPSSE operations. Most
adapters use the default, channel 0, but there are exceptions.
@@ -2807,11 +2905,6 @@ FT232R
These interfaces have several commands, used to configure the driver
before initializing the JTAG scan chain:
-@deffn {Config Command} {ft232r vid_pid} @var{vid} @var{pid}
-The vendor ID and product ID of the adapter. If not specified, default
-0x0403:0x6001 is used.
-@end deffn
-
@deffn {Config Command} {ft232r jtag_nums} @var{tck} @var{tms} @var{tdi} @var{tdo}
Set four JTAG GPIO numbers at once.
If not specified, default 0 3 1 2 or TXD CTS RXD RTS is used.
@@ -2912,22 +3005,25 @@ remote_bitbang host mysocket
@deffn {Interface Driver} {usb_blaster}
USB JTAG/USB-Blaster compatibles over one of the userspace libraries
-for FTDI chips. These interfaces have several commands, used to
-configure the driver before initializing the JTAG scan chain:
+for FTDI chips.
-@deffn {Config Command} {usb_blaster vid_pid} vid pid
-The vendor ID and product ID of the FTDI FT245 device. If not specified,
-default values are used.
-Currently, only one @var{vid}, @var{pid} pair may be given, e.g. for
-Altera USB-Blaster (default):
+Use @command{adapter usb vid_pid} to specify the vendor and product ID of the
+FT245 device. If not specified, default values are used.
+
+For example, Altera USB-Blaster (default):
@example
-usb_blaster vid_pid 0x09FB 0x6001
+adapter usb vid_pid 0x09FB 0x6001
@end example
The following VID/PID is for Kolja Waschk's USB JTAG:
@example
-usb_blaster vid_pid 0x16C0 0x06AD
+adapter usb vid_pid 0x16C0 0x06AD
@end example
-@end deffn
+
+Note that the second VID/PID pair passed to @command{adapter usb vid_pid} is
+used to detect uninitialized devices.
+
+This driver has several commands, used for configuration before initializing the
+JTAG scan chain:
@deffn {Command} {usb_blaster pin} (@option{pin6}|@option{pin8}) (@option{0}|@option{1}|@option{s}|@option{t})
Sets the state or function of the unused GPIO pins on USB-Blasters
@@ -2956,6 +3052,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 +3205,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 +3272,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 +3295,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}
@@ -3250,10 +3342,6 @@ Currently Not Supported.
Specifies the adapter layout to use.
@end deffn
-@deffn {Config Command} {hla vid_pid} [vid pid]+
-Pairs of vendor IDs and product IDs of the device.
-@end deffn
-
@deffn {Config Command} {hla stlink_backend} (usb | tcp [port])
@emph{ST-Link only:} Choose between 'exclusive' USB communication (the default backend) or
'shared' mode using ST-Link TCP server (the default port is 7184).
@@ -3302,10 +3390,6 @@ ST-LINK server software module}.
@emph{Note:} ST-Link TCP server does not support the SWIM transport.
@end deffn
-@deffn {Config Command} {st-link vid_pid} [vid pid]+
-Pairs of vendor IDs and product IDs of the device.
-@end deffn
-
@deffn {Command} {st-link cmd} rx_n (tx_byte)+
Sends an arbitrary command composed by the sequence of bytes @var{tx_byte}
and receives @var{rx_n} bytes.
@@ -3374,9 +3458,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
@@ -3385,8 +3486,7 @@ able to coexist nicely with both sysfs bitbanging and various
peripherals' kernel drivers. The driver restores the previous
configuration on exit.
-GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is
-handled by the generic command @ref{adapter gpio, @command{adapter gpio}}.
+GPIO configuration is handled by the generic command @ref{adapter gpio, @command{adapter gpio}}.
See @file{interface/raspberrypi-native.cfg} for a sample config and
@file{interface/raspberrypi-gpio-connector.cfg} for pinout.
@@ -3415,9 +3515,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
@@ -3554,20 +3652,6 @@ Currently valid @var{variant} values include:
(see @uref{http://www.cypress.com/?rID=82870}).
@end itemize
@end deffn
-
-@deffn {Config Command} {openjtag device_desc} string
-The USB device description string of the adapter.
-This value is only used with the standard variant.
-@end deffn
-
-@deffn {Config Command} {openjtag vid_pid} vid pid
-The USB vendor ID and product ID of the adapter. If not specified, default
-0x0403:0x6001 is used.
-This value is only used with the standard variant.
-@example
-openjtag vid_pid 0x403 0x6014
-@end example
-@end deffn
@end deffn
@@ -3616,7 +3700,24 @@ Specifies the TCP/IP port number of the SystemVerilog DPI server interface.
@end deffn
@deffn {Config Command} {jtag_dpi set_address} address
-Specifies the TCP/IP address of the SystemVerilog DPI server interface.
+Specifies the hostname or IP address of the SystemVerilog DPI server interface.
+@end deffn
+@end deffn
+
+@deffn {Interface Driver} {jtag_vpi}
+A JTAG driver acting as a client for the JTAG VPI server interface.
+
+@deffn {Config Command} {jtag_vpi set_address} address
+Specifies the hostname or IP address of the JTAG VPI server.
+@end deffn
+
+@deffn {Config Command} {jtag_vpi set_port} port
+Specifies the TCP/IP port number of the JTAG VPI server.
+@end deffn
+
+@deffn {Config Command} {jtag_vpi stop_sim_on_exit} (@option{on}|@option{off})
+Specifies whether simulation stop command shall be sent before OpenOCD exits.
+The default is @option{off}.
@end deffn
@end deffn
@@ -3683,7 +3784,7 @@ buspirate led 1
@end deffn
@deffn {Interface Driver} {esp_usb_jtag}
-Espressif JTAG driver to communicate with ESP32-C3, ESP32-S3 chips and ESP USB Bridge board using OpenOCD.
+Espressif JTAG driver to communicate with ESP32-C3, ESP32-C6, ESP32-H2 and ESP32-S3 chips and ESP USB Bridge board using OpenOCD.
These chips have built-in JTAG circuitry and can be debugged without any additional hardware.
Only an USB cable connected to the D+/D- pins is necessary.
@@ -3698,13 +3799,6 @@ espusbjtag setio 0 1 0 1 0
@end example
@end deffn
-@deffn {Config Command} {espusbjtag vid_pid} vid_pid
-Set vendor ID and product ID for the ESP usb jtag driver
-@example
-espusbjtag vid_pid 0x303a 0x1001
-@end example
-@end deffn
-
@deffn {Config Command} {espusbjtag caps_descriptor} caps_descriptor
Set the jtag descriptor to read capabilities of ESP usb jtag driver
@example
@@ -3755,7 +3849,7 @@ device configuration, this function may be blocked out. Typical behavior
observed in such cases is a firewall exception report on the security
controller and armv8 processor reporting a system error.
-See @file{tcl/interface/ti_k3_am625-swd-native.cfg} for a sample configuration
+See @file{tcl/board/ti/am625-self-hosted.cfg} for a sample configuration
file.
@deffn {Command} {dmem info}
@@ -3792,6 +3886,34 @@ Set the emulated address and address window size. Both of these
parameters must be aligned to page size.
@end deffn
+@deffn {Interface Driver} {xvc}
+This driver implements bitbang mode of JTAG devices
+using Xilinx Virtual Cable messages over TCP/IP.
+This implementation is XVC protocol 1.0/1.1 compatible. However, 'mrd' and 'mwr'
+extensions introduced in version 1.1 are not supported. Refer to:
+@url{https://github.com/Xilinx/XilinxVirtualCable} for protocol specification.
+
+An implementation of XVC server to gpiod is available in
+@url{https://pypi.org/project/xvc-gpiod}
+and is suitable for testing this driver.
+
+Example configuration:
+
+@example
+xvc host 192.168.3.192
+xvc port 5000
+@end example
+@end deffn
+
+@deffn {Config Command} {xvc host} @var{hostname}
+Specifies the hostname of the remote debugger or UNIX socket to connect to.
+@end deffn
+
+@deffn {Config Command} {xvc port} @var{number}
+Specifies the port of the remote process to connect to.
+'0' is a special case where UNIX sockets are used.
+@end deffn
+
@end deffn
@section Transport Configuration
@@ -5061,6 +5183,10 @@ The current implementation supports eSi-32xx cores.
@item @code{esp32} -- this is an Espressif SoC with dual Xtensa cores.
@item @code{esp32s2} -- this is an Espressif SoC with single Xtensa core.
@item @code{esp32s3} -- this is an Espressif SoC with dual Xtensa cores.
+@item @code{esp32c2} -- this is an Espressif SoC with single RISC-V core.
+@item @code{esp32c3} -- this is an Espressif SoC with single RISC-V core.
+@item @code{esp32c6} -- this is an Espressif SoC with single RISC-V core.
+@item @code{esp32h2} -- this is an Espressif SoC with single RISC-V core.
@item @code{fa526} -- resembles arm920 (w/o Thumb).
@item @code{feroceon} -- resembles arm926.
@item @code{hla_target} -- a Cortex-M alternative to work with HL adapters like ST-Link.
@@ -5469,7 +5595,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
@@ -5528,6 +5655,20 @@ Otherwise, or if the optional @var{phys} flag is specified,
If @var{count} is specified, fills that many units of consecutive address.
@end deffn
+@deffn {Command} {$target_name disassemble} address [count [instruction_set]]
+@deffnx {Command} {$target_name disassemble} list
+This command requires Capstone library installed.
+
+Disassembles @var{count} instructions starting at @var{address}.
+If @var{count} is not specified, a single instruction is disassembled.
+
+It uses the target @var{$target_name} to read the instructions from memory,
+then disassemble them using either the instruction set detected on the same
+target or the one provided with @var{instruction_set}.
+
+With parameter @var{list} it dumps the list of supported instruction set.
+@end deffn
+
@anchor{targetevents}
@section Target Events
@cindex target events
@@ -5899,6 +6040,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}
@@ -6024,7 +6183,7 @@ Some drivers also activate driver-specific commands.
This is a special driver that maps a previously defined bank to another
address. All bank settings will be copied from the master physical bank.
-The @var{virtual} driver defines one mandatory parameters,
+The @var{virtual} driver defines one mandatory parameter,
@itemize
@item @var{master_bank} The bank that this virtual address refers to.
@@ -6042,6 +6201,28 @@ flash bank vbank1 virtual 0x9fc00000 0 0 0 \
@end example
@end deffn
+@deffn {Flash Driver} ro_alias
+Similar as @var{virtual} driver but suppresses write
+and erase. Use to build a complete memory map for gdb.
+Bank size will be copied from the master physical bank.
+
+The @var{virtual} driver defines one mandatory parameter,
+
+@itemize
+@item @var{master_bank} The bank that this virtual address refers to.
+@end itemize
+@end deffn
+
+@deffn {Flash Driver} read_only
+A stub driver without write and erase.
+Use to define a ROM region for the gdb memory map.
+
+@example
+flash bank $_CHIPNAME.sysrom read_only 0x1ff00000 0xedc0 0 0 \
+ $_TARGETNAME
+@end example
+@end deffn
+
@subsection External Flash
@deffn {Flash Driver} {cfi}
@@ -6089,6 +6270,22 @@ flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME
@c "cfi part_id" disabled
@end deffn
+@deffn {Flash Driver} {hpm_xpi}
+All members of the HPMxxxx microcontroller family from HPMicro.
+Additional parameters are required to configure the driver: @option{io_base} is
+the base address of the configuration register interface, @option{opt0} and
+@option{opt1} are the options for the flash.
+
+@example
+flash bank $@{_FLASHNAME@}0 hpm_xpi base_address size_bytes 0 0 $_TARGETNAME \
+ io_base opt0 opt1
+@end example
+
+@deffn {Command} {hpm_xpi mass_erase} bank_id
+Erase all pages in data memory for the bank identified by @option{bank_id}.
+@end deffn
+@end deffn
+
@anchor{jtagspi}
@deffn {Flash Driver} {jtagspi}
@cindex Generic JTAG2SPI driver
@@ -6592,6 +6789,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
@@ -6836,10 +7077,27 @@ All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from
Atmel include internal flash and use ARM's Cortex-M7 core.
This driver uses the same command names/syntax as @xref{at91sam3}.
+The same driver provides interface for PIC32CZ CA70 series. This
+Cortex-M7 family from Microchip is both binary and pin to pin compatible
+with Atmel's SAM series. The PIC series is a replacement of the original
+SAM series from Atmel after the company acquisition by Microchip.
+
@example
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},
@@ -6924,6 +7182,34 @@ flash erase_sector 0 0 last # It will perform a mass erase
Triggering a mass erase is also useful when users want to disable readout protection.
@end deffn
+@deffn {Flash Driver} {bl602}
+Supports RISC-V chips Bouffalo Lab BL602, BL702 and BL702L series.
+Both internal and external flashes are supported. The driver automatically
+recognizes the specific version's flash parameters and autoconfigures itself.
+Due to how the SFlash and XIP in those chips works, it is recommended to probe
+the flash before usage, and reset the chip after work with flash is finished.
+
+This driver does not generate boot header which is required to have working
+firmware. This header must be inside of ELF with proper Load Memory Address
+and other parts of firmware must have proper LMA based on boot header configuration.
+
+The @var{bl602} driver needs following parameters,
+which must appear in the following order:
+
+@itemize
+@item @var{chip_type} ... required, may be
+@option{bl602},
+@option{bl702},
+@option{bl702l}
+@end itemize
+
+Example:
+
+@example
+flash bank $_FLASHNAME bl602 0x23000000 0 0 0 $_TARGETNAME bl602
+@end example
+@end deffn
+
@deffn {Flash Driver} {cc26xx}
All versions of the SimpleLink CC13xx and CC26xx microcontrollers from Texas
Instruments include internal flash. The cc26xx flash driver supports both the
@@ -6951,25 +7237,25 @@ flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME
@end deffn
@deffn {Flash Driver} {efm32}
-All members of the EFM32/EFR32 microcontroller family from Energy Micro (now Silicon Labs)
-include internal flash and use Arm Cortex-M3 or Cortex-M4 cores. The driver automatically
-recognizes a number of these chips using the chip identification register, and
-autoconfigures itself.
+All members of the EFM32/EFR32 microcontroller family from Silicon Labs (former
+Energy Micro) include internal flash and use Arm Cortex-M3, Cortex-M4 or
+Cortex-M33 cores. The driver automatically recognizes a number of these chips
+using the chip identification register, and autoconfigures itself.
@example
-flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME
+flash bank $_FLASHNAME efm32 0x80000000 0 0 0 $_TARGETNAME
@end example
It supports writing to the user data page, as well as the portion of the lockbits page
-past 512 bytes on chips with larger page sizes. The latter is used by the SiLabs
-bootloader/AppLoader system for encryption keys. Setting protection on these pages is
-currently not supported.
+past 512 bytes on chips with larger page sizes. The latter is used by the
+Silicon Labs bootloader/AppLoader system for encryption keys. Setting protection
+on these pages is currently not supported.
@example
flash bank userdata.flash efm32 0x0FE00000 0 0 0 $_TARGETNAME
flash bank lockbits.flash efm32 0x0FE04000 0 0 0 $_TARGETNAME
@end example
-A special feature of efm32 controllers is that it is possible to completely disable the
-debug interface by writing the correct values to the 'Debug Lock Word'. OpenOCD supports
-this via the following command:
+A special feature of Silicon Labs Series 0/1 controllers is that it is possible
+to completely disable the debug interface by writing the correct values to the
+'Debug Lock Word'. OpenOCD supports this via the following command:
@example
efm32 debuglock num
@end example
@@ -8259,10 +8545,16 @@ data). This is the only way to unlock a protected flash (unless RDP
Level is 2 which can't be unlocked at all).
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
+
+@deffn {Command} {stm32lx option_load} num
+Forces a re-load of the option byte registers.
+This command will cause a system reset of the device.
+The @var{num} parameter is a value shown by @command{flash banks}.
+@end deffn
@end deffn
@deffn {Flash Driver} {stm32l4x}
-All members of the STM32 C0, G0, G4, L4, L4+, L5, U0, U5, WB and WL
+All members of the STM32 C0, G0, G4, L4, L4+, L5, U0, U5, WB, WBA and WL
microcontroller families from STMicroelectronics include internal flash
and use ARM Cortex-M0+, M4 and M33 cores.
The driver automatically recognizes a number of these chips using
@@ -8320,10 +8612,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
@@ -9262,7 +9552,12 @@ port is 6666.
@section Server Commands
@deffn {Command} {exit}
-Exits the current telnet session.
+Exits the current telnet or Tcl session but the OpenOCD process remains running.
+This command should only be used in telnet or Tcl sessions (and not directly
+in Tcl scripts).
+
+Note: To terminate the whole OpenOCD process, use the
+@command{shutdown} command instead.
@end deffn
@deffn {Command} {help} [string]
@@ -9312,16 +9607,18 @@ 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;
level 2 adds informational messages;
level 3 adds debugging messages;
-and level 4 adds verbose low-level debug messages.
+level 4 adds verbose low-level debug messages;
+and level 5 adds USB communication messages
+and amount of free heap space if mallinfo is available.
The default is level 2, but that can be overridden on
the command line along with the location of that log
file (which is normally the server's standard output).
@@ -9342,7 +9639,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
@@ -9735,12 +10032,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.)
@@ -9877,11 +10176,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
@@ -10223,24 +10522,6 @@ The target may later be resumed in the currently set core_state.
that is not currently supported in OpenOCD.)
@end deffn
-@deffn {Command} {arm disassemble} address [count [@option{thumb}]]
-@cindex disassemble
-Disassembles @var{count} instructions starting at @var{address}.
-If @var{count} is not specified, a single instruction is disassembled.
-If @option{thumb} is specified, or the low bit of the address is set,
-Thumb2 (mixed 16/32-bit) instructions are used;
-else ARM (32-bit) instructions are used.
-(Processors may also support the Jazelle state, but
-those instructions are not currently understood by OpenOCD.)
-
-Note that all Thumb instructions are Thumb2 instructions,
-so older processors (without Thumb2 support) will still
-see correct disassembly of Thumb code.
-Also, ThumbEE opcodes are the same as Thumb2,
-with a handful of exceptions.
-ThumbEE disassembly currently has no explicit support.
-@end deffn
-
@deffn {Command} {arm mcr} pX op1 CRn CRm op2 value
Write @var{value} to a coprocessor @var{pX} register
passing parameters @var{CRn},
@@ -10955,6 +11236,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.
@@ -11040,12 +11325,6 @@ target code relies on. In a configuration file, the command would typically be c
However, normally it is not necessary to use the command at all.
@end deffn
-@deffn {Command} {aarch64 disassemble} address [count]
-@cindex disassemble
-Disassembles @var{count} instructions starting at @var{address}.
-If @var{count} is not specified, a single instruction is disassembled.
-@end deffn
-
@deffn {Command} {aarch64 smp} [on|off]
Display, enable or disable SMP handling mode. The state of SMP handling influences the way targets in an SMP group
are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger
@@ -11645,7 +11924,7 @@ Display/set the current core displayed in GDB. This is needed only if
@code{riscv smp} was used.
@end deffn
-@deffn {Command} {riscv use_bscan_tunnel} width [type]
+@deffn {Config Command} {riscv use_bscan_tunnel} width [type]
Enable or disable use of a BSCAN tunnel to reach the Debug Module. Supply the
@var{width} of the DM transport TAP's instruction register to enable. The
@var{width} should fit into 7 bits. Supply a value of 0 to disable.
@@ -11669,7 +11948,7 @@ tunneled DR scan consists of:
@end enumerate
@end deffn
-@deffn {Command} {riscv set_bscan_tunnel_ir} value
+@deffn {Config Command} {riscv set_bscan_tunnel_ir} value
Allows the use_bscan_tunnel feature to target non Xilinx device by
specifying the JTAG TAP IR used to access the bscan tunnel.
@end deffn
@@ -12781,7 +13060,7 @@ If your device/vendor is not supported you have to use the first variant.
@end deffn
-@deffn {Command} {$hub_name ipdbg start} @option{-tool @var{number}} @option{-port @var{number}}
+@deffn {Command} {$hub_name start} @option{-tool @var{number}} @option{-port @var{number}}
Starts a IPDBG JTAG-Host server. The remaining arguments can be specified in any order.
Command options:
@@ -12791,7 +13070,7 @@ Command options:
@end itemize
@end deffn
-@deffn {Command} {$hub_name ipdbg stop} @option{-tool @var{number}}
+@deffn {Command} {$hub_name stop} @option{-tool @var{number}}
Stops a IPDBG JTAG-Host server.
Command options:
@itemize @bullet
@@ -12802,21 +13081,21 @@ Command options:
Examples:
@example
ipdbg create-hub xc6s.ipdbghub -tap xc6s.tap -hub 0x02
-xc6s.ipdbghub ipdbg start -port 4242 -tool 4
+xc6s.ipdbghub start -port 4242 -tool 4
@end example
Creates a IPDBG Hub and starts a server listening on tcp-port 4242 which connects to tool 4.
The connection is through the TAP of a Xilinx Spartan 6 on USER1 instruction (tested with a papillion pro board).
@example
ipdbg create-hub max10m50.ipdbghub -tap max10m50.tap -hub 0x00C -vir
-max10m50.ipdbghub ipdbg start -tool 1 -port 60000
+max10m50.ipdbghub start -tool 1 -port 60000
@end example
Starts a server listening on tcp-port 60000 which connects to tool 1 (data_up_1/data_down_1).
The connection is through the TAP of a Intel MAX10 virtual jtag component (sld_instance_index is 0; sld_ir_width is smaller than 5).
@example
ipdbg create-hub xc7.ipdbghub -pld xc7.pld
-xc7.ipdbghub ipdbg start -port 5555 -tool 0
+xc7.ipdbghub start -port 5555 -tool 0
@end example
Starts a server listening on tcp-port 5555 which connects to tool 0 (data_up_0/data_down_0).
The TAP and ir value used to reach the JTAG Hub is given by the pld driver.
@@ -13221,14 +13500,6 @@ contrib/rtos-helpers/FreeRTOS-openocd.c
contrib/rtos-helpers/uCOS-III-openocd.c
@end table
-@section RTOS Commands
-@cindex RTOS Commands
-
-@deffn {Config Command} {freertos_ticktype_size} (2|4|8)
-Pass the size (in bytes) of FreeRTOS TickType_t to OpenOCD. To make sure the
-calculation of offsets and sizes is correct. Defaults to 4.
-@end deffn
-
@anchor{usingopenocdsmpwithgdb}
@section Using OpenOCD SMP with GDB
@cindex SMP
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/git-hooks/commit-msg b/git-hooks/commit-msg
deleted file mode 100755
index 99d96cdd53..0000000000
--- a/git-hooks/commit-msg
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/bin/sh
-# From Gerrit Code Review 2.13.5
-#
-# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
-#
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-unset GREP_OPTIONS
-
-CHANGE_ID_AFTER="Bug|Issue|Test|Feature|Fixes|Fixed"
-MSG="$1"
-
-# Check for, and add if missing, a unique Change-Id
-#
-add_ChangeId() {
- clean_message=`sed -e '
- /^diff --git .*/{
- s///
- q
- }
- /^Signed-off-by:/d
- /^#/d
- ' "$MSG" | git stripspace`
- if test -z "$clean_message"
- then
- return
- fi
-
- # Do not add Change-Id to temp commits
- if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!'
- then
- return
- fi
-
- if test "false" = "`git config --bool --get gerrit.createChangeId`"
- then
- return
- fi
-
- # Does Change-Id: already exist? if so, exit (no change).
- if grep -i '^Change-Id:' "$MSG" >/dev/null
- then
- return
- fi
-
- id=`_gen_ChangeId`
- T="$MSG.tmp.$$"
- AWK=awk
- if [ -x /usr/xpg4/bin/awk ]; then
- # Solaris AWK is just too broken
- AWK=/usr/xpg4/bin/awk
- fi
-
- # Get core.commentChar from git config or use default symbol
- commentChar=`git config --get core.commentChar`
- commentChar=${commentChar:-#}
-
- # How this works:
- # - parse the commit message as (textLine+ blankLine*)*
- # - assume textLine+ to be a footer until proven otherwise
- # - exception: the first block is not footer (as it is the title)
- # - read textLine+ into a variable
- # - then count blankLines
- # - once the next textLine appears, print textLine+ blankLine* as these
- # aren't footer
- # - in END, the last textLine+ block is available for footer parsing
- $AWK '
- BEGIN {
- # while we start with the assumption that textLine+
- # is a footer, the first block is not.
- isFooter = 0
- footerComment = 0
- blankLines = 0
- }
-
- # Skip lines starting with commentChar without any spaces before it.
- /^'"$commentChar"'/ { next }
-
- # Skip the line starting with the diff command and everything after it,
- # up to the end of the file, assuming it is only patch data.
- # If more than one line before the diff was empty, strip all but one.
- /^diff --git / {
- blankLines = 0
- while (getline) { }
- next
- }
-
- # Count blank lines outside footer comments
- /^$/ && (footerComment == 0) {
- blankLines++
- next
- }
-
- # Catch footer comment
- /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
- footerComment = 1
- }
-
- /]$/ && (footerComment == 1) {
- footerComment = 2
- }
-
- # We have a non-blank line after blank lines. Handle this.
- (blankLines > 0) {
- print lines
- for (i = 0; i < blankLines; i++) {
- print ""
- }
-
- lines = ""
- blankLines = 0
- isFooter = 1
- footerComment = 0
- }
-
- # Detect that the current block is not the footer
- (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
- isFooter = 0
- }
-
- {
- # We need this information about the current last comment line
- if (footerComment == 2) {
- footerComment = 0
- }
- if (lines != "") {
- lines = lines "\n";
- }
- lines = lines $0
- }
-
- # Footer handling:
- # If the last block is considered a footer, splice in the Change-Id at the
- # right place.
- # Look for the right place to inject Change-Id by considering
- # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
- # then Change-Id, then everything else (eg. Signed-off-by:).
- #
- # Otherwise just print the last block, a new line and the Change-Id as a
- # block of its own.
- END {
- unprinted = 1
- if (isFooter == 0) {
- print lines "\n"
- lines = ""
- }
- changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
- numlines = split(lines, footer, "\n")
- for (line = 1; line <= numlines; line++) {
- if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
- unprinted = 0
- print "Change-Id: I'"$id"'"
- }
- print footer[line]
- }
- if (unprinted) {
- print "Change-Id: I'"$id"'"
- }
- }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T"
-}
-_gen_ChangeIdInput() {
- echo "tree `git write-tree`"
- if parent=`git rev-parse "HEAD^0" 2>/dev/null`
- then
- echo "parent $parent"
- fi
- echo "author `git var GIT_AUTHOR_IDENT`"
- echo "committer `git var GIT_COMMITTER_IDENT`"
- echo
- printf '%s' "$clean_message"
-}
-_gen_ChangeId() {
- _gen_ChangeIdInput |
- git hash-object -t commit --stdin
-}
-
-
-add_ChangeId
diff --git a/git-hooks/pre-push b/git-hooks/pre-push
deleted file mode 100755
index a7e126655e..0000000000
--- a/git-hooks/pre-push
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-./tools/checkpatch.sh
diff --git a/src/flash/nand/arm_io.c b/src/flash/nand/arm_io.c
index dd012e161a..8261c6386d 100644
--- a/src/flash/nand/arm_io.c
+++ b/src/flash/nand/arm_io.c
@@ -56,10 +56,8 @@ static int arm_code_to_working_area(struct target *target,
target_buffer_set_u32_array(target, code_buf, code_size / 4, code);
/* copy code to work area */
- retval = target_write_memory(target, (*area)->address,
+ return target_write_memory(target, (*area)->address,
4, code_size / 4, code_buf);
-
- return retval;
}
/**
@@ -282,7 +280,5 @@ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
destroy_reg_param(®_params[2]);
/* read from work area to the host's memory */
- retval = target_read_buffer(target, target_buf, size, data);
-
- return retval;
+ return target_read_buffer(target, target_buf, size, data);
}
diff --git a/src/flash/nand/at91sam9.c b/src/flash/nand/at91sam9.c
index 41cb07bc90..acc9e36348 100644
--- a/src/flash/nand/at91sam9.c
+++ b/src/flash/nand/at91sam9.c
@@ -250,15 +250,12 @@ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int
{
struct at91sam9_nand *info = nand->controller_priv;
struct arm_nand_data *io = &info->io;
- int status;
if (!at91sam9_halted(nand->target, "read block"))
return ERROR_NAND_OPERATION_FAILED;
io->chunk_size = nand->page_size;
- status = arm_nandread(io, data, size);
-
- return status;
+ return arm_nandread(io, data, size);
}
/**
@@ -274,15 +271,12 @@ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, in
{
struct at91sam9_nand *info = nand->controller_priv;
struct arm_nand_data *io = &info->io;
- int status;
if (!at91sam9_halted(nand->target, "write block"))
return ERROR_NAND_OPERATION_FAILED;
io->chunk_size = nand->page_size;
- status = arm_nandwrite(io, data, size);
-
- return status;
+ return arm_nandwrite(io, data, size);
}
/**
@@ -469,9 +463,7 @@ static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
return retval;
}
- retval = nand_write_finish(nand);
-
- return retval;
+ return nand_write_finish(nand);
}
/**
diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c
index c5430aeb05..6fe8d4023a 100644
--- a/src/flash/nand/core.c
+++ b/src/flash/nand/core.c
@@ -21,7 +21,7 @@ void nand_device_add(struct nand_device *c)
{
if (nand_devices) {
struct nand_device *p = nand_devices;
- while (p && p->next)
+ while (p->next)
p = p->next;
p->next = c;
} else
@@ -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/lpc3180.c b/src/flash/nand/lpc3180.c
index d221c34d9e..050c636645 100644
--- a/src/flash/nand/lpc3180.c
+++ b/src/flash/nand/lpc3180.c
@@ -88,7 +88,6 @@ static float lpc3180_cycle_time(struct nand_device *nand)
int sysclk;
int hclk;
int hclk_pll;
- float cycle;
/* calculate timings */
@@ -119,9 +118,7 @@ static float lpc3180_cycle_time(struct nand_device *nand)
LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);
- cycle = (1.0 / hclk) * 1000000.0;
-
- return cycle;
+ return (1.0 / hclk) * 1000000.0;
}
static int lpc3180_init(struct nand_device *nand)
diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c
index c67f2aa303..132a579d33 100644
--- a/src/flash/nand/lpc32xx.c
+++ b/src/flash/nand/lpc32xx.c
@@ -121,7 +121,6 @@ static float lpc32xx_cycle_time(struct nand_device *nand)
int sysclk;
int hclk;
int hclk_pll;
- float cycle;
int retval;
/* calculate timings */
@@ -169,9 +168,7 @@ static float lpc32xx_cycle_time(struct nand_device *nand)
LOG_DEBUG("LPC32xx HCLK currently clocked at %i kHz", hclk);
- cycle = (1.0 / hclk) * 1000000.0;
-
- return cycle;
+ return (1.0 / hclk) * 1000000.0;
}
static int lpc32xx_init(struct nand_device *nand)
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..5c4737f7ac 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 \
@@ -21,6 +22,7 @@ NOR_DRIVERS = \
%D%/atsamv.c \
%D%/atsame5.c \
%D%/avrf.c \
+ %D%/bl602.c \
%D%/bluenrg-x.c \
%D%/cc3220sf.c \
%D%/cc26xx.c \
@@ -58,6 +60,7 @@ NOR_DRIVERS = \
%D%/psoc5lp.c \
%D%/psoc6.c \
%D%/qn908x.c \
+ %D%/read_only.c \
%D%/renesas_rpchf.c \
%D%/rp2xxx.c \
%D%/rsl10.c \
@@ -82,9 +85,11 @@ NOR_DRIVERS = \
%D%/w600.c \
%D%/xcf.c \
%D%/xmc1xxx.c \
- %D%/xmc4xxx.c
+ %D%/xmc4xxx.c \
+ %D%/hpm_xpi.c
NORHEADERS = \
+ %D%/artery.h \
%D%/core.h \
%D%/cc3220sf.h \
%D%/bluenrg-x.h \
diff --git a/src/flash/nor/aducm360.c b/src/flash/nor/aducm360.c
index aa573acded..a5fd2cd249 100644
--- a/src/flash/nor/aducm360.c
+++ b/src/flash/nor/aducm360.c
@@ -440,7 +440,6 @@ static int aducm360_write_modified(struct flash_bank *bank,
uint32_t count)
{
uint32_t value;
- int res = ERROR_OK;
uint32_t i, j, a, d;
struct target *target = bank->target;
@@ -464,7 +463,7 @@ static int aducm360_write_modified(struct flash_bank *bank,
}
aducm360_set_write_enable(target, 0);
- return res;
+ return ERROR_OK;
}
/* ----------------------------------------------------------------------- */
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..2479505626 100644
--- a/src/flash/nor/at91sam3.c
+++ b/src/flash/nor/at91sam3.c
@@ -69,10 +69,7 @@
static float _tomhz(uint32_t freq_hz)
{
- float f;
-
- f = ((float)(freq_hz)) / 1000000.0;
- return f;
+ return ((float)freq_hz) / 1000000.0;
}
/* How the chip is configured. */
@@ -2040,40 +2037,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 +2567,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 +2679,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 +2710,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 +3007,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 +3570,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 +3637,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..a2d720cce4 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -64,10 +64,7 @@
static float _tomhz(uint32_t freq_hz)
{
- float f;
-
- f = ((float)(freq_hz)) / 1000000.0;
- return f;
+ return ((float)freq_hz) / 1000000.0;
}
/* How the chip is configured. */
@@ -1490,40 +1487,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 +1674,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 +2076,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 +2188,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 +2219,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 +2500,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 +3118,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 +3185,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..f6aff73b74 100644
--- a/src/flash/nor/at91sam4l.c
+++ b/src/flash/nor/at91sam4l.c
@@ -185,9 +185,7 @@ static int sam4l_flash_command(struct target *target, uint8_t cmd, int page)
if (err != 0)
LOG_ERROR("%s got error status 0x%08" PRIx32, __func__, err);
- res = sam4l_flash_wait_until_ready(target);
-
- return res;
+ return sam4l_flash_wait_until_ready(target);
}
FLASH_BANK_COMMAND_HANDLER(sam4l_flash_bank_command)
@@ -282,19 +280,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 */
@@ -505,9 +503,7 @@ static int sam4l_write_page(struct sam4l_info *chip, struct target *target,
res = sam4l_flash_command(target, SAM4L_FCMD_EP, -1);
if (res != ERROR_OK)
return res;
- res = sam4l_flash_command(target, SAM4L_FCMD_WP, -1);
-
- return res;
+ return sam4l_flash_command(target, SAM4L_FCMD_WP, -1);
}
/* Write partial contents into page-aligned 'address' on the Flash from host
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..20f9bedfdc 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,130 @@ 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)
+{
+ return samv_efc_read_sequence(target, SAMV_EFC_FCMD_STUS,
+ SAMV_EFC_FCMD_SPUS, buf, SAMV_PAGE_SIZE);
+}
+
+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 +683,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 +694,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 +709,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 +727,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 +735,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 +749,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 +763,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 +812,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 +903,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/bl602.c b/src/flash/nor/bl602.c
new file mode 100644
index 0000000000..63e15509c1
--- /dev/null
+++ b/src/flash/nor/bl602.c
@@ -0,0 +1,760 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2024 by Marek Kraus *
+ * gamelaster@gami.ee *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include
+#include
+#include "spi.h"
+#include "target/riscv/opcodes.h"
+#include "target/riscv/gdb_regs.h"
+
+/*
+ * Flash bank driver for Bouffalo chips with BL602-like flash controller
+ *
+ * Supported chips (series): BL602, BL702 and BL702L
+ * Not supported but compatible chips (series): BL616, BL606P and BL808
+ *
+ * SFlash supports both direct access and eXecute In Place (XIP) via L1 cache (L1C).
+ * If XIP is configured and direct access is needed,
+ * then the state needs to be saved and some settings need to be reset for it to work properly.
+ * The only way to do this is to save/restore the entire SFlash core configuration, which has not been tested.
+ * Because of this, on every OpenOCD flash probe, GPIO and SFlash will be reconfigured, resulting in XIP not working.
+ * So it's recommended to reset the device after every OpenOCD flash operation.
+ *
+ * QSPI write is not supported yet.
+ */
+
+// SFlash CFG definitions
+#define SFLASH_CFG_SIZE 84
+#define SFLASH_CFG_BUSY_BIT_POS 0x2D
+#define SFLASH_CFG_BUSY_INDEX_POS 0x2A
+#define SFLASH_CFG_BUSY_READ_REG_LEN_POS 0x33
+#define SFLASH_CFG_FAST_READ_CMD_POS 0x18
+#define SFLASH_CFG_JEDEC_ID_CMD_DMY_CLK_POS 0x09
+#define SFLASH_CFG_JEDEC_ID_CMD_POS 0x08
+#define SFLASH_CFG_PAGE_PROGRAM_CMD_POS 0x15
+#define SFLASH_CFG_PAGE_SIZE_POS 0x0E
+#define SFLASH_CFG_READ_STATUS_REG1_POS 0x34
+#define SFLASH_CFG_SECTOR_ERASE_CMD_POS 0x11
+#define SFLASH_CFG_SECTOR_SIZE_POS 0x0C
+#define SFLASH_CFG_TIME_ERASE_SECTOR_POS 0x48
+#define SFLASH_CFG_TIME_PAGE_PGM_POS 0x4E
+#define SFLASH_CFG_WRITE_ENABLE_BIT_POS 0x2B
+#define SFLASH_CFG_WRITE_ENABLE_CMD_POS 0x14
+#define SFLASH_CFG_WRITE_ENABLE_INDEX_POS 0x28
+#define SFLASH_CFG_WRITE_ENABLE_READ_REG_LEN_POS 0x2F
+
+#define BL602_DEFAULT_TIMEOUT_MS 5000
+
+enum bflb_series {
+ BFLB_SERIES_BL602,
+ BFLB_SERIES_BL702,
+ BFLB_SERIES_BL702L,
+};
+
+struct bl602_part_info {
+ uint32_t idcode;
+ enum bflb_series series;
+ uint32_t romapi_get_jedec_id;
+ uint32_t romapi_sflash_init_gpio;
+ uint32_t romapi_sflash_init;
+ uint32_t romapi_sflash_program;
+ uint32_t romapi_sflash_read;
+ uint32_t romapi_sflash_erase_sector;
+};
+
+struct bl602_flash_bank {
+ // flag indicating successful flash probe
+ bool probed;
+ enum bflb_series series;
+ const struct bl602_part_info *part_info;
+ uint8_t sflash_cfg[SFLASH_CFG_SIZE];
+ // detected model of SPI flash
+ const struct flash_device *dev;
+};
+
+static const struct bl602_part_info bl602_parts[] = {
+ {
+ .idcode = 0x20000c05,
+ .series = BFLB_SERIES_BL602,
+ .romapi_get_jedec_id = 0x210109bc,
+ .romapi_sflash_init_gpio = 0x21010a20,
+ .romapi_sflash_init = 0x21010980,
+ .romapi_sflash_program = 0x210109b4,
+ .romapi_sflash_read = 0x210109fc,
+ .romapi_sflash_erase_sector = 0x210109a4,
+ },
+ {
+ .idcode = 0x20000e05,
+ .series = BFLB_SERIES_BL702,
+ .romapi_get_jedec_id = 0x210189a4,
+ .romapi_sflash_init_gpio = 0x21018a78,
+ .romapi_sflash_init = 0x21018960,
+ .romapi_sflash_program = 0x2101899c,
+ .romapi_sflash_read = 0x210189d8,
+ .romapi_sflash_erase_sector = 0x2101898c,
+ },
+ {
+ .idcode = 0x20000e05,
+ .series = BFLB_SERIES_BL702L,
+ .romapi_get_jedec_id = 0x21010d10,
+ .romapi_sflash_init_gpio = 0x21010c54,
+ .romapi_sflash_init = 0x21010cc8,
+ .romapi_sflash_program = 0x21010d08,
+ .romapi_sflash_read = 0x21010d44,
+ .romapi_sflash_erase_sector = 0x21010cf8,
+ },
+};
+
+static int bl602_call_func(struct target *target, uint32_t func_addr,
+ uint32_t arg_data[], unsigned int n_args, uint32_t *return_data, unsigned int timeout_ms)
+{
+ static const char * const reg_names[] = { "a0", "a1", "a2", "a3", "a4", "a5" };
+ struct reg_param reg_params[ARRAY_SIZE(reg_names) + 1];
+ unsigned int n_reg_params = 0;
+
+ assert(n_args <= ARRAY_SIZE(reg_names)); // only allow register arguments
+
+ struct working_area *trampoline_algorithm;
+
+ uint32_t trampoline_code[] = {
+ ebreak(),
+ };
+
+ int retval = target_alloc_working_area(target, sizeof(trampoline_code),
+ &trampoline_algorithm);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No working area available, can't do trampoline");
+ return retval;
+ }
+
+ retval = target_write_buffer(target, trampoline_algorithm->address,
+ sizeof(trampoline_code), (uint8_t *)trampoline_code);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Writing trampoline code failed, can't do trampoline");
+ goto cleanup;
+ }
+
+ // initialize a0 register, which is used both as arg and also return register.
+ if (!return_data || n_args > 0) {
+ init_reg_param(®_params[0], reg_names[0], 32, PARAM_IN);
+ if (n_args > 0) {
+ buf_set_u32(reg_params[0].value, 0, 32, arg_data[0]);
+ reg_params[0].direction = PARAM_IN_OUT;
+ }
+ n_reg_params++;
+ }
+ // initialize rest of registers, if any
+ for (unsigned int i = 1; i < n_args; ++i) {
+ init_reg_param(®_params[i], reg_names[i], 32, PARAM_OUT);
+ buf_set_u32(reg_params[i].value, 0, 32, arg_data[i]);
+ n_reg_params++;
+ }
+ // set return address to the ebreak instruction in working area
+ init_reg_param(®_params[n_reg_params], "ra", 32, PARAM_OUT);
+ buf_set_u32(reg_params[n_reg_params].value, 0, 32, trampoline_algorithm->address);
+ n_reg_params++;
+
+ retval = target_run_algorithm(target,
+ 0, NULL,
+ n_reg_params, reg_params,
+ func_addr,
+ trampoline_algorithm->address,
+ timeout_ms, NULL);
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d",
+ trampoline_algorithm->address, retval);
+ goto cleanup;
+ }
+
+ if (return_data)
+ *return_data = buf_get_u32(reg_params[0].value, 0, 32);
+
+cleanup:
+ for (unsigned int i = 0; i < n_reg_params; i++)
+ destroy_reg_param(®_params[i]);
+
+ target_free_working_area(target, trampoline_algorithm);
+ return retval;
+}
+
+static int bl602_call_romapi_func(struct target *target, uint32_t romapi_func_addr,
+ uint32_t arg_data[], unsigned int n_args, uint32_t *return_data, unsigned int timeout_ms)
+{
+ uint32_t func_addr;
+
+ int retval = target_read_u32(target, romapi_func_addr, &func_addr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return bl602_call_func(target, func_addr, arg_data, n_args, return_data, timeout_ms);
+}
+
+static int bl602_alloc_bounce_buffer(struct flash_bank *bank,
+ struct working_area **working_area, uint32_t count)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ struct target *target = bank->target;
+
+ unsigned int avail_pages = target_get_working_area_avail(target) / priv->dev->pagesize;
+ if (avail_pages == 0) {
+ LOG_ERROR("Not enough space for bounce buffer. Can't continue");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ /* We try to allocate working area rounded down to device page size,
+ * at least 1 page, at most the write data size */
+ unsigned int chunk_size = MIN(MAX(avail_pages - 1, 1) * priv->dev->pagesize, count);
+ int retval = target_alloc_working_area(target, chunk_size, working_area);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not allocate bounce buffer for flash manipulation. Can't continue");
+ return retval;
+ }
+
+ LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, (*working_area)->address);
+
+ return ERROR_OK;
+}
+
+static int bl602_alloc_sflash_cfg(struct flash_bank *bank,
+ struct working_area **working_area)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ struct target *target = bank->target;
+
+ int retval = target_alloc_working_area(target, sizeof(priv->sflash_cfg),
+ working_area);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No working area available, can't alloc sflash cfg");
+ return retval;
+ }
+
+ retval = target_write_buffer(target, (*working_area)->address,
+ sizeof(priv->sflash_cfg), priv->sflash_cfg);
+ if (retval != ERROR_OK)
+ target_free_working_area(target, *working_area);
+ return retval;
+}
+
+static int bl602_flash_gpio_init(struct flash_bank *bank)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ struct target *target = bank->target;
+ const struct bl602_part_info *part_info = priv->part_info;
+
+ uint32_t flash_pin_cfg = 0;
+
+ // Read device info from eFuse
+ if (part_info->series == BFLB_SERIES_BL702 ||
+ part_info->series == BFLB_SERIES_BL702L) {
+ // Read device_info register
+ uint32_t device_info;
+ int retval = target_read_u32(target, 0x40007074, &device_info);
+ if (retval != ERROR_OK || device_info == 0x0) {
+ /* device_info being 0x0 shouldn't happen, since eFuse is loaded in BootROM,
+ * but better to handle it */
+ LOG_ERROR("Failed to read device info from eFuse");
+ return retval;
+ }
+
+ uint32_t flash_cfg = (device_info >> 26) & 0x03;
+ uint32_t sf_swap_cfg = (device_info >> 22) & 0x03;
+ uint32_t sf_reverse_cfg = (device_info >> 29) & 0x01; // BL702L only
+ if (part_info->series == BFLB_SERIES_BL702) {
+ flash_pin_cfg = (flash_cfg << 2) | sf_swap_cfg;
+ } else { // BL702L
+ flash_pin_cfg = sf_swap_cfg + (sf_reverse_cfg != 0 ? 5 : 1);
+ }
+ } else if (part_info->series == BFLB_SERIES_BL602) {
+ // Structure is not known.
+ uint32_t sw_usage;
+ int retval = target_read_u32(target, 0x40007010, &sw_usage);
+ if (retval != ERROR_OK || sw_usage == 0x0) {
+ /* sw_usage being 0x0 shouldn't happen, since eFuse is loaded in BootROM,
+ * but better to handle it */
+ LOG_ERROR("Failed to read sw usage from eFuse");
+ return retval;
+ }
+
+ // We only assume it is sf_swap_cfg
+ uint32_t sf_swap_cfg = (sw_usage >> 16) & 0x03;
+ flash_pin_cfg = sf_swap_cfg;
+ }
+
+ // initialize flash GPIOs
+ uint32_t args[] = {
+ flash_pin_cfg,
+ 1, // restoreDefault
+ };
+
+ int retval = bl602_call_romapi_func(target, part_info->romapi_sflash_init_gpio,
+ args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke spi flash gpio init function");
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static const uint8_t bl602_sflash_ctrl_cfg[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00
+};
+
+/* The structure of SF_Ctrl_Cfg_Type is same as on BL602 and BL702,
+ * but BL702L's BootROM was compiled without -fshort-enums flag.
+ * That caused that first three fields (enums) are 4 bytes instead of 1 byte. */
+static const uint8_t bl702l_sflash_ctrl_cfg[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0xe1, 0xfd, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x01, 0x21,
+};
+
+static int bl602_flash_init(struct flash_bank *bank)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ struct target *target = bank->target;
+ const struct bl602_part_info *part_info = priv->part_info;
+
+ int retval = bl602_flash_gpio_init(bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ // initialize SFlash peripheral
+ // structure for this can be found in official SDK by name SF_Ctrl_Cfg_Type
+ const uint8_t *sflash_ctrl_cfg = NULL;
+ uint16_t sflash_ctrl_cfg_size = 0;
+
+ switch (part_info->series) {
+ case BFLB_SERIES_BL602:
+ case BFLB_SERIES_BL702:
+ sflash_ctrl_cfg = bl602_sflash_ctrl_cfg;
+ sflash_ctrl_cfg_size = ARRAY_SIZE(bl602_sflash_ctrl_cfg);
+ break;
+ case BFLB_SERIES_BL702L:
+ sflash_ctrl_cfg = bl702l_sflash_ctrl_cfg;
+ sflash_ctrl_cfg_size = ARRAY_SIZE(bl702l_sflash_ctrl_cfg);
+ break;
+ default:
+ LOG_ERROR("No SFlash Control Config available for this chip");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+
+ struct working_area *sflash_ctrl_cfg_area;
+ retval = target_alloc_working_area(target, sflash_ctrl_cfg_size,
+ &sflash_ctrl_cfg_area);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("No working area available, can't init SFlash");
+ return retval;
+ }
+
+ retval = target_write_buffer(target, sflash_ctrl_cfg_area->address,
+ sflash_ctrl_cfg_size, sflash_ctrl_cfg);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write SFlash Control CFG into working area");
+ goto cleanup;
+ }
+
+ uint32_t args[] = {
+ sflash_ctrl_cfg_area->address,
+ };
+
+ retval = bl602_call_romapi_func(target, part_info->romapi_sflash_init,
+ args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke SFlash init function");
+ goto cleanup;
+ }
+
+cleanup:
+ target_free_working_area(target, sflash_ctrl_cfg_area);
+ return retval;
+}
+
+static int bl602_flash_read_id(struct flash_bank *bank, uint32_t *jedec_id)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ struct target *target = bank->target;
+ const struct bl602_part_info *part_info = priv->part_info;
+
+ struct working_area *data_area;
+ int retval = target_alloc_working_area(target, sizeof(uint32_t) + SFLASH_CFG_SIZE,
+ &data_area);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No working area available, can't read flash id");
+ return retval;
+ }
+
+ retval = target_write_buffer(target, data_area->address + sizeof(uint32_t),
+ SFLASH_CFG_SIZE, priv->sflash_cfg);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write data required for flash id read");
+ goto cleanup;
+ }
+
+ uint32_t args[2] = {
+ data_area->address + 4, // SFlash CFG
+ data_area->address, // JEDEC ID pointer
+ };
+
+ retval = bl602_call_romapi_func(target, part_info->romapi_get_jedec_id,
+ args, ARRAY_SIZE(args), NULL, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke get jedec id function");
+ goto cleanup;
+ }
+
+ retval = target_read_u32(target, data_area->address, jedec_id);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read flash id from target");
+ goto cleanup;
+ }
+
+ *jedec_id &= 0x00FFFFFF;
+
+cleanup:
+ target_free_working_area(target, data_area);
+
+ return retval;
+}
+
+static int bl602_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ const struct bl602_part_info *part_info = priv->part_info;
+ struct target *target = bank->target;
+ struct working_area *sflash_cfg_area = NULL;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area);
+ if (retval != ERROR_OK)
+ return retval;
+
+ uint32_t return_value;
+
+ for (unsigned int sector = first; sector <= last; sector++) {
+ LOG_INFO("Erasing sector %d", sector);
+ uint32_t args[] = {
+ sflash_cfg_area->address,
+ sector,
+ };
+ retval = bl602_call_romapi_func(target, part_info->romapi_sflash_erase_sector,
+ args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke flash erase code on target");
+ break;
+ }
+ if (return_value != 0) {
+ LOG_ERROR("Erase flash function returned wrong value: %02X", return_value);
+ retval = ERROR_FAIL;
+ break;
+ }
+ }
+
+ target_free_working_area(target, sflash_cfg_area);
+ return retval;
+}
+
+static int bl602_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ const struct bl602_part_info *part_info = priv->part_info;
+ struct target *target = bank->target;
+ struct working_area *bounce_area = NULL;
+ struct working_area *sflash_cfg_area = NULL;
+
+ LOG_DEBUG("bank->size=0x%x offset=0x%08" PRIx32 " count=0x%08" PRIx32,
+ bank->size, offset, count);
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > priv->dev->size_in_bytes) {
+ LOG_WARNING("Write past end of flash. Extra data discarded");
+ count = priv->dev->size_in_bytes - offset;
+ }
+
+ int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = bl602_alloc_bounce_buffer(bank, &bounce_area, count);
+ if (retval != ERROR_OK)
+ goto cleanup;
+
+ unsigned int chunk_size = bounce_area->size;
+ uint32_t return_value;
+
+ while (count > 0) {
+ uint32_t write_size = count > chunk_size ? chunk_size : count;
+ LOG_INFO("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
+ retval = target_write_buffer(target, bounce_area->address, write_size, buffer);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not load data into target bounce buffer");
+ goto cleanup;
+ }
+ uint32_t args[] = {
+ sflash_cfg_area->address,
+ 0x0, // io_mode
+ offset,
+ bounce_area->address,
+ write_size,
+ };
+ retval = bl602_call_romapi_func(target, part_info->romapi_sflash_program,
+ args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke flash programming code on target");
+ goto cleanup;
+ }
+ if (return_value != 0) {
+ LOG_ERROR("Write flash function returned wrong value: %02X", return_value);
+ retval = ERROR_FAIL;
+ goto cleanup;
+ }
+
+ buffer += write_size;
+ offset += write_size;
+ count -= write_size;
+ }
+
+
+cleanup:
+ target_free_working_area(target, bounce_area);
+ target_free_working_area(target, sflash_cfg_area);
+ return retval;
+}
+
+static int bl602_read(struct flash_bank *bank,
+ uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+ const struct bl602_part_info *part_info = priv->part_info;
+ struct target *target = bank->target;
+ struct working_area *bounce_area = NULL;
+ struct working_area *sflash_cfg_area = NULL;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > priv->dev->size_in_bytes) {
+ LOG_WARNING("Read past end of flash");
+ count = priv->dev->size_in_bytes - offset;
+ }
+
+ int retval = bl602_alloc_sflash_cfg(bank, &sflash_cfg_area);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = bl602_alloc_bounce_buffer(bank, &bounce_area, count);
+ if (retval != ERROR_OK)
+ goto cleanup;
+
+ unsigned int chunk_size = bounce_area->size;
+
+ while (count > 0) {
+ uint32_t read_size = count > chunk_size ? chunk_size : count;
+ LOG_DEBUG("Read %d bytes from offset 0x%" PRIx32, read_size, offset);
+ uint32_t args[] = {
+ sflash_cfg_area->address,
+ 0x0, // io_mode
+ false, // continous_read
+ offset,
+ bounce_area->address,
+ read_size,
+ };
+ uint32_t return_value;
+ retval = bl602_call_romapi_func(target, part_info->romapi_sflash_read,
+ args, ARRAY_SIZE(args), &return_value, BL602_DEFAULT_TIMEOUT_MS);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to invoke flash read code on target");
+ break;
+ }
+ if (return_value != 0) {
+ LOG_ERROR("Read flash function returned wrong value: %02X", return_value);
+ retval = ERROR_FAIL;
+ break;
+ }
+
+ retval = target_read_buffer(target, bounce_area->address, read_size, buffer);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not load data from target bounce buffer");
+ break;
+ }
+
+ buffer += read_size;
+ offset += read_size;
+ count -= read_size;
+ }
+
+cleanup:
+ target_free_working_area(target, bounce_area);
+ target_free_working_area(target, sflash_cfg_area);
+
+ return retval;
+}
+
+static int bl602_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct bl602_flash_bank *priv = bank->driver_priv;
+
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_TARGET_NOT_EXAMINED;
+ }
+
+ priv->probed = false;
+
+ for (unsigned int n = 0; n < ARRAY_SIZE(bl602_parts); n++) {
+ const struct bl602_part_info *part_info = &bl602_parts[n];
+ if (priv->series == part_info->series) {
+ if (target->tap->idcode != part_info->idcode) {
+ LOG_ERROR("TAP IDCODE is not valid for selected chip type");
+ return ERROR_FAIL;
+ }
+ priv->part_info = part_info;
+ break;
+ }
+ }
+
+ if (!priv->part_info) {
+ LOG_ERROR("Cannot identify target as an BL602 family device");
+ return ERROR_FAIL;
+ }
+
+ int retval = bl602_flash_init(bank);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Initialization of flash failed");
+ return retval;
+ }
+
+ uint32_t jedec_id;
+ retval = bl602_flash_read_id(bank, &jedec_id);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Cannot identify flash JEDEC ID");
+ return retval;
+ }
+
+ priv->dev = NULL;
+ for (const struct flash_device *p = flash_devices; p->name ; p++) {
+ if (p->device_id == jedec_id) {
+ priv->dev = p;
+ break;
+ }
+ }
+
+ if (!priv->dev) {
+ LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", jedec_id);
+ return ERROR_FAIL;
+ }
+ LOG_INFO("Found flash device '%s' (ID 0x%08" PRIx32 ")", priv->dev->name,
+ priv->dev->device_id);
+
+ // set correct size value
+ bank->size = priv->dev->size_in_bytes;
+ bank->num_sectors = bank->size / priv->dev->sectorsize;
+ bank->write_start_alignment = 8;
+ bank->write_end_alignment = 8;
+
+ bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
+ if (!bank->sectors)
+ return ERROR_FAIL;
+
+ priv->sflash_cfg[SFLASH_CFG_PAGE_PROGRAM_CMD_POS] = priv->dev->pprog_cmd;
+ priv->sflash_cfg[SFLASH_CFG_PAGE_SIZE_POS] = priv->dev->pagesize & 0xFF;
+ priv->sflash_cfg[SFLASH_CFG_PAGE_SIZE_POS + 1] = (priv->dev->pagesize >> 8) & 0xFF;
+ priv->sflash_cfg[SFLASH_CFG_FAST_READ_CMD_POS] = priv->dev->read_cmd;
+ priv->sflash_cfg[SFLASH_CFG_SECTOR_SIZE_POS] = priv->dev->sectorsize / 1024;
+ priv->sflash_cfg[SFLASH_CFG_SECTOR_ERASE_CMD_POS] = priv->dev->erase_cmd;
+
+ priv->probed = true;
+
+ return retval;
+}
+
+static int bl602_auto_probe(struct flash_bank *bank)
+{
+ struct bl602_flash_bank *priv = bank->driver_priv;
+
+ if (priv->probed)
+ return ERROR_OK;
+
+ return bl602_probe(bank);
+}
+
+/*
+ * flash bank bl602 0 0 0
+ */
+FLASH_BANK_COMMAND_HANDLER(bl602_flash_bank_command)
+{
+ if (CMD_ARGC < 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct bl602_flash_bank *priv;
+ priv = malloc(sizeof(struct bl602_flash_bank));
+ priv->probed = false;
+ priv->part_info = NULL;
+
+ if (strcmp(CMD_ARGV[6], "bl602") == 0) {
+ priv->series = BFLB_SERIES_BL602;
+ } else if (strcmp(CMD_ARGV[6], "bl702") == 0) {
+ priv->series = BFLB_SERIES_BL702;
+ } else if (strcmp(CMD_ARGV[6], "bl702l") == 0) {
+ priv->series = BFLB_SERIES_BL702L;
+ } else {
+ LOG_ERROR("Unknown BL602 chip type: %s", CMD_ARGV[6]);
+ free(priv);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ // initialize default sflash_cfg fields
+ priv->sflash_cfg[SFLASH_CFG_JEDEC_ID_CMD_POS] = 0x9F;
+ priv->sflash_cfg[SFLASH_CFG_JEDEC_ID_CMD_DMY_CLK_POS] = 0x0;
+ priv->sflash_cfg[SFLASH_CFG_TIME_PAGE_PGM_POS] = 200;
+ priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_CMD_POS] = 0x06;
+ priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_INDEX_POS] = 0;
+ priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_READ_REG_LEN_POS] = 1;
+ priv->sflash_cfg[SFLASH_CFG_WRITE_ENABLE_BIT_POS] = 1;
+ priv->sflash_cfg[SFLASH_CFG_READ_STATUS_REG1_POS] = 0x05;
+ priv->sflash_cfg[SFLASH_CFG_BUSY_INDEX_POS] = 0;
+ priv->sflash_cfg[SFLASH_CFG_BUSY_READ_REG_LEN_POS] = 1;
+ priv->sflash_cfg[SFLASH_CFG_BUSY_BIT_POS] = 0;
+ priv->sflash_cfg[SFLASH_CFG_TIME_ERASE_SECTOR_POS] = 1000 & 0xFF;
+ priv->sflash_cfg[SFLASH_CFG_TIME_ERASE_SECTOR_POS + 1] = (1000 >> 8) & 0xFF;
+
+ // set up driver_priv
+ bank->driver_priv = priv;
+
+ return ERROR_OK;
+}
+
+const struct flash_driver bl602_flash = {
+ .name = "bl602",
+ .flash_bank_command = bl602_flash_bank_command,
+ .erase = bl602_erase,
+ .write = bl602_write,
+ .read = bl602_read,
+ .probe = bl602_probe,
+ .auto_probe = bl602_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .free_driver_priv = default_flash_free_driver_priv
+};
diff --git a/src/flash/nor/bluenrg-x.c b/src/flash/nor/bluenrg-x.c
index 9ced2e9718..7bc8ce35c7 100644
--- a/src/flash/nor/bluenrg-x.c
+++ b/src/flash/nor/bluenrg-x.c
@@ -11,6 +11,7 @@
#include
#include "helper/types.h"
+#include "helper/align.h"
#include
#include
#include
@@ -19,6 +20,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 +65,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 +75,27 @@ 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)",
+};
+
+static const struct flash_ctrl_priv_data flash_priv_data_spirit3 = {
+ .die_id_reg = 0x40000000,
+ .jtag_idcode_reg = 0x40000004,
+ .flash_base = 0x10040000,
+ .flash_regs_base = 0x40001000,
+ .flash_page_size = 2048,
+ .jtag_idcode = 0x02027041,
+ .part_name = "STM32WL33/WL3R (SPIRIT3/3R)",
};
struct bluenrgx_flash_bank {
@@ -86,7 +108,10 @@ 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_priv_data_spirit3
+};
/* flash_bank bluenrg-x 0 0 0 0 */
FLASH_BANK_COMMAND_HANDLER(bluenrgx_flash_bank_command)
@@ -130,8 +155,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 +235,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 +260,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,12 +269,12 @@ 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;
struct target *target = bank->target;
- uint32_t buffer_size = 16384 + 8;
+ uint32_t max_buffer_size = 16384 + 8;
struct working_area *write_algorithm;
struct working_area *write_algorithm_stack;
struct working_area *source;
@@ -251,22 +291,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");
@@ -279,6 +303,23 @@ static int bluenrgx_write(struct flash_bank *bank, const uint8_t *buffer,
if (retval != ERROR_OK)
return retval;
+ /* Compute usable buffer size by excluding 128 bytes for write_algorithm_stack
+ * and 8 bytes for read and write pointers.
+ */
+ uint32_t buffer_size = target_get_working_area_avail(target) - 128 - 8;
+ /* buffer size should be multiple of FLASH_DATA_WIDTH*/
+ buffer_size = ALIGN_DOWN(buffer_size, FLASH_DATA_WIDTH);
+ buffer_size += 8;
+
+ if (buffer_size < 256) {
+ LOG_WARNING("large enough working area not available, can't do block memory writes");
+ target_free_working_area(target, write_algorithm);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ } else if (buffer_size > max_buffer_size) {
+ /* probably won't benefit from more than 16k ... */
+ buffer_size = max_buffer_size;
+ }
+
/* memory buffer */
if (target_alloc_working_area(target, buffer_size, &source)) {
LOG_WARNING("no large enough working area available");
@@ -302,10 +343,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 +394,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 +406,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 +421,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 +504,9 @@ 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
+ && idcode != flash_priv_data_spirit3.jtag_idcode) {
retval = target_read_u32(bank->target, BLUENRG2_JTAG_REG, &idcode);
if (retval != ERROR_OK)
return retval;
@@ -414,7 +533,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++) {
@@ -474,4 +593,5 @@ const struct flash_driver bluenrgx_flash = {
.protect_check = NULL,
.auto_probe = bluenrgx_auto_probe,
.info = bluenrgx_get_info,
+ .free_driver_priv = default_flash_free_driver_priv,
};
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/core.c b/src/flash/nor/core.c
index 5c4f2accaf..2c41d18530 100644
--- a/src/flash/nor/core.c
+++ b/src/flash/nor/core.c
@@ -44,6 +44,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
int retval;
unsigned int num_blocks;
+ if (!bank->driver->protect) {
+ LOG_ERROR("Flash protection is not supported");
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
if (bank->num_prot_blocks)
num_blocks = bank->num_prot_blocks;
else
@@ -59,11 +64,6 @@ int flash_driver_protect(struct flash_bank *bank, int set, unsigned int first,
/* force "set" to 0/1 */
set = !!set;
- if (!bank->driver->protect) {
- LOG_ERROR("Flash protection is not supported.");
- return ERROR_FLASH_OPER_UNSUPPORTED;
- }
-
/* DANGER!
*
* We must not use any cached information about protection state!!!!
@@ -223,15 +223,8 @@ void flash_free_all_banks(void)
else
LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name);
- /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from
- * master flash_bank structure. They point to memory locations allocated by master flash driver
- * so master driver is responsible for releasing them.
- * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */
-
- if (strcmp(bank->driver->name, "virtual") != 0) {
- free(bank->sectors);
- free(bank->prot_blocks);
- }
+ free(bank->sectors);
+ free(bank->prot_blocks);
free(bank->name);
free(bank);
@@ -343,6 +336,10 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
}
uint8_t *buffer = malloc(buffer_size);
+ if (!buffer) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
for (unsigned int i = 0; i < bank->num_sectors; i++) {
uint32_t j;
@@ -389,8 +386,10 @@ int default_flash_blank_check(struct flash_bank *bank)
struct target_memory_check_block *block_array;
block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
- if (!block_array)
+ if (!block_array) {
+ LOG_WARNING("Running slow fallback erase check - limited host memory available");
return default_flash_mem_blank_check(bank);
+ }
for (unsigned int i = 0; i < bank->num_sectors; i++) {
block_array[i].address = bank->base + bank->sectors[i].offset;
@@ -400,17 +399,18 @@ int default_flash_blank_check(struct flash_bank *bank)
bool fast_check = true;
for (unsigned int i = 0; i < bank->num_sectors; ) {
+ unsigned int checked;
retval = target_blank_check_memory(target,
block_array + i, bank->num_sectors - i,
- bank->erased_value);
- if (retval < 1) {
+ bank->erased_value, &checked);
+ if (retval != ERROR_OK) {
/* Run slow fallback if the first run gives no result
* otherwise use possibly incomplete results */
if (i == 0)
fast_check = false;
break;
}
- i += retval; /* add number of blocks done this round */
+ i += checked; /* add number of blocks done this round */
}
if (fast_check) {
@@ -419,9 +419,9 @@ int default_flash_blank_check(struct flash_bank *bank)
retval = ERROR_OK;
} else {
if (retval == ERROR_NOT_IMPLEMENTED)
- LOG_USER("Running slow fallback erase check");
+ LOG_DEBUG("Running slow fallback erase check");
else
- LOG_USER("Running slow fallback erase check - add working memory");
+ LOG_WARNING("Running slow fallback erase check - add working memory");
retval = default_flash_mem_blank_check(bank);
}
@@ -735,11 +735,25 @@ int flash_write_unlock_verify(struct target *target, struct image *image,
unsigned int section;
uint32_t section_offset;
struct flash_bank *c;
- int *padding;
section = 0;
section_offset = 0;
+ /* allocate padding array */
+ int *padding = calloc(image->num_sections, sizeof(*padding));
+
+ /* This fn requires all sections to be in ascending order of addresses,
+ * whereas an image can have sections out of order. */
+ struct imagesection **sections = malloc(sizeof(struct imagesection *) *
+ image->num_sections);
+
+ if (!padding || !sections) {
+ LOG_ERROR("Out of memory");
+ free(padding);
+ free(sections);
+ return ERROR_FAIL;
+ }
+
if (written)
*written = 0;
@@ -750,14 +764,6 @@ int flash_write_unlock_verify(struct target *target, struct image *image,
flash_set_dirty();
}
- /* allocate padding array */
- padding = calloc(image->num_sections, sizeof(*padding));
-
- /* This fn requires all sections to be in ascending order of addresses,
- * whereas an image can have sections out of order. */
- struct imagesection **sections = malloc(sizeof(struct imagesection *) *
- image->num_sections);
-
for (unsigned int i = 0; i < image->num_sections; i++)
sections[i] = &image->sections[i];
diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h
index f8cf5e2698..55ea3c7e5b 100644
--- a/src/flash/nor/core.h
+++ b/src/flash/nor/core.h
@@ -84,6 +84,8 @@ struct flash_bank {
target_addr_t base; /**< The base address of this bank */
uint32_t size; /**< The size of this chip bank, in bytes */
+ bool read_only; /**< a ROM region - mainly to list in gdb memory map */
+
unsigned int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
unsigned int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 3b57ef9ff0..afb73a3fb2 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;
@@ -249,6 +251,7 @@ extern const struct flash_driver ath79_flash;
extern const struct flash_driver atsame5_flash;
extern const struct flash_driver atsamv_flash;
extern const struct flash_driver avr_flash;
+extern const struct flash_driver bl602_flash;
extern const struct flash_driver bluenrgx_flash;
extern const struct flash_driver cc26xx_flash;
extern const struct flash_driver cc3220sf_flash;
@@ -263,6 +266,7 @@ extern const struct flash_driver faux_flash;
extern const struct flash_driver fespi_flash;
extern const struct flash_driver fm3_flash;
extern const struct flash_driver fm4_flash;
+extern const struct flash_driver hpm_xpi_flash;
extern const struct flash_driver jtagspi_flash;
extern const struct flash_driver kinetis_flash;
extern const struct flash_driver kinetis_ke_flash;
@@ -288,7 +292,9 @@ extern const struct flash_driver psoc5lp_flash;
extern const struct flash_driver psoc5lp_nvl_flash;
extern const struct flash_driver psoc6_flash;
extern const struct flash_driver qn908x_flash;
+extern const struct flash_driver read_only_flash;
extern const struct flash_driver renesas_rpchf_flash;
+extern const struct flash_driver ro_alias_flash;
extern const struct flash_driver rp2xxx_flash;
extern const struct flash_driver rsl10_flash;
extern const struct flash_driver sh_qspi_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 3770bfbd3c..094b5a76ba 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,
@@ -26,9 +30,10 @@ static const struct flash_driver * const flash_drivers[] = {
&atsame5_flash,
&atsamv_flash,
&avr_flash,
+ &bl602_flash,
&bluenrgx_flash,
- &cc3220sf_flash,
&cc26xx_flash,
+ &cc3220sf_flash,
&cfi_flash,
&dsp5680xx_flash,
&dw_spi_flash,
@@ -37,9 +42,10 @@ static const struct flash_driver * const flash_drivers[] = {
&eneispif_flash,
&esirisc_flash,
&faux_flash,
+ &fespi_flash,
&fm3_flash,
&fm4_flash,
- &fespi_flash,
+ &hpm_xpi_flash,
&jtagspi_flash,
&kinetis_flash,
&kinetis_ke_flash,
@@ -54,46 +60,47 @@ 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,
+ &read_only_flash,
+ &ro_alias_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..9f5f1b111e 100644
--- a/src/flash/nor/efm32.c
+++ b/src/flash/nor/efm32.c
@@ -16,8 +16,17 @@
* Copyright (C) 2014 Nemui Trinomius *
* nemuisan_kawausogasuki@live.jp *
* *
+ * Copyright (C) 2021 Michael Teichgräber *
+ * mteichgraeber@gmx.de *
+ * *
* Copyright (C) 2021 Doug Brunner *
* doug.a.brunner@gmail.com *
+ * *
+ * Copyright (C) 2022 Mikrodust AB *
+ * henrik.persson@mikrodust.com *
+ * *
+ * Copyright (c) 2026 Silicon Laboratories Inc. *
+ * jerome.pouiller@silabs.com *
***************************************************************************/
#ifdef HAVE_CONFIG_H
@@ -26,57 +35,143 @@
#include "imp.h"
#include
+#include
#include
#include
#include
-#define EFM_FAMILY_ID_GIANT_GECKO 72
-#define EFM_FAMILY_ID_LEOPARD_GECKO 74
-
-#define EFM32_FLASH_ERASE_TMO 100
-#define EFM32_FLASH_WDATAREADY_TMO 100
-#define EFM32_FLASH_WRITE_TMO 100
+/* Datasheet specifies ~22ms for page erase on first chip generation. 100ms
+ * provides reasonable margin.
+ */
+#define EFM32_FLASH_OPERATION_TIMEOUT 100
-#define EFM32_FLASH_BASE 0
+#define EFM32_FLASH_BASE_V1 0x00000000
+#define EFM32_FLASH_BASE_V2 0x08000000
/* size in bytes, not words; must fit all Gecko devices */
-#define LOCKWORDS_SZ 512
+#define LOCKWORDS_SZ 512
#define EFM32_MSC_INFO_BASE 0x0fe00000
+#define EFM32_MSC_USER_DATA (EFM32_MSC_INFO_BASE + 0x0000)
+#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE + 0x4000)
+#define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_INFO_BASE + 0x4200)
+
+struct efm32_dev_info_addr {
+ target_addr_t part_num;
+ target_addr_t part_rev;
+#define EFM32_DI_PARTINFO_NUM_MASK 0x0000ffff
+#define EFM32_DI_PARTINFO_FAMILY_MASK 0x00ff0000
+#define EFM32_DI_PARTINFO_TYPE_MASK 0x3f000000
+ target_addr_t part_info;
+#define EFM32_DI_PARTINFO_PAGE_SZ_MASK 0x000000ff
+#define EFM32_DI_PARTINFO_PAGE_SZ_UD_MASK 0x0000ff00
+ target_addr_t page_size;
+ target_addr_t flash_sz;
+ target_addr_t ram_sz;
+};
+
+#define EFM32_DI_PART_FAMILY (EFM32_MSC_INFO_BASE + 0x81fe)
+
+static const struct efm32_dev_info_addr efm32_dev_info_addr[] = {
+ [0] = {
+ .part_num = EFM32_MSC_INFO_BASE + 0x81fc,
+ .part_rev = EFM32_MSC_INFO_BASE + 0x81ff,
+ .part_info = 0x00000000, // Not used in Series 0/1
+ .page_size = EFM32_MSC_INFO_BASE + 0x81e7,
+ .flash_sz = EFM32_MSC_INFO_BASE + 0x81f8,
+ .ram_sz = EFM32_MSC_INFO_BASE + 0x81fa,
+ },
+ [1] = {
+ .part_num = EFM32_MSC_INFO_BASE + 0x81fc,
+ .part_rev = EFM32_MSC_INFO_BASE + 0x81ff,
+ .part_info = 0x0000000, // Not used in Series 0/1
+ .page_size = EFM32_MSC_INFO_BASE + 0x81e7,
+ .flash_sz = EFM32_MSC_INFO_BASE + 0x81f8,
+ .ram_sz = EFM32_MSC_INFO_BASE + 0x81fa,
+ },
+ [2] = {
+ .part_num = 0x00000000, // Not used in Series 2
+ .part_rev = EFM32_MSC_INFO_BASE + 0x8002,
+ .part_info = EFM32_MSC_INFO_BASE + 0x8004,
+ .page_size = EFM32_MSC_INFO_BASE + 0x8008,
+ .flash_sz = EFM32_MSC_INFO_BASE + 0x800c,
+ .ram_sz = EFM32_MSC_INFO_BASE + 0x800e,
+ },
+};
+
+// Offsets relative to msc_regbase
+struct efm32_msc_offset {
+#define EFM32_MSC_WRITECTRL_WREN_MASK 0x0001
+ target_addr_t off_writectrl;
+
+#define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x0001
+#define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x0002
+#define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x0008
+ target_addr_t off_writecmd;
+ target_addr_t off_addrb;
+ target_addr_t off_wdata;
+ target_addr_t off_userdatasize;
+
+#define EFM32_MSC_STATUS_BUSY_MASK 0x0001
+#define EFM32_MSC_STATUS_LOCKED_MASK 0x0002
+#define EFM32_MSC_STATUS_INVADDR_MASK 0x0004
+#define EFM32_MSC_STATUS_WDATAREADY_MASK 0x0008
+ target_addr_t off_status;
+
+#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
+ target_addr_t off_lock;
+
+ const uint8_t *flash_write_code;
+ size_t flash_write_code_len;
+};
+
+// see contrib/loaders/flash/efm32.S for source
+static const uint8_t efm32_flash_write_code_s0_s1[] = {
+#include "../../../contrib/loaders/flash/silabs/silabs_s0_s1.inc"
+};
+
+static const uint8_t efm32_flash_write_code_s2[] = {
+#include "../../../contrib/loaders/flash/silabs/silabs_s2.inc"
+};
+
+static const struct efm32_msc_offset efm32_msc_offset[] = {
+ [0] = {
+ .off_writectrl = 0x0008,
+ .off_writecmd = 0x000c,
+ .off_addrb = 0x0010,
+ .off_wdata = 0x0018,
+ .off_status = 0x001c,
+ .off_lock = 0x003c,
+ .off_userdatasize = 0x0000, // Does not exist in Series 0/1
+ .flash_write_code = efm32_flash_write_code_s0_s1,
+ .flash_write_code_len = sizeof(efm32_flash_write_code_s0_s1),
+ },
+ [1] = {
+ .off_writectrl = 0x0008,
+ .off_writecmd = 0x000c,
+ .off_addrb = 0x0010,
+ .off_wdata = 0x0018,
+ .off_status = 0x001c,
+ .off_lock = 0x0040,
+ .off_userdatasize = 0x0000, // Does not exist in Series 0/1
+ .flash_write_code = efm32_flash_write_code_s0_s1,
+ .flash_write_code_len = sizeof(efm32_flash_write_code_s0_s1),
+ },
+ [2] = {
+ .off_writectrl = 0x000c,
+ .off_writecmd = 0x0010,
+ .off_addrb = 0x0014,
+ .off_wdata = 0x0018,
+ .off_status = 0x001c,
+ .off_lock = 0x003c,
+ .off_userdatasize = 0x0034,
+ .flash_write_code = efm32_flash_write_code_s2,
+ .flash_write_code_len = sizeof(efm32_flash_write_code_s2),
+ },
+};
-#define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE
-#define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000)
-#define EFM32_MSC_LOCK_BITS_EXTRA (EFM32_MSC_LOCK_BITS+LOCKWORDS_SZ)
-#define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000)
-
-/* PAGE_SIZE is not present in Zero, Happy and the original Gecko MCU */
-#define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7)
-#define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8)
-#define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa)
-#define EFM32_MSC_DI_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc)
-#define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe)
-#define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff)
-
-#define EFM32_MSC_REGBASE 0x400c0000
-#define EFM32_MSC_REGBASE_SERIES1 0x400e0000
-#define EFM32_MSC_REG_WRITECTRL 0x008
-#define EFM32_MSC_WRITECTRL_WREN_MASK 0x1
-#define EFM32_MSC_REG_WRITECMD 0x00c
-#define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1
-#define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2
-#define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8
-#define EFM32_MSC_REG_ADDRB 0x010
-#define EFM32_MSC_REG_WDATA 0x018
-#define EFM32_MSC_REG_STATUS 0x01c
-#define EFM32_MSC_STATUS_BUSY_MASK 0x1
-#define EFM32_MSC_STATUS_LOCKED_MASK 0x2
-#define EFM32_MSC_STATUS_INVADDR_MASK 0x4
-#define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8
-#define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10
-#define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20
-#define EFM32_MSC_REG_LOCK 0x03c
-#define EFM32_MSC_REG_LOCK_SERIES1 0x040
-#define EFM32_MSC_LOCK_LOCKKEY 0x1b71
+// Series 2 only
+#define EFM32_CMU_REG_CLKEN1_SET 0x50009068
enum efm32_bank_index {
EFM32_BANK_INDEX_MAIN,
@@ -85,316 +180,345 @@ enum efm32_bank_index {
EFM32_N_BANKS
};
-static int efm32x_get_bank_index(target_addr_t base)
+static int efm32_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_V1:
+ case EFM32_FLASH_BASE_V2:
+ 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;
}
}
struct efm32_family_data {
- int family_id;
- const char *name;
-
- /* EFM32 series (EFM32LG995F is the "old" series 0, while EFR32MG12P132
- is the "new" series 1). Determines location of MSC registers. */
+ uint8_t part_id;
int series;
+ const char *name;
+ uint32_t msc_regbase;
- /* Page size in bytes, or 0 to read from EFM32_MSC_DI_PAGE_SIZE */
+ // Page size in bytes, or 0 to read from msc_di->page_size
int page_size;
-
- /* MSC register base address, or 0 to use default */
- uint32_t msc_regbase;
};
struct efm32_info {
const struct efm32_family_data *family_data;
+ const struct efm32_dev_info_addr *di_addr;
+ const struct efm32_msc_offset *msc_offset;
+ uint16_t part_num; // Series 0/1 only
+ uint32_t part_info; // Series 2 only
+ uint8_t part_rev;
uint16_t flash_sz_kib;
uint16_t ram_sz_kib;
- uint16_t part_num;
- uint8_t part_family;
- uint8_t prod_rev;
uint16_t page_size;
+ uint16_t page_size_ud;
};
-struct efm32x_flash_chip {
+struct efm32_flash_chip {
struct efm32_info info;
bool probed[EFM32_N_BANKS];
- uint32_t lb_page[LOCKWORDS_SZ/4];
- uint32_t reg_base;
- uint32_t reg_lock;
+ uint32_t lb_page[LOCKWORDS_SZ / 4];
uint32_t refcount;
};
static const struct efm32_family_data efm32_families[] = {
- { 16, "EFR32MG1P Mighty", .series = 1 },
- { 17, "EFR32MG1B Mighty", .series = 1 },
- { 18, "EFR32MG1V Mighty", .series = 1 },
- { 19, "EFR32BG1P Blue", .series = 1 },
- { 20, "EFR32BG1B Blue", .series = 1 },
- { 21, "EFR32BG1V Blue", .series = 1 },
- { 25, "EFR32FG1P Flex", .series = 1 },
- { 26, "EFR32FG1B Flex", .series = 1 },
- { 27, "EFR32FG1V Flex", .series = 1 },
- { 28, "EFR32MG2P Mighty", .series = 1 },
- { 29, "EFR32MG2B Mighty", .series = 1 },
- { 30, "EFR32MG2V Mighty", .series = 1 },
- { 31, "EFR32BG12P Blue", .series = 1 },
- { 32, "EFR32BG12B Blue", .series = 1 },
- { 33, "EFR32BG12V Blue", .series = 1 },
- { 37, "EFR32FG12P Flex", .series = 1 },
- { 38, "EFR32FG12B Flex", .series = 1 },
- { 39, "EFR32FG12V Flex", .series = 1 },
- { 40, "EFR32MG13P Mighty", .series = 1 },
- { 41, "EFR32MG13B Mighty", .series = 1 },
- { 42, "EFR32MG13V Mighty", .series = 1 },
- { 43, "EFR32BG13P Blue", .series = 1 },
- { 44, "EFR32BG13B Blue", .series = 1 },
- { 45, "EFR32BG13V Blue", .series = 1 },
- { 46, "EFR32ZG13P Zen", .series = 1 },
- { 49, "EFR32FG13P Flex", .series = 1 },
- { 50, "EFR32FG13B Flex", .series = 1 },
- { 51, "EFR32FG13V Flex", .series = 1 },
- { 52, "EFR32MG14P Mighty", .series = 1 },
- { 53, "EFR32MG14B Mighty", .series = 1 },
- { 54, "EFR32MG14V Mighty", .series = 1 },
- { 55, "EFR32BG14P Blue", .series = 1 },
- { 56, "EFR32BG14B Blue", .series = 1 },
- { 57, "EFR32BG14V Blue", .series = 1 },
- { 58, "EFR32ZG14P Zen", .series = 1 },
- { 61, "EFR32FG14P Flex", .series = 1 },
- { 62, "EFR32FG14B Flex", .series = 1 },
- { 63, "EFR32FG14V Flex", .series = 1 },
- { 71, "EFM32G", .series = 0, .page_size = 512 },
- { 72, "EFM32GG Giant", .series = 0 },
- { 73, "EFM32TG Tiny", .series = 0, .page_size = 512 },
- { 74, "EFM32LG Leopard", .series = 0 },
- { 75, "EFM32WG Wonder", .series = 0 },
- { 76, "EFM32ZG Zero", .series = 0, .page_size = 1024 },
- { 77, "EFM32HG Happy", .series = 0, .page_size = 1024 },
- { 81, "EFM32PG1B Pearl", .series = 1 },
- { 83, "EFM32JG1B Jade", .series = 1 },
- { 85, "EFM32PG12B Pearl", .series = 1 },
- { 87, "EFM32JG12B Jade", .series = 1 },
- { 89, "EFM32PG13B Pearl", .series = 1 },
- { 91, "EFM32JG13B Jade", .series = 1 },
- { 100, "EFM32GG11B Giant", .series = 1, .msc_regbase = 0x40000000 },
- { 103, "EFM32TG11B Tiny", .series = 1, .msc_regbase = 0x40000000 },
- { 106, "EFM32GG12B Giant", .series = 1, .msc_regbase = 0x40000000 },
- { 120, "EZR32WG Wonder", .series = 0 },
- { 121, "EZR32LG Leopard", .series = 0 },
- { 122, "EZR32HG Happy", .series = 0, .page_size = 1024 },
+ { 16, 1, "EFR32MG1P Mighty", .msc_regbase = 0x400e0000 },
+ { 17, 1, "EFR32MG1B Mighty", .msc_regbase = 0x400e0000 },
+ { 18, 1, "EFR32MG1V Mighty", .msc_regbase = 0x400e0000 },
+ { 19, 1, "EFR32BG1P Blue", .msc_regbase = 0x400e0000 },
+ { 20, 1, "EFR32BG1B Blue", .msc_regbase = 0x400e0000 },
+ { 21, 1, "EFR32BG1V Blue", .msc_regbase = 0x400e0000 },
+ { 25, 1, "EFR32FG1P Flex", .msc_regbase = 0x400e0000 },
+ { 26, 1, "EFR32FG1B Flex", .msc_regbase = 0x400e0000 },
+ { 27, 1, "EFR32FG1V Flex", .msc_regbase = 0x400e0000 },
+ { 28, 1, "EFR32MG12P Mighty", .msc_regbase = 0x400e0000 },
+ { 29, 1, "EFR32MG12B Mighty", .msc_regbase = 0x400e0000 },
+ { 30, 1, "EFR32MG12V Mighty", .msc_regbase = 0x400e0000 },
+ { 31, 1, "EFR32BG12P Blue", .msc_regbase = 0x400e0000 },
+ { 32, 1, "EFR32BG12B Blue", .msc_regbase = 0x400e0000 },
+ { 33, 1, "EFR32BG12V Blue", .msc_regbase = 0x400e0000 },
+ { 37, 1, "EFR32FG12P Flex", .msc_regbase = 0x400e0000 },
+ { 38, 1, "EFR32FG12B Flex", .msc_regbase = 0x400e0000 },
+ { 39, 1, "EFR32FG12V Flex", .msc_regbase = 0x400e0000 },
+ { 40, 1, "EFR32MG13P Mighty", .msc_regbase = 0x400e0000 },
+ { 41, 1, "EFR32MG13B Mighty", .msc_regbase = 0x400e0000 },
+ { 42, 1, "EFR32MG13V Mighty", .msc_regbase = 0x400e0000 },
+ { 43, 1, "EFR32BG13P Blue", .msc_regbase = 0x400e0000 },
+ { 44, 1, "EFR32BG13B Blue", .msc_regbase = 0x400e0000 },
+ { 45, 1, "EFR32BG13V Blue", .msc_regbase = 0x400e0000 },
+ { 46, 1, "EFR32ZG13P Zen", .msc_regbase = 0x400e0000 },
+ { 49, 1, "EFR32FG13P Flex", .msc_regbase = 0x400e0000 },
+ { 50, 1, "EFR32FG13B Flex", .msc_regbase = 0x400e0000 },
+ { 51, 1, "EFR32FG13V Flex", .msc_regbase = 0x400e0000 },
+ { 52, 1, "EFR32MG14P Mighty", .msc_regbase = 0x400e0000 },
+ { 53, 1, "EFR32MG14B Mighty", .msc_regbase = 0x400e0000 },
+ { 54, 1, "EFR32MG14V Mighty", .msc_regbase = 0x400e0000 },
+ { 55, 1, "EFR32BG14P Blue", .msc_regbase = 0x400e0000 },
+ { 56, 1, "EFR32BG14B Blue", .msc_regbase = 0x400e0000 },
+ { 57, 1, "EFR32BG14V Blue", .msc_regbase = 0x400e0000 },
+ { 58, 1, "EFR32ZG14P Zen", .msc_regbase = 0x400e0000 },
+ { 61, 1, "EFR32FG14P Flex", .msc_regbase = 0x400e0000 },
+ { 62, 1, "EFR32FG14B Flex", .msc_regbase = 0x400e0000 },
+ { 63, 1, "EFR32FG14V Flex", .msc_regbase = 0x400e0000 },
+ { 71, 0, "EFM32G", .msc_regbase = 0x400c0000, .page_size = 512 },
+ { 72, 0, "EFM32GG Giant", .msc_regbase = 0x400c0000 },
+ { 73, 0, "EFM32TG Tiny", .msc_regbase = 0x400c0000, .page_size = 512 },
+ { 74, 0, "EFM32LG Leopard", .msc_regbase = 0x400c0000 },
+ { 75, 0, "EFM32WG Wonder", .msc_regbase = 0x400c0000 },
+ { 76, 0, "EFM32ZG Zero", .msc_regbase = 0x400c0000, .page_size = 1024 },
+ { 77, 0, "EFM32HG Happy", .msc_regbase = 0x400c0000, .page_size = 1024 },
+ { 81, 1, "EFM32PG1B Pearl", .msc_regbase = 0x400e0000 },
+ { 83, 1, "EFM32JG1B Jade", .msc_regbase = 0x400e0000 },
+ { 85, 1, "EFM32PG12B Pearl", .msc_regbase = 0x400e0000 },
+ { 87, 1, "EFM32JG12B Jade", .msc_regbase = 0x400e0000 },
+ { 89, 1, "EFM32PG13B Pearl", .msc_regbase = 0x400e0000 },
+ { 91, 1, "EFM32JG13B Jade", .msc_regbase = 0x400e0000 },
+ { 100, 1, "EFM32GG11B Giant", .msc_regbase = 0x40000000 },
+ { 103, 1, "EFM32TG11B Tiny", .msc_regbase = 0x40000000 },
+ { 106, 1, "EFM32GG12B Giant", .msc_regbase = 0x40000000 },
+ { 120, 0, "EZR32WG Wonder", .msc_regbase = 0x400c0000 },
+ { 121, 0, "EZR32LG Leopard", .msc_regbase = 0x400c0000 },
+ { 122, 0, "EZR32HG Happy", .msc_regbase = 0x400c0000, .page_size = 1024 },
+ { 128, 2, "EFR32/EFM32 Series-2", .msc_regbase = 0x50030000 },
};
const struct flash_driver efm32_flash;
-static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t addr, uint32_t count);
+static int efm32_priv_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t addr, uint32_t count);
-static int efm32x_write_only_lockbits(struct flash_bank *bank);
+static int efm32_write_only_lockbits(struct flash_bank *bank);
-static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz)
+static int efm32_read_reg_u32(struct flash_bank *bank, target_addr_t offset,
+ uint32_t *value)
{
- return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz);
-}
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
-static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz)
-{
- return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz);
-}
-
-static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum)
-{
- return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum);
-}
-
-static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily)
-{
- return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily);
-}
-
-static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev)
-{
- return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev);
+ return target_read_u32(bank->target,
+ efm32_info->info.family_data->msc_regbase + offset,
+ value);
}
-static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset,
- uint32_t *value)
+static int efm32_write_reg_u32(struct flash_bank *bank, target_addr_t offset,
+ uint32_t value)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- uint32_t base = efm32x_info->reg_base;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
- return target_read_u32(bank->target, base + offset, value);
+ return target_write_u32(bank->target,
+ efm32_info->info.family_data->msc_regbase + offset,
+ value);
}
-static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset,
- uint32_t value)
-{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- uint32_t base = efm32x_info->reg_base;
-
- return target_write_u32(bank->target, base + offset, value);
-}
-
-static int efm32x_read_info(struct flash_bank *bank)
+static int efm32_read_info(struct flash_bank *bank)
{
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ struct efm32_info *efm32_mcu_info = &efm32_info->info;
int ret;
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- struct efm32_info *efm32_info = &(efm32x_info->info);
- memset(efm32_info, 0, sizeof(struct efm32_info));
+ memset(efm32_mcu_info, 0, sizeof(struct efm32_info));
- ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib));
+ uint8_t val8;
+ ret = target_read_u8(bank->target, EFM32_DI_PART_FAMILY, &val8);
if (ret != ERROR_OK)
return ret;
+ for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) {
+ if (efm32_families[i].part_id == val8)
+ efm32_mcu_info->family_data = &efm32_families[i];
+ }
+ if (!efm32_mcu_info->family_data) {
+ LOG_ERROR("Unknown MCU family %d", val8);
+ return ERROR_FAIL;
+ }
- ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib));
- if (ret != ERROR_OK)
- return ret;
+ efm32_mcu_info->di_addr = &efm32_dev_info_addr[efm32_mcu_info->family_data->series];
+ efm32_mcu_info->msc_offset = &efm32_msc_offset[efm32_mcu_info->family_data->series];
- ret = efm32x_get_part_num(bank, &(efm32_info->part_num));
+ if (efm32_mcu_info->family_data->series == 2) {
+ ret = target_read_u32(bank->target,
+ efm32_mcu_info->di_addr->part_info,
+ &efm32_mcu_info->part_info);
+ if (ret != ERROR_OK)
+ return ret;
+ } else {
+ ret = target_read_u16(bank->target,
+ efm32_mcu_info->di_addr->part_num,
+ &efm32_mcu_info->part_num);
+ if (ret != ERROR_OK)
+ return ret;
+ }
+
+ ret = target_read_u8(bank->target,
+ efm32_mcu_info->di_addr->part_rev,
+ &efm32_mcu_info->part_rev);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_get_part_family(bank, &(efm32_info->part_family));
+ ret = target_read_u16(bank->target,
+ efm32_mcu_info->di_addr->flash_sz,
+ &efm32_mcu_info->flash_sz_kib);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev));
+ ret = target_read_u16(bank->target,
+ efm32_mcu_info->di_addr->ram_sz,
+ &efm32_mcu_info->ram_sz_kib);
if (ret != ERROR_OK)
return ret;
- for (size_t i = 0; i < ARRAY_SIZE(efm32_families); i++) {
- if (efm32_families[i].family_id == efm32_info->part_family)
- efm32_info->family_data = &efm32_families[i];
- }
-
- if (!efm32_info->family_data) {
- LOG_ERROR("Unknown MCU family %d", efm32_info->part_family);
- return ERROR_FAIL;
- }
-
- 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;
- }
-
- if (efm32_info->family_data->msc_regbase != 0)
- efm32x_info->reg_base = efm32_info->family_data->msc_regbase;
-
- if (efm32_info->family_data->page_size != 0) {
- efm32_info->page_size = efm32_info->family_data->page_size;
+ efm32_mcu_info->page_size_ud = 0;
+ if (efm32_mcu_info->family_data->page_size != 0) {
+ efm32_mcu_info->page_size = efm32_mcu_info->family_data->page_size;
+ } else if ((efm32_mcu_info->family_data->part_id == 72 ||
+ efm32_mcu_info->family_data->part_id == 74) &&
+ efm32_mcu_info->part_rev < 18) {
+ /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid for MCUs
+ * with part_rev < 18
+ */
+ if (efm32_mcu_info->flash_sz_kib < 512)
+ efm32_mcu_info->page_size = 2048;
+ else
+ efm32_mcu_info->page_size = 4096;
} else {
- uint8_t pg_size = 0;
- ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE,
- &pg_size);
+ uint32_t val32;
+ ret = target_read_u32(bank->target,
+ efm32_mcu_info->di_addr->page_size,
+ &val32);
if (ret != ERROR_OK)
return ret;
- efm32_info->page_size = (1 << ((pg_size+10) & 0xff));
-
- if (efm32_info->part_family == EFM_FAMILY_ID_GIANT_GECKO ||
- efm32_info->part_family == EFM_FAMILY_ID_LEOPARD_GECKO) {
- /* Giant or Leopard Gecko */
- if (efm32_info->prod_rev < 18) {
- /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid
- for MCUs with PROD_REV < 18 */
- if (efm32_info->flash_sz_kib < 512)
- efm32_info->page_size = 2048;
- else
- efm32_info->page_size = 4096;
- }
- }
-
- if ((efm32_info->page_size != 2048) &&
- (efm32_info->page_size != 4096)) {
- LOG_ERROR("Invalid page size %u", efm32_info->page_size);
- return ERROR_FAIL;
- }
+ efm32_mcu_info->page_size = BIT(FIELD_GET(EFM32_DI_PARTINFO_PAGE_SZ_MASK, val32)) * 1024;
+ if (efm32_mcu_info->family_data->series == 2)
+ efm32_mcu_info->page_size_ud = FIELD_GET(EFM32_DI_PARTINFO_PAGE_SZ_UD_MASK, val32) * 1024;
+ }
+ if (!efm32_mcu_info->page_size_ud)
+ efm32_mcu_info->page_size_ud = efm32_mcu_info->page_size;
+
+ if (efm32_mcu_info->page_size != 512 &&
+ efm32_mcu_info->page_size != 1024 &&
+ efm32_mcu_info->page_size != 2048 &&
+ efm32_mcu_info->page_size != 4096 &&
+ efm32_mcu_info->page_size != 8192) {
+ LOG_ERROR("Invalid page size %u", efm32_mcu_info->page_size);
+ return ERROR_FAIL;
}
return ERROR_OK;
}
/* flash bank efm32 0 0 */
-FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command)
+FLASH_BANK_COMMAND_HANDLER(efm32_flash_bank_command)
{
- struct efm32x_flash_chip *efm32x_info = NULL;
-
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
- int bank_index = efm32x_get_bank_index(bank->base);
+ int bank_index = efm32_get_bank_index(bank->base);
if (bank_index < 0) {
LOG_ERROR("Flash bank with base address %" PRIx32 " is not supported",
- (uint32_t) bank->base);
+ (uint32_t)bank->base);
return ERROR_FAIL;
}
/* look for an existing flash structure matching target */
- for (struct flash_bank *bank_iter = flash_bank_list(); bank_iter; bank_iter = bank_iter->next) {
- if (bank_iter->driver == &efm32_flash
- && bank_iter->target == bank->target
- && bank->driver_priv) {
- efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = NULL;
+ for (struct flash_bank *bank_iter = flash_bank_list();
+ bank_iter;
+ bank_iter = bank_iter->next) {
+ if (bank_iter->driver == &efm32_flash &&
+ bank_iter->target == bank->target &&
+ bank->driver_priv) {
+ efm32_info = bank->driver_priv;
break;
}
}
- if (!efm32x_info) {
+ if (!efm32_info) {
/* target not matched, make a new one */
- efm32x_info = calloc(1, sizeof(struct efm32x_flash_chip));
+ efm32_info = calloc(1, sizeof(struct efm32_flash_chip));
- memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ);
+ memset(efm32_info->lb_page, 0xff, LOCKWORDS_SZ);
}
- ++efm32x_info->refcount;
- bank->driver_priv = efm32x_info;
+ ++efm32_info->refcount;
+ bank->driver_priv = efm32_info;
return ERROR_OK;
}
/**
- * Remove flash structure corresponding to this bank,
- * if and only if it's not used by any others
+ * Remove flash structure corresponding to this bank, if and only if it's not
+ * used by any others
*/
-static void efm32x_free_driver_priv(struct flash_bank *bank)
+static void efm32_free_driver_priv(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
-
- if (efm32x_info) {
- /* Use ref count to determine if it can be freed; scanning bank list doesn't work,
- * because this function can be called after some banks in the list have been
- * already destroyed */
- --efm32x_info->refcount;
- if (efm32x_info->refcount == 0) {
- free(efm32x_info);
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+
+ if (efm32_info) {
+ /* Use ref count to determine if it can be freed; scanning bank
+ * list doesn't work, because this function can be called after
+ * some banks in the list have been already destroyed.
+ */
+ --efm32_info->refcount;
+ if (efm32_info->refcount == 0) {
+ free(efm32_info);
bank->driver_priv = NULL;
}
}
}
+static int efm32_msc_clock_enable(struct flash_bank *bank)
+{
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+
+ if (efm32_info->info.family_data->series == 0 ||
+ efm32_info->info.family_data->series == 1)
+ return ERROR_OK;
+
+ unsigned int s2_family = FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK,
+ efm32_info->info.part_info);
+ uint32_t msc_clken;
+ switch (s2_family) {
+ case 21:
+ msc_clken = 0;
+ break;
+ case 22:
+ case 27:
+ case 29:
+ msc_clken = BIT(17);
+ break;
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 28:
+ msc_clken = BIT(16);
+ break;
+ default:
+ LOG_WARNING("Don't know EFR/EFM Gx family number, can't set MSC register. Use default values..");
+ msc_clken = BIT(16);
+ }
+ int ret = target_write_u32(bank->target,
+ EFM32_CMU_REG_CLKEN1_SET,
+ msc_clken);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Failed to enable MSC clock");
+ return ret;
+ }
+
+ return ERROR_OK;
+}
+
/* set or reset given bits in a register */
-static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg,
- uint32_t bitmask, int set)
+static int efm32_set_reg_bits(struct flash_bank *bank, uint32_t reg,
+ uint32_t bitmask, int set)
{
int ret = 0;
uint32_t reg_val = 0;
- ret = efm32x_read_reg_u32(bank, reg, ®_val);
+ ret = efm32_read_reg_u32(bank, reg, ®_val);
if (ret != ERROR_OK)
return ret;
@@ -403,41 +527,49 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg,
else
reg_val &= ~bitmask;
- return efm32x_write_reg_u32(bank, reg, reg_val);
+ return efm32_write_reg_u32(bank, reg, reg_val);
}
-static int efm32x_set_wren(struct flash_bank *bank, int write_enable)
+static int efm32_set_wren(struct flash_bank *bank, int write_enable)
{
- return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL,
- EFM32_MSC_WRITECTRL_WREN_MASK, write_enable);
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+
+ return efm32_set_reg_bits(bank,
+ efm32_info->info.msc_offset->off_writectrl,
+ EFM32_MSC_WRITECTRL_WREN_MASK, write_enable);
}
-static int efm32x_msc_lock(struct flash_bank *bank, int lock)
+static int efm32_msc_lock(struct flash_bank *bank, int lock)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- return efm32x_write_reg_u32(bank, efm32x_info->reg_lock,
- (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY));
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+
+ return efm32_write_reg_u32(bank,
+ efm32_info->info.msc_offset->off_lock,
+ lock ? 0 : EFM32_MSC_LOCK_LOCKKEY);
}
-static int efm32x_wait_status(struct flash_bank *bank, int timeout,
- uint32_t wait_mask, int wait_for_set)
+static int efm32_wait_status(struct flash_bank *bank, int timeout_ms,
+ uint32_t wait_mask, bool wait_for_set)
{
- int ret = 0;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ int64_t start_ms = timeval_ms();
uint32_t status = 0;
while (1) {
- ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
+ int ret = efm32_read_reg_u32(bank,
+ efm32_info->info.msc_offset->off_status,
+ &status);
if (ret != ERROR_OK)
- break;
+ return ret;
- LOG_DEBUG("status: 0x%" PRIx32 "", status);
+ LOG_DEBUG("status: 0x%" PRIx32, status);
- if (((status & wait_mask) == 0) && (wait_for_set == 0))
+ if (!(status & wait_mask) && !wait_for_set)
break;
- else if (((status & wait_mask) != 0) && wait_for_set)
+ if ((status & wait_mask) && wait_for_set)
break;
- if (timeout-- <= 0) {
+ if (timeval_ms() - start_ms > timeout_ms) {
LOG_ERROR("timed out waiting for MSC status");
return ERROR_FAIL;
}
@@ -445,13 +577,10 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout,
alive_sleep(1);
}
- if (status & EFM32_MSC_STATUS_ERASEABORTED_MASK)
- LOG_WARNING("page erase was aborted");
-
- return ret;
+ return ERROR_OK;
}
-static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
+static int efm32_erase_page(struct flash_bank *bank, uint32_t addr)
{
/* this function DOES NOT set WREN; must be set already */
/* 1. write address to ADDRB
@@ -460,20 +589,27 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
4. write ERASEPAGE
5. wait until !STATUS_BUSY
*/
- int ret = 0;
- uint32_t status = 0;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ int ret;
+
LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr);
- ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);
+ ret = efm32_write_reg_u32(bank,
+ efm32_info->info.msc_offset->off_addrb,
+ addr);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
- EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
+ ret = efm32_set_reg_bits(bank,
+ efm32_info->info.msc_offset->off_writecmd,
+ EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
+ uint32_t status;
+ ret = efm32_read_reg_u32(bank,
+ efm32_info->info.msc_offset->off_status,
+ &status);
if (ret != ERROR_OK)
return ret;
@@ -487,17 +623,18 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr)
return ERROR_FAIL;
}
- ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
- EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1);
+ ret = efm32_set_reg_bits(bank,
+ efm32_info->info.msc_offset->off_writecmd,
+ EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1);
if (ret != ERROR_OK)
return ret;
- return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO,
- EFM32_MSC_STATUS_BUSY_MASK, 0);
+ return efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT,
+ EFM32_MSC_STATUS_BUSY_MASK, false);
}
-static int efm32x_erase(struct flash_bank *bank, unsigned int first,
- unsigned int last)
+static int efm32_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
{
struct target *target = bank->target;
int ret = 0;
@@ -507,26 +644,32 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first,
return ERROR_TARGET_NOT_HALTED;
}
- efm32x_msc_lock(bank, 0);
- ret = efm32x_set_wren(bank, 1);
+ ret = efm32_msc_clock_enable(bank);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Failed to enable MSC clock");
+ return ret;
+ }
+
+ efm32_msc_lock(bank, 0);
+ ret = efm32_set_wren(bank, 1);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to enable MSC write");
return ret;
}
for (unsigned int i = first; i <= last; i++) {
- ret = efm32x_erase_page(bank, bank->base + bank->sectors[i].offset);
+ ret = efm32_erase_page(bank, bank->base + bank->sectors[i].offset);
if (ret != ERROR_OK)
LOG_ERROR("Failed to erase page %d", i);
}
- ret = efm32x_set_wren(bank, 0);
- efm32x_msc_lock(bank, 1);
+ ret = efm32_set_wren(bank, 0);
+ efm32_msc_lock(bank, 1);
if (ret != ERROR_OK)
return ret;
if (bank->base == EFM32_MSC_LOCK_BITS) {
- ret = efm32x_write_only_lockbits(bank);
+ ret = efm32_write_only_lockbits(bank);
if (ret != ERROR_OK)
LOG_ERROR("Failed to restore lockbits after erase");
}
@@ -534,9 +677,9 @@ static int efm32x_erase(struct flash_bank *bank, unsigned int first,
return ret;
}
-static int efm32x_read_lock_data(struct flash_bank *bank)
+static int efm32_read_lock_data(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
struct target *target = bank->target;
int data_size = 0;
uint32_t *ptr = NULL;
@@ -547,10 +690,10 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
/* calculate the number of 32-bit words to read (one lock bit per sector) */
data_size = (bank->num_sectors + 31) / 32;
- ptr = efm32x_info->lb_page;
+ ptr = efm32_info->lb_page;
for (int i = 0; i < data_size; i++, ptr++) {
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr);
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + i * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read PLW %d", i);
return ret;
@@ -560,48 +703,48 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
/* also, read ULW, DLW, MLW, ALW and CLW words */
/* ULW, word 126 */
- ptr = efm32x_info->lb_page + 126;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr);
+ ptr = efm32_info->lb_page + 126;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 126 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read ULW");
return ret;
}
/* DLW, word 127 */
- ptr = efm32x_info->lb_page + 127;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr);
+ ptr = efm32_info->lb_page + 127;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 127 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read DLW");
return ret;
}
/* MLW, word 125, present in GG, LG, PG, JG, EFR32 */
- ptr = efm32x_info->lb_page + 125;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr);
+ ptr = efm32_info->lb_page + 125;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 125 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read MLW");
return ret;
}
/* ALW, word 124, present in GG, LG, PG, JG, EFR32 */
- ptr = efm32x_info->lb_page + 124;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+124*4, ptr);
+ ptr = efm32_info->lb_page + 124;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 124 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read ALW");
return ret;
}
/* CLW1, word 123, present in EFR32 */
- ptr = efm32x_info->lb_page + 123;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+123*4, ptr);
+ ptr = efm32_info->lb_page + 123;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 123 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read CLW1");
return ret;
}
/* CLW0, word 122, present in GG, LG, PG, JG, EFR32 */
- ptr = efm32x_info->lb_page + 122;
- ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+122*4, ptr);
+ ptr = efm32_info->lb_page + 122;
+ ret = target_read_u32(target, EFM32_MSC_LOCK_BITS + 122 * 4, ptr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read CLW0");
return ret;
@@ -610,24 +753,29 @@ static int efm32x_read_lock_data(struct flash_bank *bank)
return ERROR_OK;
}
-static int efm32x_write_only_lockbits(struct flash_bank *bank)
+static int efm32_write_only_lockbits(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- return efm32x_priv_write(bank, (uint8_t *)efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ);
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+
+ return efm32_priv_write(bank, (uint8_t *)efm32_info->lb_page,
+ EFM32_MSC_LOCK_BITS, LOCKWORDS_SZ);
}
-static int efm32x_write_lock_data(struct flash_bank *bank)
+static int efm32_write_lock_data(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- int ret = 0;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
/* Preserve any data written to the high portion of the lockbits page */
- assert(efm32x_info->info.page_size >= LOCKWORDS_SZ);
- uint32_t extra_bytes = efm32x_info->info.page_size - LOCKWORDS_SZ;
+ assert(efm32_info->info.page_size >= LOCKWORDS_SZ);
+
+ uint32_t extra_bytes = efm32_info->info.page_size - LOCKWORDS_SZ;
uint8_t *extra_data = NULL;
+ int ret;
if (extra_bytes) {
extra_data = malloc(extra_bytes);
- ret = target_read_buffer(bank->target, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes, extra_data);
+ ret = target_read_buffer(bank->target,
+ EFM32_MSC_LOCK_BITS_EXTRA,
+ extra_bytes, extra_data);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read extra contents of LB page");
free(extra_data);
@@ -635,7 +783,7 @@ static int efm32x_write_lock_data(struct flash_bank *bank)
}
}
- ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS);
+ ret = efm32_erase_page(bank, EFM32_MSC_LOCK_BITS);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to erase LB page");
if (extra_data)
@@ -644,7 +792,9 @@ static int efm32x_write_lock_data(struct flash_bank *bank)
}
if (extra_data) {
- ret = efm32x_priv_write(bank, extra_data, EFM32_MSC_LOCK_BITS_EXTRA, extra_bytes);
+ ret = efm32_priv_write(bank, extra_data,
+ EFM32_MSC_LOCK_BITS_EXTRA,
+ extra_bytes);
free(extra_data);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to restore extra contents of LB page");
@@ -652,47 +802,46 @@ static int efm32x_write_lock_data(struct flash_bank *bank)
}
}
- return efm32x_write_only_lockbits(bank);
+ return efm32_write_only_lockbits(bank);
}
-static int efm32x_get_page_lock(struct flash_bank *bank, size_t page)
+static int efm32_get_page_lock(struct flash_bank *bank, size_t page)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
uint32_t dw = 0;
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_V1:
+ case EFM32_FLASH_BASE_V2:
+ dw = efm32_info->lb_page[page >> 5];
+ mask = BIT(page & 0x1f);
+ break;
+ case EFM32_MSC_USER_DATA:
+ dw = efm32_info->lb_page[126];
+ mask = BIT(0);
+ break;
+ case EFM32_MSC_LOCK_BITS:
+ dw = efm32_info->lb_page[126];
+ mask = BIT(1);
+ break;
}
return (dw & mask) ? 0 : 1;
}
-static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
+static int efm32_set_page_lock(struct flash_bank *bank, size_t page, int set)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
- if (bank->base != EFM32_FLASH_BASE) {
+ if (bank->base != EFM32_FLASH_BASE_V1 &&
+ bank->base != EFM32_FLASH_BASE_V2) {
LOG_ERROR("Locking user and lockbits pages is not supported yet");
return ERROR_FAIL;
}
- uint32_t *dw = &efm32x_info->lb_page[page >> 5];
- uint32_t mask = 0;
-
- mask = 1 << (page & 0x1f);
-
+ uint32_t *dw = &efm32_info->lb_page[page >> 5];
+ uint32_t mask = BIT(page & 0x1f);
if (!set)
*dw |= mask;
else
@@ -701,26 +850,36 @@ static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set)
return ERROR_OK;
}
-static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first,
- unsigned int last)
+static int efm32_protect(struct flash_bank *bank, int set, unsigned int first,
+ unsigned int last)
{
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
struct target *target = bank->target;
int ret = 0;
+ if (efm32_info->info.family_data->series == 2)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ ret = efm32_read_lock_data(bank);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Failed to read LB data");
+ return ret;
+ }
+
for (unsigned int i = first; i <= last; i++) {
- ret = efm32x_set_page_lock(bank, i, set);
+ ret = efm32_set_page_lock(bank, i, set);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to set lock on page %d", i);
return ret;
}
}
- ret = efm32x_write_lock_data(bank);
+ ret = efm32_write_lock_data(bank);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to write LB page");
return ret;
@@ -729,146 +888,74 @@ static int efm32x_protect(struct flash_bank *bank, int set, unsigned int first,
return ERROR_OK;
}
-static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf,
- uint32_t address, uint32_t count)
+static int efm32_write_block(struct flash_bank *bank, const uint8_t *buf,
+ uint32_t address, uint32_t count)
{
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
struct target *target = bank->target;
- uint32_t buffer_size = 16384;
- struct working_area *write_algorithm;
- struct working_area *source;
- struct reg_param reg_params[5];
- struct armv7m_algorithm armv7m_info;
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- int ret = ERROR_OK;
-
- /* see contrib/loaders/flash/efm32.S for src */
- static const uint8_t efm32x_flash_write_code[] = {
- /* #define EFM32_MSC_WRITECTRL_OFFSET 0x008 */
- /* #define EFM32_MSC_WRITECMD_OFFSET 0x00c */
- /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */
- /* #define EFM32_MSC_WDATA_OFFSET 0x018 */
- /* #define EFM32_MSC_STATUS_OFFSET 0x01c */
-
- 0x01, 0x26, /* movs r6, #1 */
- 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */
-
- /* wait_fifo: */
- 0x16, 0x68, /* ldr r6, [r2, #0] */
- 0x00, 0x2e, /* cmp r6, #0 */
- 0x22, 0xd0, /* beq exit */
- 0x55, 0x68, /* ldr r5, [r2, #4] */
- 0xb5, 0x42, /* cmp r5, r6 */
- 0xf9, 0xd0, /* beq wait_fifo */
-
- 0x04, 0x61, /* str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] */
- 0x01, 0x26, /* movs r6, #1 */
- 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */
- 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
- 0x06, 0x27, /* movs r7, #6 */
- 0x3e, 0x42, /* tst r6, r7 */
- 0x16, 0xd1, /* bne error */
-
- /* wait_wdataready: */
- 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
- 0x08, 0x27, /* movs r7, #8 */
- 0x3e, 0x42, /* tst r6, r7 */
- 0xfb, 0xd0, /* beq wait_wdataready */
-
- 0x2e, 0x68, /* ldr r6, [r5] */
- 0x86, 0x61, /* str r6, [r0, #EFM32_MSC_WDATA_OFFSET] */
- 0x08, 0x26, /* movs r6, #8 */
- 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */
-
- 0x04, 0x35, /* adds r5, #4 */
- 0x04, 0x34, /* adds r4, #4 */
-
- /* busy: */
- 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */
- 0x01, 0x27, /* movs r7, #1 */
- 0x3e, 0x42, /* tst r6, r7 */
- 0xfb, 0xd1, /* bne busy */
-
- 0x9d, 0x42, /* cmp r5, r3 */
- 0x01, 0xd3, /* bcc no_wrap */
- 0x15, 0x46, /* mov r5, r2 */
- 0x08, 0x35, /* adds r5, #8 */
-
- /* no_wrap: */
- 0x55, 0x60, /* str r5, [r2, #4] */
- 0x01, 0x39, /* subs r1, r1, #1 */
- 0x00, 0x29, /* cmp r1, #0 */
- 0x02, 0xd0, /* beq exit */
- 0xdb, 0xe7, /* b wait_fifo */
-
- /* error: */
- 0x00, 0x20, /* movs r0, #0 */
- 0x50, 0x60, /* str r0, [r2, #4] */
-
- /* exit: */
- 0x30, 0x46, /* mov r0, r6 */
- 0x00, 0xbe, /* bkpt #0 */
- };
-
+ struct working_area *write_algorithm, *source;
+ int ret;
/* flash write code */
- if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code),
- &write_algorithm) != ERROR_OK) {
+ ret = target_alloc_working_area(target,
+ efm32_info->info.msc_offset->flash_write_code_len,
+ &write_algorithm);
+ if (ret) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
-
ret = target_write_buffer(target, write_algorithm->address,
- sizeof(efm32x_flash_write_code), efm32x_flash_write_code);
- if (ret != ERROR_OK)
+ efm32_info->info.msc_offset->flash_write_code_len,
+ efm32_info->info.msc_offset->flash_write_code);
+ if (ret)
return ret;
/* memory buffer */
- while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
- buffer_size /= 2;
- buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
- if (buffer_size <= 256) {
- /* we already allocated the writing code, but failed to get a
- * buffer, free the algorithm */
- target_free_working_area(target, write_algorithm);
-
- LOG_WARNING("no large enough working area available, can't do block memory writes");
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
- }
+ uint32_t buffer_size = target_get_working_area_avail(target);
+ if (buffer_size <= 256) {
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
+ buffer_size = MIN(buffer_size, 16 * 1024);
+ ret = target_alloc_working_area(target, buffer_size, &source);
+ if (ret)
+ return ret;
+ struct reg_param reg_params[5];
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (word-32bit) */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */
init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */
init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
- buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base);
+ buf_set_u32(reg_params[0].value, 0, 32, efm32_info->info.family_data->msc_regbase);
buf_set_u32(reg_params[1].value, 0, 32, count);
buf_set_u32(reg_params[2].value, 0, 32, source->address);
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[4].value, 0, 32, address);
- armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
- armv7m_info.core_mode = ARM_MODE_THREAD;
-
+ struct armv7m_algorithm armv7m_info = {
+ .common_magic = ARMV7M_COMMON_MAGIC,
+ .core_mode = ARM_MODE_THREAD,
+ };
ret = target_run_flash_async_algorithm(target, buf, count, 4,
- 0, NULL,
- 5, reg_params,
- source->address, source->size,
- write_algorithm->address, 0,
- &armv7m_info);
+ 0, NULL,
+ 5, reg_params,
+ source->address, source->size,
+ write_algorithm->address, 0,
+ &armv7m_info);
if (ret == ERROR_FLASH_OPERATION_FAILED) {
- LOG_ERROR("flash write failed at address 0x%"PRIx32,
- buf_get_u32(reg_params[4].value, 0, 32));
+ LOG_ERROR("flash write failed at address 0x%" PRIx32,
+ buf_get_u32(reg_params[4].value, 0, 32));
if (buf_get_u32(reg_params[0].value, 0, 32) &
- EFM32_MSC_STATUS_LOCKED_MASK) {
+ EFM32_MSC_STATUS_LOCKED_MASK) {
LOG_ERROR("flash memory write protected");
}
if (buf_get_u32(reg_params[0].value, 0, 32) &
- EFM32_MSC_STATUS_INVADDR_MASK) {
+ EFM32_MSC_STATUS_INVADDR_MASK) {
LOG_ERROR("invalid flash memory write address");
}
}
@@ -885,8 +972,8 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf,
return ret;
}
-static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
- uint32_t val)
+static int efm32_write_word(struct flash_bank *bank, uint32_t addr,
+ uint32_t val)
{
/* this function DOES NOT set WREN; must be set already */
/* 1. write address to ADDRB
@@ -900,23 +987,28 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
/* FIXME: EFM32G ref states (7.3.2) that writes should be
* performed twice per dword */
-
- int ret = 0;
- uint32_t status = 0;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ int ret;
/* if not called, GDB errors will be reported during large writes */
keep_alive();
- ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr);
+ ret = efm32_write_reg_u32(bank,
+ efm32_info->info.msc_offset->off_addrb,
+ addr);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD,
- EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
+ ret = efm32_set_reg_bits(bank,
+ efm32_info->info.msc_offset->off_writecmd,
+ EFM32_MSC_WRITECMD_LADDRIM_MASK, 1);
if (ret != ERROR_OK)
return ret;
- ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status);
+ uint32_t status;
+ ret = efm32_read_reg_u32(bank,
+ efm32_info->info.msc_offset->off_status,
+ &status);
if (ret != ERROR_OK)
return ret;
@@ -930,28 +1022,31 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
return ERROR_FAIL;
}
- ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO,
- EFM32_MSC_STATUS_WDATAREADY_MASK, 1);
+ ret = efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT,
+ EFM32_MSC_STATUS_WDATAREADY_MASK, true);
if (ret != ERROR_OK) {
LOG_ERROR("Wait for WDATAREADY failed");
return ret;
}
- ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val);
+ ret = efm32_write_reg_u32(bank,
+ efm32_info->info.msc_offset->off_wdata,
+ val);
if (ret != ERROR_OK) {
LOG_ERROR("WDATA write failed");
return ret;
}
- ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD,
- EFM32_MSC_WRITECMD_WRITEONCE_MASK);
+ ret = efm32_write_reg_u32(bank,
+ efm32_info->info.msc_offset->off_writecmd,
+ EFM32_MSC_WRITECMD_WRITEONCE_MASK);
if (ret != ERROR_OK) {
LOG_ERROR("WRITECMD write failed");
return ret;
}
- ret = efm32x_wait_status(bank, EFM32_FLASH_WRITE_TMO,
- EFM32_MSC_STATUS_BUSY_MASK, 0);
+ ret = efm32_wait_status(bank, EFM32_FLASH_OPERATION_TIMEOUT,
+ EFM32_MSC_STATUS_BUSY_MASK, false);
if (ret != ERROR_OK) {
LOG_ERROR("Wait for BUSY failed");
return ret;
@@ -960,8 +1055,8 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr,
return ERROR_OK;
}
-static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t addr, uint32_t count)
+static int efm32_priv_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t addr, uint32_t count)
{
struct target *target = bank->target;
uint8_t *new_buffer = NULL;
@@ -972,8 +1067,7 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
}
if (addr & 0x3) {
- LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte "
- "alignment", addr);
+ LOG_ERROR("addr 0x%" PRIx32 " breaks required 4-byte alignment", addr);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
@@ -982,12 +1076,11 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
count = (old_count | 3) + 1;
new_buffer = malloc(count);
if (!new_buffer) {
- LOG_ERROR("odd number of bytes to write and no memory "
- "for padding buffer");
+ LOG_ERROR("odd number of bytes to write and no memory for padding buffer");
return ERROR_FAIL;
}
- LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %" PRIu32 " "
- "and padding with 0xff", old_count, count);
+ LOG_INFO("odd number of bytes to write (%" PRIu32 "), extending to %"
+ PRIu32 " and padding with 0xff", old_count, count);
memset(new_buffer, 0xff, count);
buffer = memcpy(new_buffer, buffer, old_count);
}
@@ -995,26 +1088,29 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t words_remaining = count / 4;
int retval, retval2;
+ retval = efm32_msc_clock_enable(bank);
+ if (retval != ERROR_OK)
+ goto cleanup;
+
/* unlock flash registers */
- efm32x_msc_lock(bank, 0);
- retval = efm32x_set_wren(bank, 1);
+ efm32_msc_lock(bank, 0);
+ retval = efm32_set_wren(bank, 1);
if (retval != ERROR_OK)
goto cleanup;
/* try using a block write */
- retval = efm32x_write_block(bank, buffer, addr, words_remaining);
+ retval = efm32_write_block(bank, buffer, addr, words_remaining);
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* if block write failed (no sufficient working area),
* we use normal (slow) single word accesses */
- LOG_WARNING("couldn't use block writes, falling back to single "
- "memory accesses");
+ LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
while (words_remaining > 0) {
uint32_t value;
memcpy(&value, buffer, sizeof(uint32_t));
- retval = efm32x_write_word(bank, addr, value);
+ retval = efm32_write_word(bank, addr, value);
if (retval != ERROR_OK)
goto reset_pg_and_lock;
@@ -1025,8 +1121,8 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
}
reset_pg_and_lock:
- retval2 = efm32x_set_wren(bank, 0);
- efm32x_msc_lock(bank, 1);
+ retval2 = efm32_set_wren(bank, 0);
+ efm32_msc_lock(bank, 1);
if (retval == ERROR_OK)
retval = retval2;
@@ -1035,34 +1131,77 @@ static int efm32x_priv_write(struct flash_bank *bank, const uint8_t *buffer,
return retval;
}
-static int efm32x_write(struct flash_bank *bank, const uint8_t *buffer,
- uint32_t offset, uint32_t count)
+static int efm32_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
{
if (bank->base == EFM32_MSC_LOCK_BITS && offset < LOCKWORDS_SZ) {
LOG_ERROR("Cannot write to lock words");
return ERROR_FAIL;
}
- return efm32x_priv_write(bank, buffer, bank->base + offset, count);
+ return efm32_priv_write(bank, buffer, bank->base + offset, count);
+}
+
+static char *efm32_get_str_identifier(struct efm32_info *efm32_mcu_info,
+ char *buf, size_t len)
+{
+ if (!efm32_mcu_info->part_info) {
+ snprintf(buf, len, "%s Gecko, rev %" PRIu8,
+ efm32_mcu_info->family_data->name,
+ efm32_mcu_info->part_rev);
+ return buf;
+ }
+ unsigned int dev_num = FIELD_GET(EFM32_DI_PARTINFO_NUM_MASK,
+ efm32_mcu_info->part_info);
+ unsigned int dev_family = FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK,
+ efm32_mcu_info->part_info);
+ unsigned int dev_type = FIELD_GET(EFM32_DI_PARTINFO_TYPE_MASK,
+ efm32_mcu_info->part_info);
+
+ const char *types = "FMBZxP";
+ if (dev_type > strlen(types)) {
+ snprintf(buf, len, "Unknown MCU family %u", dev_type);
+ return buf;
+ }
+
+ char dev_num_letter = 'A' + (dev_num / 1000);
+ unsigned int dev_num_digits = dev_num % 1000;
+
+ snprintf(buf, len, "%s%cG%u %c%03u, rev %" PRIu8,
+ types[dev_type] == 'P' ? "EFM32" : "EFR32",
+ types[dev_type],
+ dev_family,
+ dev_num_letter,
+ dev_num_digits,
+ efm32_mcu_info->part_rev);
+ return buf;
}
-static int efm32x_probe(struct flash_bank *bank)
+static int efm32_probe(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
- struct efm32_info *efm32_mcu_info = &(efm32x_info->info);
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ struct efm32_info *efm32_mcu_info = &efm32_info->info;
+ int bank_index = efm32_get_bank_index(bank->base);
+ uint32_t base_address = EFM32_FLASH_BASE_V2;
+ char strbuf[256];
int ret;
- int bank_index = efm32x_get_bank_index(bank->base);
assert(bank_index >= 0);
- efm32x_info->probed[bank_index] = false;
- memset(efm32x_info->lb_page, 0xff, LOCKWORDS_SZ);
+ efm32_info->probed[bank_index] = false;
+ memset(efm32_info->lb_page, 0xff, LOCKWORDS_SZ);
- ret = efm32x_read_info(bank);
+ ret = efm32_read_info(bank);
if (ret != ERROR_OK)
return ret;
- LOG_INFO("detected part: %s Gecko, rev %d",
- efm32_mcu_info->family_data->name, efm32_mcu_info->prod_rev);
+ if (efm32_mcu_info->family_data->series == 0 ||
+ efm32_mcu_info->family_data->series == 1 ||
+ FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, efm32_mcu_info->part_info) == 21 ||
+ FIELD_GET(EFM32_DI_PARTINFO_FAMILY_MASK, efm32_mcu_info->part_info) == 22)
+ base_address = EFM32_FLASH_BASE_V1;
+
+ LOG_INFO("detected part: %s",
+ efm32_get_str_identifier(efm32_mcu_info, strbuf, sizeof(strbuf)));
LOG_INFO("flash size = %d KiB", efm32_mcu_info->flash_sz_kib);
LOG_INFO("flash page size = %d B", efm32_mcu_info->page_size);
@@ -1071,56 +1210,67 @@ static int efm32x_probe(struct flash_bank *bank)
free(bank->sectors);
bank->sectors = NULL;
- if (bank->base == EFM32_FLASH_BASE) {
- bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 /
- efm32_mcu_info->page_size;
+ uint32_t page_size;
+ if (bank->base == base_address) { /* main flash */
+ page_size = efm32_mcu_info->page_size;
+ bank->num_sectors = efm32_mcu_info->flash_sz_kib * 1024 / page_size;
assert(bank->num_sectors > 0);
+ } else if (efm32_info->info.family_data->series != 2) {
+ page_size = efm32_mcu_info->page_size_ud;
+ bank->num_sectors = 1;
+ } else {
+ ret = efm32_msc_clock_enable(bank);
+ if (ret != ERROR_OK)
+ return ret;
- ret = efm32x_read_lock_data(bank);
+ uint32_t userdatasize;
+ ret = efm32_read_reg_u32(bank,
+ efm32_info->info.msc_offset->off_userdatasize,
+ &userdatasize);
if (ret != ERROR_OK) {
- LOG_ERROR("Failed to read LB data");
+ LOG_ERROR("Failed to read page size");
return ret;
}
- } else
- bank->num_sectors = 1;
- bank->size = bank->num_sectors * efm32_mcu_info->page_size;
- bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
-
- for (uint32_t i = 0; i < bank->num_sectors; i++) {
- bank->sectors[i].offset = i * efm32_mcu_info->page_size;
- bank->sectors[i].size = efm32_mcu_info->page_size;
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
+ page_size = efm32_mcu_info->page_size_ud;
+ bank->num_sectors = (userdatasize * 256) / page_size;
}
+ bank->size = bank->num_sectors * page_size;
+ bank->sectors = alloc_block_array(0, page_size, bank->num_sectors);
+ if (!bank->sectors)
+ return ERROR_FAIL;
- efm32x_info->probed[bank_index] = true;
+ efm32_info->probed[bank_index] = true;
return ERROR_OK;
}
-static int efm32x_auto_probe(struct flash_bank *bank)
+static int efm32_auto_probe(struct flash_bank *bank)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ int bank_index = efm32_get_bank_index(bank->base);
- int bank_index = efm32x_get_bank_index(bank->base);
assert(bank_index >= 0);
- if (efm32x_info->probed[bank_index])
+ if (efm32_info->probed[bank_index])
return ERROR_OK;
- return efm32x_probe(bank);
+ return efm32_probe(bank);
}
-static int efm32x_protect_check(struct flash_bank *bank)
+static int efm32_protect_check(struct flash_bank *bank)
{
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
struct target *target = bank->target;
int ret = 0;
+ if (efm32_info->info.family_data->series == 2)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- ret = efm32x_read_lock_data(bank);
+ ret = efm32_read_lock_data(bank);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read LB data");
return ret;
@@ -1129,67 +1279,72 @@ static int efm32x_protect_check(struct flash_bank *bank)
assert(bank->sectors);
for (unsigned int i = 0; i < bank->num_sectors; i++)
- bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i);
+ bank->sectors[i].is_protected = efm32_get_page_lock(bank, i);
return ERROR_OK;
}
-static int get_efm32x_info(struct flash_bank *bank, struct command_invocation *cmd)
+static int efm32_get_info(struct flash_bank *bank, struct command_invocation *cmd)
{
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ char strbuf[256];
int ret;
- ret = efm32x_read_info(bank);
+ ret = efm32_read_info(bank);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read EFM32 info");
return ret;
}
- command_print_sameline(cmd, "%s Gecko, rev %d", efm32x_info->info.family_data->name,
- efm32x_info->info.prod_rev);
+ command_print_sameline(cmd, "%s",
+ efm32_get_str_identifier(&efm32_info->info,
+ strbuf,
+ sizeof(strbuf)));
return ERROR_OK;
}
-COMMAND_HANDLER(efm32x_handle_debuglock_command)
+COMMAND_HANDLER(efm32_handle_debuglock_command)
{
- struct target *target = NULL;
-
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;
-
- struct efm32x_flash_chip *efm32x_info = bank->driver_priv;
+ int ret = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ret != ERROR_OK)
+ return ret;
- target = bank->target;
+ struct efm32_flash_chip *efm32_info = bank->driver_priv;
+ struct target *target = bank->target;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- uint32_t *ptr;
- ptr = efm32x_info->lb_page + 127;
+ uint32_t *ptr = efm32_info->lb_page + 127;
*ptr = 0;
- retval = efm32x_write_lock_data(bank);
- if (retval != ERROR_OK) {
+ ret = efm32_msc_clock_enable(bank);
+ if (ret != ERROR_OK) {
+ LOG_ERROR("Failed to enable MSC clock");
+ return ret;
+ }
+
+ ret = efm32_write_lock_data(bank);
+ if (ret != ERROR_OK) {
LOG_ERROR("Failed to write LB page");
- return retval;
+ return ret;
}
- command_print(CMD, "efm32x debug interface locked, reset the device to apply");
+ command_print(CMD, "efm32 debug interface locked, reset the device to apply");
return ERROR_OK;
}
-static const struct command_registration efm32x_exec_command_handlers[] = {
+static const struct command_registration efm32_exec_command_handlers[] = {
{
.name = "debuglock",
- .handler = efm32x_handle_debuglock_command,
+ .handler = efm32_handle_debuglock_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Lock the debug interface of the device.",
@@ -1197,29 +1352,29 @@ static const struct command_registration efm32x_exec_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-static const struct command_registration efm32x_command_handlers[] = {
+static const struct command_registration efm32_command_handlers[] = {
{
.name = "efm32",
.mode = COMMAND_ANY,
- .help = "efm32 flash command group",
+ .help = "Silicon Labs (EFM32 and EFR32) flash command group",
.usage = "",
- .chain = efm32x_exec_command_handlers,
+ .chain = efm32_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
const struct flash_driver efm32_flash = {
- .name = "efm32",
- .commands = efm32x_command_handlers,
- .flash_bank_command = efm32x_flash_bank_command,
- .erase = efm32x_erase,
- .protect = efm32x_protect,
- .write = efm32x_write,
- .read = default_flash_read,
- .probe = efm32x_probe,
- .auto_probe = efm32x_auto_probe,
- .erase_check = default_flash_blank_check,
- .protect_check = efm32x_protect_check,
- .info = get_efm32x_info,
- .free_driver_priv = efm32x_free_driver_priv,
+ .name = "efm32",
+ .commands = efm32_command_handlers,
+ .flash_bank_command = efm32_flash_bank_command,
+ .erase = efm32_erase,
+ .protect = efm32_protect,
+ .write = efm32_write,
+ .read = default_flash_read,
+ .probe = efm32_probe,
+ .auto_probe = efm32_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = efm32_protect_check,
+ .info = efm32_get_info,
+ .free_driver_priv = efm32_free_driver_priv,
};
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/fm3.c b/src/flash/nor/fm3.c
index 48f4493ab6..486f6d4353 100644
--- a/src/flash/nor/fm3.c
+++ b/src/flash/nor/fm3.c
@@ -309,8 +309,7 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first,
write_algorithm->address, 0, 100000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing flash erase programming algorithm");
- retval = ERROR_FLASH_OPERATION_FAILED;
- return retval;
+ return ERROR_FLASH_OPERATION_FAILED;
}
retval = fm3_busy_wait(target, offset, 500);
@@ -329,9 +328,8 @@ static int fm3_erase(struct flash_bank *bank, unsigned int first,
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */
-
- return retval;
+ // dummy read of FASZR
+ return target_read_u32(target, 0x40000000, &u32_dummy_read);
}
static int fm3_write_block(struct flash_bank *bank, const uint8_t *buffer,
@@ -907,8 +905,7 @@ static int fm3_chip_erase(struct flash_bank *bank)
write_algorithm->address, 0, 100000, &armv7m_info);
if (retval != ERROR_OK) {
LOG_ERROR("Error executing flash erase programming algorithm");
- retval = ERROR_FLASH_OPERATION_FAILED;
- return retval;
+ return ERROR_FLASH_OPERATION_FAILED;
}
target_free_working_area(target, write_algorithm);
@@ -925,9 +922,8 @@ static int fm3_chip_erase(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, 0x40000000, &u32_dummy_read); /* dummy read of FASZR */
-
- return retval;
+ // dummy read of FASZR
+ return target_read_u32(target, 0x40000000, &u32_dummy_read);
}
COMMAND_HANDLER(fm3_handle_chip_erase_command)
diff --git a/src/flash/nor/fm4.c b/src/flash/nor/fm4.c
index 2db79ef502..4c8f14c9ac 100644
--- a/src/flash/nor/fm4.c
+++ b/src/flash/nor/fm4.c
@@ -605,7 +605,7 @@ static bool fm4_name_match(const char *s, const char *pattern)
if (!pattern[i])
return true;
/* Use x as wildcard */
- if (pattern[i] != 'x' && tolower(s[i]) != tolower(pattern[i]))
+ if (pattern[i] != 'x' && tolower((unsigned char)s[i]) != tolower((unsigned char)pattern[i]))
return false;
i++;
}
diff --git a/src/flash/nor/hpm_xpi.c b/src/flash/nor/hpm_xpi.c
new file mode 100644
index 0000000000..3cb1f407aa
--- /dev/null
+++ b/src/flash/nor/hpm_xpi.c
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2025 hpmicro
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "imp.h"
+#include
+#include
+#include
+#include
+#include
+#include "target/riscv/program.h"
+
+#include "../../../contrib/loaders/flash/hpmicro/hpm_xpi_flash.h"
+static uint8_t flash_algo[] = {
+#include "../../../contrib/loaders/flash/hpmicro/hpm_xpi_flash.inc"
+};
+#define TIMEOUT_IN_MS (10000U)
+#define ERASE_CHIP_TIMEOUT_IN_MS (100000U)
+#define SECTOR_ERASE_TIMEOUT_IN_MS (100)
+#define TYPICAL_TIMEOUT_IN_MS (500U)
+#define BLOCK_SIZE (4096U)
+#define NOR_CFG_OPT_HEADER (0xFCF90000UL)
+
+struct hpm_flash_info {
+ uint32_t total_sz_in_bytes;
+ uint32_t sector_sz_in_bytes;
+};
+
+struct hpm_xpi_priv {
+ uint32_t io_base;
+ uint32_t header;
+ uint32_t opt0;
+ uint32_t opt1;
+ bool probed;
+};
+
+static int hpm_xpi_run_algo_flash_init(struct flash_bank *bank,
+ target_addr_t algo_entry)
+{
+ struct reg_param reg_params[6];
+ struct target *target = bank->target;
+ struct hpm_xpi_priv *xpi_priv = bank->driver_priv;
+
+ int xlen = riscv_xlen(target);
+ init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
+ init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
+ init_reg_param(®_params[2], "a2", xlen, PARAM_OUT);
+ init_reg_param(®_params[3], "a3", xlen, PARAM_OUT);
+ init_reg_param(®_params[4], "a4", xlen, PARAM_OUT);
+ init_reg_param(®_params[5], "ra", xlen, PARAM_OUT);
+ buf_set_u64(reg_params[0].value, 0, xlen, bank->base);
+ buf_set_u64(reg_params[1].value, 0, xlen, xpi_priv->header);
+ buf_set_u64(reg_params[2].value, 0, xlen, xpi_priv->opt0);
+ buf_set_u64(reg_params[3].value, 0, xlen, xpi_priv->opt1);
+ buf_set_u64(reg_params[4].value, 0, xlen, xpi_priv->io_base);
+ buf_set_u64(reg_params[5].value, 0, xlen, algo_entry + FLASH_INIT + 4);
+ int retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params,
+ algo_entry, algo_entry + FLASH_INIT + 4, TYPICAL_TIMEOUT_IN_MS, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute run algorithm: %d", retval);
+ goto err;
+ }
+
+ uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen);
+ if (stat) {
+ retval = ERROR_TARGET_FAILURE;
+ LOG_ERROR("init flash failed on target: 0x%" PRIx32, retval);
+ goto err;
+ }
+
+err:
+ for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++)
+ destroy_reg_param(®_params[k]);
+
+ return retval;
+}
+
+static int hpm_xpi_probe(struct flash_bank *bank)
+{
+ struct hpm_flash_info flash_info = {0};
+ struct working_area *data_wa = NULL;
+ struct flash_sector *sectors = NULL;
+ struct working_area *wa;
+ struct target *target = bank->target;
+
+ struct hpm_xpi_priv *xpi_priv = bank->driver_priv;
+
+ if (xpi_priv->probed) {
+ xpi_priv->probed = false;
+ bank->size = 0;
+ bank->num_sectors = 0;
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %zd-byte working area",
+ sizeof(flash_algo));
+ return retval;
+ }
+
+ retval = target_write_buffer(target, wa->address,
+ sizeof(flash_algo), flash_algo);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d",
+ wa->address, retval);
+ target_free_working_area(target, wa);
+ return retval;
+ }
+
+ retval = hpm_xpi_run_algo_flash_init(bank, wa->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to run init flash algorithm: %d", retval);
+ return retval;
+ }
+
+ if (target_alloc_working_area(target, sizeof(flash_info),
+ &data_wa) != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %zd-byte working area",
+ sizeof(flash_info));
+ goto err;
+ }
+
+ int xlen = riscv_xlen(target);
+ struct reg_param reg_params[3];
+ init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
+ init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
+ init_reg_param(®_params[2], "ra", xlen, PARAM_OUT);
+ buf_set_u64(reg_params[0].value, 0, xlen, bank->base);
+ buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address);
+ buf_set_u64(reg_params[2].value, 0, xlen, wa->address + FLASH_GET_INFO + 4);
+
+ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params,
+ wa->address + FLASH_GET_INFO, wa->address + FLASH_GET_INFO + 4, TYPICAL_TIMEOUT_IN_MS, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to run algorithm at: %d", retval);
+ goto err;
+ }
+
+ uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen);
+ if (stat) {
+ retval = ERROR_TARGET_FAILURE;
+ LOG_ERROR("flash get info failed on target: 0x%" PRIx32, retval);
+ goto err;
+ }
+
+ target_read_u32(target, data_wa->address, &flash_info.total_sz_in_bytes);
+ target_read_u32(target, data_wa->address + 4, &flash_info.sector_sz_in_bytes);
+
+ bank->size = flash_info.total_sz_in_bytes;
+ bank->num_sectors = flash_info.total_sz_in_bytes / flash_info.sector_sz_in_bytes;
+
+ /* create and fill sectors array */
+ sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+ if (!sectors) {
+ LOG_ERROR("not enough memory");
+ retval = ERROR_FAIL;
+ goto err;
+ }
+
+ for (unsigned int sector = 0; sector < bank->num_sectors; sector++) {
+ sectors[sector].offset = sector * (flash_info.sector_sz_in_bytes);
+ sectors[sector].size = flash_info.sector_sz_in_bytes;
+ sectors[sector].is_erased = -1;
+ sectors[sector].is_protected = 0;
+ }
+
+ bank->sectors = sectors;
+ xpi_priv->probed = true;
+
+err:
+ for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++)
+ destroy_reg_param(®_params[k]);
+ target_free_working_area(target, data_wa);
+ target_free_working_area(target, wa);
+ return retval;
+}
+
+static int hpm_xpi_auto_probe(struct flash_bank *bank)
+{
+ struct hpm_xpi_priv *xpi_priv = bank->driver_priv;
+ if (xpi_priv->probed)
+ return ERROR_OK;
+ return hpm_xpi_probe(bank);
+}
+
+static int hpm_xpi_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct working_area *data_wa = NULL;
+ struct working_area *wa = NULL;
+ uint32_t data_size = BLOCK_SIZE;
+ uint32_t left = count, i = 0;
+ struct target *target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %zd-byte working area",
+ sizeof(flash_algo));
+ return retval;
+ }
+
+ retval = target_write_buffer(target, wa->address,
+ sizeof(flash_algo), flash_algo);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d",
+ wa->address, retval);
+ target_free_working_area(target, wa);
+ return retval;
+ }
+
+ retval = hpm_xpi_run_algo_flash_init(bank, wa->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to run init flash algorithm: %d", retval);
+ return retval;
+ }
+
+ /* memory buffer */
+ uint32_t avail_buffer_size;
+ avail_buffer_size = target_get_working_area_avail(target);
+ if (avail_buffer_size <= 256) {
+ /* we already allocated the writing code, but failed to get a
+ * buffer, free the algorithm */
+ target_free_working_area(target, wa);
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ data_size = MIN(data_size, avail_buffer_size);
+ retval = target_alloc_working_area(target, data_size, &data_wa);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %d-byte working area", data_size);
+ return retval;
+ }
+
+ int xlen = riscv_xlen(target);
+ struct reg_param reg_params[4];
+ init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
+ init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
+ init_reg_param(®_params[2], "a2", xlen, PARAM_OUT);
+ init_reg_param(®_params[3], "a3", xlen, PARAM_OUT);
+
+ while (left) {
+ uint32_t trans_size = MIN(data_size, left);
+ retval = target_write_buffer(target, data_wa->address, trans_size, buffer + i * data_size);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write buffer to 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval);
+ goto err;
+ }
+
+ buf_set_u32(reg_params[0].value, 0, xlen, bank->base);
+ buf_set_u32(reg_params[1].value, 0, xlen, offset + i * data_size);
+ buf_set_u32(reg_params[2].value, 0, xlen, data_wa->address);
+ buf_set_u32(reg_params[3].value, 0, xlen, trans_size);
+
+ retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
+ wa->address + FLASH_PROGRAM, wa->address + FLASH_PROGRAM + 4, TIMEOUT_IN_MS, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval);
+ goto err;
+ }
+
+ uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen);
+ if (stat) {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ LOG_ERROR("flash write failed on target: 0x%" PRIx32, retval);
+ goto err;
+ }
+ i++;
+ left -= trans_size;
+ }
+
+err:
+ if (data_wa)
+ target_free_working_area(target, data_wa);
+
+ for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++)
+ destroy_reg_param(®_params[k]);
+
+ target_free_working_area(target, wa);
+ return retval;
+}
+
+static int hpm_xpi_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
+{
+ struct target *target = bank->target;
+ struct working_area *wa = NULL;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %zd-byte working area",
+ sizeof(flash_algo));
+ return retval;
+ }
+
+ retval = target_write_buffer(target, wa->address,
+ sizeof(flash_algo), flash_algo);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d",
+ wa->address, retval);
+ target_free_working_area(target, wa);
+ return retval;
+ }
+
+ retval = hpm_xpi_run_algo_flash_init(bank, wa->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to run init flash algorithm: %d", retval);
+ return retval;
+ }
+
+ LOG_DEBUG("from sector %u to sector %u", first, last);
+
+ int xlen = riscv_xlen(target);
+ struct reg_param reg_params[3];
+ init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
+ init_reg_param(®_params[1], "a1", xlen, PARAM_OUT);
+ init_reg_param(®_params[2], "a2", xlen, PARAM_OUT);
+
+ buf_set_u32(reg_params[0].value, 0, xlen, bank->base);
+ buf_set_u32(reg_params[1].value, 0, xlen, first * bank->sectors[0].size);
+ buf_set_u32(reg_params[2].value, 0, xlen, (last - first + 1) * bank->sectors[0].size);
+
+ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params,
+ wa->address + FLASH_ERASE, wa->address + FLASH_ERASE + 4,
+ SECTOR_ERASE_TIMEOUT_IN_MS * (last - first + 1), NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval);
+ goto err;
+ }
+
+ uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen);
+ if (stat) {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ LOG_ERROR("flash erase failed on target: 0x%" PRIx32, retval);
+ goto err;
+ }
+
+err:
+ target_free_working_area(target, wa);
+ for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++)
+ destroy_reg_param(®_params[k]);
+ return retval;
+}
+
+static int hpm_xpi_erase_chip(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct working_area *wa = NULL;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ int retval = target_alloc_working_area(target, sizeof(flash_algo), &wa);
+ if (retval != ERROR_OK) {
+ LOG_WARNING("Couldn't allocate %zd-byte working area",
+ sizeof(flash_algo));
+ return retval;
+ }
+
+ retval = target_write_buffer(target, wa->address,
+ sizeof(flash_algo), flash_algo);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write code to 0x%" TARGET_PRIxADDR ": %d",
+ wa->address, retval);
+ target_free_working_area(target, wa);
+ return retval;
+ }
+
+ retval = hpm_xpi_run_algo_flash_init(bank, wa->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to run init flash algorithm: %d", retval);
+ return retval;
+ }
+
+ int xlen = riscv_xlen(target);
+ struct reg_param reg_params[1];
+ init_reg_param(®_params[0], "a0", xlen, PARAM_IN_OUT);
+ buf_set_u64(reg_params[0].value, 0, xlen, bank->base);
+
+ retval = target_run_algorithm(target, 0, NULL, ARRAY_SIZE(reg_params), reg_params,
+ wa->address + FLASH_ERASE_CHIP, wa->address + FLASH_ERASE_CHIP + 4, ERASE_CHIP_TIMEOUT_IN_MS, NULL);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", wa->address, retval);
+ goto err;
+ }
+
+ uint32_t stat = buf_get_u32(reg_params[0].value, 0, xlen);
+ if (stat) {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ LOG_ERROR("flash erase chip failed on target: 0x%" PRIx32, retval);
+ goto err;
+ }
+
+err:
+ target_free_working_area(target, wa);
+ for (size_t k = 0; k < ARRAY_SIZE(reg_params); k++)
+ destroy_reg_param(®_params[k]);
+ return retval;
+}
+
+COMMAND_HANDLER(hpm_xpi_handle_erase_chip_command)
+{
+ int retval;
+ struct flash_bank *bank;
+ struct target *target;
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ target = bank->target;
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ return hpm_xpi_erase_chip(bank);
+}
+
+static const struct command_registration hpm_xpi_exec_command_handlers[] = {
+ {
+ .name = "mass_erase",
+ .handler = hpm_xpi_handle_erase_chip_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "erase entire flash device",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration hpm_xpi_command_handlers[] = {
+ {
+ .name = "hpm_xpi",
+ .mode = COMMAND_ANY,
+ .help = "hpm_xpi command group",
+ .usage = "",
+ .chain = hpm_xpi_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+FLASH_BANK_COMMAND_HANDLER(hpm_xpi_flash_bank_command)
+{
+ struct hpm_xpi_priv *xpi_priv;
+ uint32_t io_base;
+ uint32_t header;
+ uint32_t opt0;
+ uint32_t opt1;
+
+ if (CMD_ARGC < 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], io_base);
+
+ switch (CMD_ARGC) {
+ case 7:
+ header = NOR_CFG_OPT_HEADER + 1;
+ opt1 = 0;
+ opt0 = 7;
+ break;
+ case 8:
+ header = NOR_CFG_OPT_HEADER + 1;
+ opt1 = 0;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0);
+ break;
+ case 9:
+ header = NOR_CFG_OPT_HEADER + 2;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], opt0);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], opt1);
+ break;
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ xpi_priv = malloc(sizeof(struct hpm_xpi_priv));
+ if (!xpi_priv) {
+ LOG_ERROR("not enough memory");
+ return ERROR_FAIL;
+ }
+
+ bank->driver_priv = xpi_priv;
+ xpi_priv->io_base = io_base;
+ xpi_priv->header = header;
+ xpi_priv->opt0 = opt0;
+ xpi_priv->opt1 = opt1;
+ xpi_priv->probed = false;
+
+ return ERROR_OK;
+}
+
+const struct flash_driver hpm_xpi_flash = {
+ .name = "hpm_xpi",
+ .flash_bank_command = hpm_xpi_flash_bank_command,
+ .commands = hpm_xpi_command_handlers,
+ .erase = hpm_xpi_erase,
+ .write = hpm_xpi_write,
+ .read = default_flash_read,
+ .verify = default_flash_verify,
+ .probe = hpm_xpi_probe,
+ .auto_probe = hpm_xpi_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
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..266b447c04 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -1224,7 +1224,6 @@ static int kinetis_disable_wdog(struct kinetis_chip *k_chip)
COMMAND_HANDLER(kinetis_disable_wdog_handler)
{
- int result;
struct target *target = get_current_target(CMD_CTX);
struct kinetis_chip *k_chip = kinetis_get_chip(target);
@@ -1234,8 +1233,7 @@ COMMAND_HANDLER(kinetis_disable_wdog_handler)
if (CMD_ARGC > 0)
return ERROR_COMMAND_SYNTAX_ERROR;
- result = kinetis_disable_wdog(k_chip);
- return result;
+ return kinetis_disable_wdog(k_chip);
}
@@ -1589,8 +1587,7 @@ static int kinetis_read_pmstat(struct kinetis_chip *k_chip, uint8_t *pmstat)
switch (k_chip->sysmodectrlr_type) {
case KINETIS_SMC:
- result = target_read_u8(target, SMC_PMSTAT, pmstat);
- return result;
+ return target_read_u8(target, SMC_PMSTAT, pmstat);
case KINETIS_SMC32:
result = target_read_u32(target, SMC32_PMSTAT, &stat32);
@@ -2145,24 +2142,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/lpcspifi.c b/src/flash/nor/lpcspifi.c
index f950f21db7..c5db16c92a 100644
--- a/src/flash/nor/lpcspifi.c
+++ b/src/flash/nor/lpcspifi.c
@@ -445,11 +445,10 @@ static int lpcspifi_erase(struct flash_bank *bank, unsigned int first,
" Will use bulk erase instead of sector-by-sector erase.");
retval = lpcspifi_bulk_erase(bank);
- if (retval == ERROR_OK) {
- retval = lpcspifi_set_hw_mode(bank);
- return retval;
- } else
- LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
+ if (retval == ERROR_OK)
+ return lpcspifi_set_hw_mode(bank);
+
+ LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
}
if (lpcspifi_info->dev->erase_cmd == 0x00)
@@ -554,9 +553,7 @@ static int lpcspifi_erase(struct flash_bank *bank, unsigned int first,
destroy_reg_param(®_params[2]);
destroy_reg_param(®_params[3]);
- retval = lpcspifi_set_hw_mode(bank);
-
- return retval;
+ return lpcspifi_set_hw_mode(bank);
}
static int lpcspifi_protect(struct flash_bank *bank, int set,
@@ -749,8 +746,7 @@ static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
destroy_reg_param(®_params[4]);
/* Switch to HW mode before return to prompt */
- retval = lpcspifi_set_hw_mode(bank);
- return retval;
+ return lpcspifi_set_hw_mode(bank);
}
/* Return ID of flash device */
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..ac87098b3c 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";
}
}
@@ -199,9 +199,7 @@ static int msp432_exec_cmd(struct target *target, struct msp432_algo_params
return retval;
/* Write out command to target memory */
- retval = target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command);
-
- return retval;
+ return target_write_u32(target, ALGO_FLASH_COMMAND_ADDR, command);
}
static int msp432_wait_return_code(struct target *target)
@@ -219,10 +217,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 +242,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 +259,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 +293,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 */
@@ -393,9 +391,7 @@ static int msp432_init(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
- retval = msp432_wait_return_code(target);
-
- return retval;
+ return msp432_wait_return_code(target);
}
static int msp432_quit(struct flash_bank *bank)
@@ -678,8 +674,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 +747,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 +779,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 +976,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..1ba35374d9 100644
--- a/src/flash/nor/mspm0.c
+++ b/src/flash/nor/mspm0.c
@@ -77,6 +77,20 @@
#define SYSCTL_BASE 0x400AF000
#define SYSCTL_SECCFG_SECSTATUS (SYSCTL_BASE + 0x00003048)
+/*
+ * SYSCTL SOCLOCK MCLKCFG register (offset 0x1104 from SYSCTL_BASE).
+ * Used for the FLASH_ERR_01 workaround: accessing FACTORYREGION while MCLK
+ * is sourced from HSCLK (SYSPLL/HFXT, implying MCLK > 32 MHz) with flash
+ * wait-state 2 active causes a hard fault on MSPM0G devices. The flash
+ * controller enforces its wait-state timing for all AHB masters, including
+ * the DAP AHB-AP used by OpenOCD. Temporarily switching MCLK to SYSOSC
+ * (≤ 32 MHz on all MSPM0 variants) before reading FACTORYREGION avoids this.
+ */
+#define SYSCTL_MCLKCFG (SYSCTL_BASE + 0x00001104)
+#define SYSCTL_MCLKCFG_USEHSCLK BIT(16)
+#define SYSCTL_MCLKCFG_FLASHWAIT_MASK GENMASK(11, 8)
+#define SYSCTL_MCLKCFG_FLASHWAIT_2 (2U << 8)
+
/* TI manufacturer ID */
#define TI_MANUFACTURER_ID 0x17
@@ -128,6 +142,7 @@ struct mspm0_family_info {
/* https://www.ti.com/lit/ds/symlink/mspm0l1346.pdf Table 8-13 and so on */
static const struct mspm0_part_info mspm0l_parts[] = {
+ /* MSPM0L110x */
{ "MSPM0L1105TDGS20R", 0x51DB, 0x16 },
{ "MSPM0L1105TDGS28R", 0x51DB, 0x83 },
{ "MSPM0L1105TDYYR", 0x51DB, 0x54 },
@@ -138,6 +153,7 @@ static const struct mspm0_part_info mspm0l_parts[] = {
{ "MSPM0L1106TDYYR", 0x5552, 0x9D },
{ "MSPM0L1106TRGER", 0x5552, 0x90 },
{ "MSPM0L1106TRHBR", 0x5552, 0x53 },
+ /* MSPM0L130x (covers MSPM0L134x) */
{ "MSPM0L1303SRGER", 0xef0, 0x17 },
{ "MSPM0L1303TRGER", 0xef0, 0xe2 },
{ "MSPM0L1304QDGS20R", 0xd717, 0x91 },
@@ -188,20 +204,24 @@ static const struct mspm0_part_info mspm0l_parts[] = {
{ "MSPM0L1346TDGS28R", 0xf2b5, 0xef },
};
-/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-20 */
-static const struct mspm0_part_info mspm0g_parts[] = {
+/* https://www.ti.com/lit/ds/symlink/mspm0g3506.pdf Table 8-22 */
+static const struct mspm0_part_info mspm0g_parts_bb88[] = {
+ /* MSPM0G110x */
{ "MSPM0G1105TPTR", 0x8934, 0xD },
{ "MSPM0G1105TRGZR", 0x8934, 0xFE },
{ "MSPM0G1106TPMR", 0x477B, 0xD4 },
{ "MSPM0G1106TPTR", 0x477B, 0x71 },
{ "MSPM0G1106TRGZR", 0x477B, 0xBB },
- { "MSPM0G1106TRHBR", 0x477B, 0x0 },
+ { "MSPM0G1106TRHBR", 0x477B, 0x01 },
+ { "MSPM0G1106TYCJR", 0x477B, 0x09 },
{ "MSPM0G1107TDGS28R", 0x807B, 0x82 },
{ "MSPM0G1107TPMR", 0x807B, 0xB3 },
{ "MSPM0G1107TPTR", 0x807B, 0x32 },
{ "MSPM0G1107TRGER", 0x807B, 0x79 },
{ "MSPM0G1107TRGZR", 0x807B, 0x20 },
{ "MSPM0G1107TRHBR", 0x807B, 0xBC },
+ { "MSPM0G1107TYCJR", 0x807B, 0x7A },
+ /* MSPM0G150x */
{ "MSPM0G1505SDGS28R", 0x13C4, 0x73 },
{ "MSPM0G1505SPMR", 0x13C4, 0x53 },
{ "MSPM0G1505SPTR", 0x13C4, 0x3E },
@@ -213,11 +233,16 @@ static const struct mspm0_part_info mspm0g_parts[] = {
{ "MSPM0G1506SRGER", 0x5AE0, 0x67 },
{ "MSPM0G1506SRGZR", 0x5AE0, 0x75 },
{ "MSPM0G1506SRHBR", 0x5AE0, 0x57 },
+ { "MSPM0G1506SRPTR", 0x5AE0, 0x36 },
+ { "MSPM0G1506SYCJR", 0x5AE0, 0x9E },
{ "MSPM0G1507SDGS28R", 0x2655, 0x6D },
{ "MSPM0G1507SPMR", 0x2655, 0x97 },
+ { "MSPM0G1507SPTR", 0x2655, 0x2E },
{ "MSPM0G1507SRGER", 0x2655, 0x83 },
{ "MSPM0G1507SRGZR", 0x2655, 0xD3 },
{ "MSPM0G1507SRHBR", 0x2655, 0x4D },
+ { "MSPM0G1507SYCJR", 0x2655, 0x65 },
+ /* MSPM0G310x */
{ "MSPM0G3105SDGS20R", 0x4749, 0x21 },
{ "MSPM0G3105SDGS28R", 0x4749, 0xDD },
{ "MSPM0G3105SRHBR", 0x4749, 0xBE },
@@ -227,12 +252,12 @@ static const struct mspm0_part_info mspm0g_parts[] = {
{ "MSPM0G3107SDGS20R", 0xAB39, 0x5C },
{ "MSPM0G3107SDGS28R", 0xAB39, 0xCC },
{ "MSPM0G3107SRHBR", 0xAB39, 0xB7 },
+ /* MSPM0G350x */
{ "MSPM0G3505SDGS28R", 0xc504, 0x8e },
{ "MSPM0G3505SPMR", 0xc504, 0x1d },
{ "MSPM0G3505SPTR", 0xc504, 0x93 },
{ "MSPM0G3505SRGZR", 0xc504, 0xc7 },
{ "MSPM0G3505SRHBR", 0xc504, 0xe7 },
- { "MSPM0G3505TDGS28R", 0xc504, 0xdf },
{ "MSPM0G3506SDGS28R", 0x151f, 0x8 },
{ "MSPM0G3506SPMR", 0x151f, 0xd4 },
{ "MSPM0G3506SPTR", 0x151f, 0x39 },
@@ -243,27 +268,109 @@ static const struct mspm0_part_info mspm0g_parts[] = {
{ "MSPM0G3507SPTR", 0xae2d, 0x3f },
{ "MSPM0G3507SRGZR", 0xae2d, 0xf7 },
{ "MSPM0G3507SRHBR", 0xae2d, 0x4c },
- { "M0G3107QPMRQ1", 0x4e2f, 0x51 },
- { "M0G3107QPTRQ1", 0x4e2f, 0xc7},
- { "M0G3107QRGZRQ1", 0x4e2f, 0x8a },
- { "M0G3107QRHBRQ1", 0x4e2f, 0x9a},
- { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5},
- { "M0G3107QDGS28RQ1", 0x4e2f, 0x67},
- { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd},
- { "M0G3106QPMRQ1", 0x54C7, 0x08},
- { "M0G3105QDGS32RQ1", 0x1349, 0x08},
- { "M0G3106QPTRQ1", 0x54C7, 0x3F},
- { "M0G3105QDGS28RQ1", 0x1349, 0x1B},
- { "M0G3106QRGZRQ1", 0x94AD, 0xE6},
+ /* MSPM0G310x-Q1 */
{ "M0G3105QDGS20RQ1", 0x1349, 0xFB},
- { "M0G3106QRHBRQ1", 0x94AD, 0x20},
- { "M0G3106QDGS32RQ1", 0x94AD, 0x8D},
- { "M0G3106QDGS28RQ1", 0x94AD, 0x03},
- { "M0G3106QDGS20RQ1", 0x94AD, 0x6F},
+ { "M0G3105QDGS28RQ1", 0x1349, 0x1B},
+ { "M0G3105QDGS32RQ1", 0x1349, 0x08},
{ "M0G3105QPMRQ1", 0x1349, 0xD0},
{ "M0G3105QPTRQ1", 0x1349, 0xEF},
{ "M0G3105QRGZRQ1", 0x1349, 0x70},
{ "M0G3105QRHBRQ1", 0x1349, 0x01},
+ { "M0G3106QDGS20RQ1", 0x94AD, 0x6F},
+ { "M0G3106QDGS28RQ1", 0x94AD, 0x03},
+ { "M0G3106QDGS32RQ1", 0x94AD, 0x8D},
+ { "M0G3106QPMRQ1", 0x54C7, 0x08},
+ { "M0G3106QPTRQ1", 0x54C7, 0x3F},
+ { "M0G3106QRGZRQ1", 0x94AD, 0xE6},
+ { "M0G3106QRHBRQ1", 0x94AD, 0x20},
+ { "M0G3107QDGS20RQ1", 0x4e2f, 0xfd},
+ { "M0G3107QDGS28RQ1", 0x4e2f, 0x67},
+ { "M0G3107QDGS28RQ1", 0x4e2f, 0xd5},
+ { "M0G3107QPMRQ1", 0x4e2f, 0x51 },
+ { "M0G3107QPTRQ1", 0x4e2f, 0xc7},
+ { "M0G3107QRGZRQ1", 0x4e2f, 0x8a },
+ { "M0G3107QRHBRQ1", 0x4e2f, 0x9a},
+ /* MSPM0G350x-Q1 */
+ { "M0G3505QDGS28RQ1", 0x704E, 0x4C },
+ { "M0G3505QDGS32RQ1", 0x704E, 0x7F },
+ { "M0G3505QPMRQ1", 0x704E, 0x7B },
+ { "M0G3505QPTRQ1", 0x704E, 0x9C },
+ { "M0G3505QRGZRQ1", 0x704E, 0xC9 },
+ { "M0G3505QRHBRQ1", 0x704E, 0x26 },
+ { "M0G3506QDGS28RQ1", 0xEE12, 0x71 },
+ { "M0G3506QDGS32RQ1", 0xEE12, 0x6C },
+ { "M0G3506QPMRQ1", 0xEE12, 0x7B },
+ { "M0G3506QPTRQ1", 0xEE12, 0x5A },
+ { "M0G3506QRGZRQ1", 0xEE12, 0xD2 },
+ { "M0G3506QRHBRQ1", 0xEE12, 0xFC },
+ { "M0G3507QDGS28RQ1", 0x34E0, 0xEA },
+ { "M0G3507QDGS32RQ1", 0x34E0, 0xF6 },
+ { "M0G3507QPMRQ1", 0x34E0, 0x26 },
+ { "M0G3507QRGZRQ1", 0x34E0, 0xC5 },
+ { "M0G3507QRHBRQ1", 0x34E0, 0xAC },
+ { "M0G3507QSPTRQ1", 0x34E0, 0xE3 },
+};
+
+/* https://www.ti.com/lit/gpn/mspm0g1518 Table 8-21 and so on */
+static const struct mspm0_part_info mspm0g_parts_bba9[] = {
+ /* MSPM0Gx51x */
+ { "MSPM0G1518SPMR", 0x2120, 0x13 },
+ { "MSPM0G1518SPNR", 0x2120, 0x16 },
+ { "MSPM0G1518SPTR", 0x2120, 0x12 },
+ { "MSPM0G1518SPZR", 0x2120, 0x18 },
+ { "MSPM0G1518SRGZR", 0x2120, 0x11 },
+ { "MSPM0G1518SRHBR", 0x2120, 0x10 },
+ { "MSPM0G1518SZAWR", 0x2120, 0x19 },
+ { "MSPM0G1519SPMR", 0x2407, 0x13 },
+ { "MSPM0G1519SPNR", 0x2407, 0x16 },
+ { "MSPM0G1519SPTR", 0x2407, 0x12 },
+ { "MSPM0G1519SPZR", 0x2407, 0x18 },
+ { "MSPM0G1519SRGZR", 0x2407, 0x11 },
+ { "MSPM0G1519SRHBR", 0x2407, 0x10 },
+ { "MSPM0G1519SZAWR", 0x2407, 0x19 },
+ { "MSPM0G3518SPMR", 0x1205, 0x13 },
+ { "MSPM0G3518SPNR", 0x1205, 0x15 },
+ { "MSPM0G3518SPTR", 0x1205, 0x12 },
+ { "MSPM0G3518SPZR", 0x1205, 0x16 },
+ { "MSPM0G3518SRGZR", 0x1205, 0x11 },
+ { "MSPM0G3518SRHBR", 0x1205, 0x10 },
+ { "MSPM0G3518SZAWR", 0x1205, 0x19 },
+ { "MSPM0G3519SPMR", 0x1508, 0x13 },
+ { "MSPM0G3519SPNR", 0x1508, 0x15 },
+ { "MSPM0G3519SPTR", 0x1508, 0x12 },
+ { "MSPM0G3519SPZR", 0x1508, 0x16 },
+ { "MSPM0G3519SRGZR", 0x1508, 0x11 },
+ { "MSPM0G3519SRHBR", 0x1508, 0x10 },
+ { "MSPM0G3519SZAWR", 0x1508, 0x19 },
+ /* MSPM0G351x-Q1 */
+ { "M0G3518QPMRQ1", 0x4009, 0x13 },
+ { "M0G3518QPNRQ1", 0x4009, 0x14 },
+ { "M0G3518QPTRQ1", 0x4009, 0x12 },
+ { "M0G3518QPZRQ1", 0x4009, 0x15 },
+ { "M0G3518QRGZRQ1", 0x4009, 0x11 },
+ { "M0G3518QRHBRQ1", 0x4009, 0x10 },
+ { "M0G3519QPMRQ1", 0x3512, 0x13 },
+ { "M0G3519AQPMRQ1", 0x3512, 0x16 },
+ { "M0G3519QPNRQ1", 0x3512, 0x14 },
+ { "M0G3519QPTRQ1", 0x3512, 0x12 },
+ { "M0G3519QPZRQ1", 0x3512, 0x15 },
+ { "M0G3519QRGZRQ1", 0x3512, 0x11 },
+ { "M0G3519QRHBRQ1", 0x3512, 0x10 },
+ /* MSPM0G352x-Q1 */
+ { "M0G3529QPMRQ1", 0xF8D1, 0x13 },
+};
+
+/* https://www.ti.com/lit/gpn/mspm0g5187 Table 8-24*/
+static const struct mspm0_part_info mspm0g_parts_bbbc[] = {
+ /* MSPM0G5187 */
+ { "MSPM0G5187S28YCJR", 0x5610, 0x18 },
+ { "MSPM0G5187SDGS20R", 0x5610, 0x16 },
+ { "MSPM0G5187SPMR", 0x5610, 0x10 },
+ { "MSPM0G5187SPTR", 0x5610, 0x11 },
+ { "MSPM0G5187SRHBR", 0x5610, 0x13 },
+ { "MSPM0G5187SRGER", 0x5610, 0x14 },
+ { "MSPM0G5187SRGZR", 0x5610, 0x12 },
+ { "MSPM0G5187SRUYR", 0x5610, 0x17 },
};
/* https://www.ti.com/lit/gpn/mspm0c1104 Table 8-12 and so on */
@@ -305,7 +412,9 @@ static const struct mspm0_part_info mspm0lx22x_parts[] = {
static const struct mspm0_family_info mspm0_finf[] = {
{ "MSPM0L", 0xbb82, ARRAY_SIZE(mspm0l_parts), mspm0l_parts },
{ "MSPM0Lx22x", 0xbb9f, ARRAY_SIZE(mspm0lx22x_parts), mspm0lx22x_parts },
- { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts), mspm0g_parts },
+ { "MSPM0G", 0xbb88, ARRAY_SIZE(mspm0g_parts_bb88), mspm0g_parts_bb88 },
+ { "MSPM0G", 0xbba9, ARRAY_SIZE(mspm0g_parts_bba9), mspm0g_parts_bba9 },
+ { "MSPM0G", 0xbbbc, ARRAY_SIZE(mspm0g_parts_bbbc), mspm0g_parts_bbbc },
{ "MSPM0C", 0xbba1, ARRAY_SIZE(mspm0c_parts), mspm0c_parts },
};
@@ -379,30 +488,94 @@ static int mspm0_read_part_info(struct flash_bank *bank)
struct target *target = bank->target;
const struct mspm0_family_info *minfo = NULL;
+ /*
+ * FLASH_ERR_01 workaround: on MSPM0G devices the flash controller
+ * rejects any bus-master access to FACTORYREGION when MCLK is sourced
+ * from HSCLK (SYSPLL/HFXT) and flash wait-state 2 is active
+ * (required for MCLK > 32 MHz). This applies to DAP AHB-AP reads too,
+ * not just CPU accesses. If both conditions are true, temporarily
+ * switch MCLK back to SYSOSC (≤ 32 MHz on every MSPM0 variant) for the
+ * FACTORYREGION reads and restore afterwards. The SYSCTL_MCLKCFG write
+ * does not take place on L/C parts: USEHSCLK is never set there because
+ * those cores do not exceed 32 MHz.
+ */
+ uint32_t saved_mclkcfg = 0;
+ bool mclk_switched = false;
+ uint32_t mclkcfg;
+ int retval = target_read_u32(target, SYSCTL_MCLKCFG, &mclkcfg);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read SYSCTL_MCLKCFG to check FLASH_ERR_01");
+ return retval;
+ }
+
+ if ((mclkcfg & SYSCTL_MCLKCFG_USEHSCLK) &&
+ ((mclkcfg & SYSCTL_MCLKCFG_FLASHWAIT_MASK) == SYSCTL_MCLKCFG_FLASHWAIT_2)) {
+ saved_mclkcfg = mclkcfg;
+ retval = target_write_u32(target, SYSCTL_MCLKCFG,
+ mclkcfg & ~SYSCTL_MCLKCFG_USEHSCLK);
+ if (retval == ERROR_OK) {
+ mclk_switched = true;
+ /*
+ * Read back MCLKCFG to flush the write, then add an
+ * explicit delay to allow the MCLK source mux to fully
+ * settle on SYSOSC before the flash controller timing is
+ * used for FACTORYREGION accesses.
+ */
+ uint32_t dummy;
+ retval = target_read_u32(target, SYSCTL_MCLKCFG, &dummy);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: "
+ "readback flush failed");
+ goto restore_mclk;
+ }
+ alive_sleep(1);
+ LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround ACTIVE: "
+ "Lowering MCLK before FACTORYREGION read");
+ } else {
+ LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: "
+ "could not lower MCLK before FACTORYREGION read");
+ }
+ }
+
/* Read and parse chip identification and flash version register */
uint32_t did;
- int retval = target_read_u32(target, MSPM0_DID, &did);
+ retval = target_read_u32(target, MSPM0_DID, &did);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read device ID");
- return retval;
+ goto restore_mclk;
}
retval = target_read_u32(target, MSPM0_TRACEID, &mspm0_info->traceid);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read trace ID");
- return retval;
+ goto restore_mclk;
}
uint32_t userid;
retval = target_read_u32(target, MSPM0_USERID, &userid);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read user ID");
- return retval;
+ goto restore_mclk;
}
uint32_t flashram;
retval = target_read_u32(target, MSPM0_SRAMFLASH, &flashram);
if (retval != ERROR_OK) {
LOG_ERROR("Failed to read sramflash register");
- return retval;
+ goto restore_mclk;
}
+
+restore_mclk:
+ if (mclk_switched) {
+ int retval2 = target_write_u32(target, SYSCTL_MCLKCFG, saved_mclkcfg);
+ if (retval2 != ERROR_OK) {
+ LOG_ERROR("MSPM0: FLASH_ERR_01 workaround: "
+ "could not restore MCLK after FACTORYREGION read");
+ return retval2;
+ }
+ LOG_DEBUG("MSPM0: FLASH_ERR_01 workaround: "
+ "restored MCLK after FACTORYREGION read");
+ }
+ if (retval != ERROR_OK)
+ return retval;
+
uint32_t flashdesc;
retval = target_read_u32(target, FCTL_REG_DESC, &flashdesc);
if (retval != ERROR_OK) {
@@ -429,7 +602,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 +910,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) {
@@ -1062,6 +1235,19 @@ static int mspm0_probe(struct flash_bank *bank)
mspm0_info->protect_reg_count = 1;
break;
case MSPM0_FLASH_BASE_MAIN:
+ if (!mspm0_info->main_flash_size_kb) {
+ /*
+ * FACTORYREGION was unreadable when this bank was probed
+ * (e.g. device not yet halted, MCLK still at HSCLK on
+ * first examine). Clear did so the next auto_probe call
+ * re-runs mspm0_read_part_info with the target in a known
+ * state.
+ */
+ LOG_WARNING("MSPM0: main flash size is 0 — "
+ "FACTORYREGION data incomplete, scheduling re-probe");
+ mspm0_info->did = 0;
+ return ERROR_FLASH_BANK_NOT_PROBED;
+ }
bank->size = (mspm0_info->main_flash_size_kb * 1024);
bank->num_sectors = bank->size / mspm0_info->sector_size;
/*
diff --git a/src/flash/nor/niietcm4.c b/src/flash/nor/niietcm4.c
index aaf0726550..4251d13dfe 100644
--- a/src/flash/nor/niietcm4.c
+++ b/src/flash/nor/niietcm4.c
@@ -1165,10 +1165,8 @@ static int niietcm4_erase(struct flash_bank *bank, unsigned int first,
return ERROR_TARGET_NOT_HALTED;
}
- if ((first == 0) && (last == (bank->num_sectors - 1))) {
- retval = niietcm4_mass_erase(bank);
- return retval;
- }
+ if (first == 0 && last == (bank->num_sectors - 1))
+ return niietcm4_mass_erase(bank);
/* chose between main bootflash and info bootflash */
uint32_t flash_cmd, flash_addr;
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 5cb552aa94..b92bb5b7cb 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -796,8 +796,8 @@ static int nrf5_read_ficr_more_info(struct nrf5_info *chip)
if (res != ERROR_OK)
return res;
- res = target_read_u32(target, ficr_base + ficr_offsets->info_flash, &chip->ficr_info.flash);
- return res;
+ return target_read_u32(target, ficr_base + ficr_offsets->info_flash,
+ &chip->ficr_info.flash);
}
/* nRF51 series only */
@@ -1121,8 +1121,7 @@ static int nrf5_erase_page(struct flash_bank *bank,
return res;
}
- res = nrf5_wait_for_nvmc(chip);
- return res;
+ return nrf5_wait_for_nvmc(chip);
}
/* Start a low level flash write for the specified region */
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/psoc5lp.c b/src/flash/nor/psoc5lp.c
index e8c9019505..e51c1cb1c0 100644
--- a/src/flash/nor/psoc5lp.c
+++ b/src/flash/nor/psoc5lp.c
@@ -237,8 +237,7 @@ static int psoc5lp_get_device_id(struct target *target, uint32_t *id)
retval = target_read_u32(target, PANTHER_DEVICE_ID, id); /* dummy read */
if (retval != ERROR_OK)
return retval;
- retval = target_read_u32(target, PANTHER_DEVICE_ID, id);
- return retval;
+ return target_read_u32(target, PANTHER_DEVICE_ID, id);
}
static int psoc5lp_find_device(struct target *target,
@@ -297,8 +296,7 @@ static int psoc5lp_spc_write_opcode(struct target *target, uint8_t opcode)
retval = target_write_u8(target, SPC_CPU_DATA, SPC_KEY2 + opcode);
if (retval != ERROR_OK)
return retval;
- retval = target_write_u8(target, SPC_CPU_DATA, opcode);
- return retval;
+ return target_write_u8(target, SPC_CPU_DATA, opcode);
}
static void psoc5lp_spc_write_opcode_buffer(struct target *target,
@@ -1081,17 +1079,18 @@ static int psoc5lp_erase_check(struct flash_bank *bank)
bool fast_check = true;
for (unsigned int i = 0; i < num_sectors; ) {
+ unsigned int checked;
retval = armv7m_blank_check_memory(target,
block_array + i, num_sectors - i,
- bank->erased_value);
- if (retval < 1) {
+ bank->erased_value, &checked);
+ if (retval != ERROR_OK) {
/* Run slow fallback if the first run gives no result
* otherwise use possibly incomplete results */
if (i == 0)
fast_check = false;
break;
}
- i += retval; /* add number of blocks done this round */
+ i += checked; /* add number of blocks done this round */
}
if (fast_check) {
diff --git a/src/flash/nor/psoc6.c b/src/flash/nor/psoc6.c
index 662910aa04..b53be7847b 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";
}
}
@@ -868,9 +868,7 @@ COMMAND_HANDLER(psoc6_handle_mass_erase_command)
if (hr != ERROR_OK)
return hr;
- hr = psoc6_erase(bank, 0, bank->num_sectors - 1);
-
- return hr;
+ return psoc6_erase(bank, 0, bank->num_sectors - 1);
}
/** ***********************************************************************************************
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/read_only.c b/src/flash/nor/read_only.c
new file mode 100644
index 0000000000..5459d9b3a2
--- /dev/null
+++ b/src/flash/nor/read_only.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * Copyright (C) 2019 by Tomas Vanek
+ *
+ * To declare a read-only region for GDB memory map.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+
+FLASH_BANK_COMMAND_HANDLER(rom_bank_command)
+{
+ bank->read_only = true;
+ return ERROR_OK;
+}
+
+static int rom_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
+{
+ LOG_ERROR("Erase of read-only memory refused");
+ return ERROR_FAIL;
+}
+
+static int rom_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ LOG_ERROR("Write to read-only memory refused");
+ return ERROR_FAIL;
+}
+
+static int rom_probe(struct flash_bank *bank)
+{
+ return ERROR_OK;
+}
+
+const struct flash_driver read_only_flash = {
+ .name = "read_only",
+ .flash_bank_command = rom_bank_command,
+ .erase = rom_erase,
+ .write = rom_write,
+ .read = default_flash_read,
+ .probe = rom_probe,
+ .auto_probe = rom_probe,
+ .erase_check = default_flash_blank_check,
+
+ // ROM driver doesn't set driver_priv, free(NULL) makes no harm
+ .free_driver_priv = default_flash_free_driver_priv,
+};
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..f1ca5f0e5e 100644
--- a/src/flash/nor/spi.c
+++ b/src/flash/nor/spi.c
@@ -125,6 +125,8 @@ const struct flash_device flash_devices[] = {
FLASH_ID("micron mt25ql01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021ba20, 0x100, 0x10000, 0x8000000),
FLASH_ID("micron mt25qu01", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0021bb20, 0x100, 0x10000, 0x8000000),
FLASH_ID("micron mt25ql02", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0022ba20, 0x100, 0x10000, 0x10000000),
+ FLASH_ID("bsemi by25q16es", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x00154068, 0x100, 0x10000, 0x200000),
+ FLASH_ID("boya by25q128as", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x00184068, 0x100, 0x10000, 0x1000000),
FLASH_ID("win w25q80bv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000),
FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540ef, 0x100, 0x10000, 0x200000),
FLASH_ID("win w25q16jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001570ef, 0x100, 0x10000, 0x200000), /* QPI / DTR */
@@ -184,6 +186,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/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 3bafde56f8..5276d323c9 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -250,6 +250,10 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
return ERROR_COMMAND_SYNTAX_ERROR;
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
+ if (!stm32x_info) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
bank->driver_priv = stm32x_info;
stm32x_info->probed = false;
diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c
index c02fae992c..c91ab51602 100644
--- a/src/flash/nor/stm32h7x.c
+++ b/src/flash/nor/stm32h7x.c
@@ -9,71 +9,127 @@
#include "imp.h"
#include
+#include
#include
#include
-
/* Erase time can be as high as 1000ms, 10x this and it's toast... */
#define FLASH_ERASE_TIMEOUT 10000
#define FLASH_WRITE_TIMEOUT 5
+#define MASS_ERASE_TIMEOUT 30000
+
+static const uint8_t stm32h7_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc"
+};
+
+static const uint8_t stm32h7rs_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/stm32/stm32h7rx.inc"
+};
+
+enum stm32h7_flash_reg_index {
+ STM32_FLASH_ACR_INDEX,
+ STM32_FLASH_KEYR_INDEX,
+ STM32_FLASH_OPTKEYR_INDEX,
+ STM32_FLASH_SR_INDEX,
+ STM32_FLASH_CR_INDEX,
+ STM32_FLASH_ICR_CCR_INDEX,
+ STM32_FLASH_OPTCR_INDEX,
+ STM32_FLASH_OPTSR_INDEX,
+ STM32_FLASH_OPTSR_CUR_INDEX,
+ STM32_FLASH_OPTSR_PRG_INDEX,
+ STM32_FLASH_OPTCCR_INDEX,
+ STM32_FLASH_WPSN_CUR_INDEX,
+ STM32_FLASH_WPSN_PRG_INDEX,
+ STM32_FLASH_ISR_INDEX,
+ STM32_FLASH_REG_INDEX_NUM,
+};
/* RM 433 */
/* Same Flash registers for both banks, */
/* access depends on Flash Base address */
-#define FLASH_ACR 0x00
-#define FLASH_KEYR 0x04
-#define FLASH_OPTKEYR 0x08
-#define FLASH_CR 0x0C
-#define FLASH_SR 0x10
-#define FLASH_CCR 0x14
-#define FLASH_OPTCR 0x18
-#define FLASH_OPTSR_CUR 0x1C
-#define FLASH_OPTSR_PRG 0x20
-#define FLASH_OPTCCR 0x24
-#define FLASH_WPSN_CUR 0x38
-#define FLASH_WPSN_PRG 0x3C
+static const uint32_t stm32h7_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+ [STM32_FLASH_ACR_INDEX] = 0x00,
+ [STM32_FLASH_KEYR_INDEX] = 0x04,
+ [STM32_FLASH_OPTKEYR_INDEX] = 0x08,
+ [STM32_FLASH_SR_INDEX] = 0x10,
+ [STM32_FLASH_CR_INDEX] = 0x0C,
+ [STM32_FLASH_ICR_CCR_INDEX] = 0x14,
+ [STM32_FLASH_OPTCR_INDEX] = 0x18,
+ [STM32_FLASH_OPTSR_CUR_INDEX] = 0x1C,
+ [STM32_FLASH_OPTSR_PRG_INDEX] = 0x20,
+ [STM32_FLASH_OPTCCR_INDEX] = 0x24,
+ [STM32_FLASH_WPSN_CUR_INDEX] = 0x38,
+ [STM32_FLASH_WPSN_PRG_INDEX] = 0x3C
+};
+static const uint32_t stm32h7rs_flash_regs[STM32_FLASH_REG_INDEX_NUM] = {
+ [STM32_FLASH_ACR_INDEX] = 0x00,
+ [STM32_FLASH_KEYR_INDEX] = 0x04,
+ [STM32_FLASH_OPTKEYR_INDEX] = 0x100,
+ [STM32_FLASH_SR_INDEX] = 0x14,
+ [STM32_FLASH_CR_INDEX] = 0x10,
+ [STM32_FLASH_ICR_CCR_INDEX] = 0x28,
+ [STM32_FLASH_OPTCR_INDEX] = 0x104,
+ [STM32_FLASH_OPTSR_INDEX] = 0x10C,
+ [STM32_FLASH_ISR_INDEX] = 0x24,
+};
/* FLASH_CR register bits */
-#define FLASH_LOCK (1 << 0)
-#define FLASH_PG (1 << 1)
-#define FLASH_SER (1 << 2)
-#define FLASH_BER (1 << 3)
+#define FLASH_LOCK BIT(0)
+#define FLASH_PG BIT(1)
+#define FLASH_SER BIT(2)
+#define FLASH_BER BIT(3)
#define FLASH_PSIZE_8 (0 << 4)
#define FLASH_PSIZE_16 (1 << 4)
#define FLASH_PSIZE_32 (2 << 4)
#define FLASH_PSIZE_64 (3 << 4)
-#define FLASH_FW (1 << 6)
-#define FLASH_START (1 << 7)
+#define FLASH_FW BIT(6)
+#define FLASH_START BIT(7)
+
+/* FLASH_ISR register bits for H7RS */
+#define FLASH_CRCRDERRF BIT(28) /* CRC read error flag */
+#define FLASH_CRCENDF BIT(27) /* CRC end flag */
+#define FLASH_DBECCERRF BIT(26) /* ECC double error flag */
+#define FLASH_SNECCERRF BIT(25) /* ECC single error flag */
+#define FLASH_RDSERRF BIT(24) /* Read security error flag */
+#define FLASH_INCERRF BIT(21) /* Inconsistency error flag */
+#define FLASH_OBLERRF BIT(20) /* Option byte loading error flag */
+#define FLASH_STRBERRF BIT(19) /* Strobe error flag */
+#define FLASH_PGSERRF BIT(18) /* Programming sequence error flag */
+#define FLASH_WRPERRF BIT(17) /* Write protection error flag */
+#define FLASH_EOPF BIT(16) /* End-of-program flag */
/* FLASH_SR register bits */
-#define FLASH_BSY (1 << 0) /* Operation in progress */
-#define FLASH_QW (1 << 2) /* Operation queue in progress */
-#define FLASH_WRPERR (1 << 17) /* Write protection error */
-#define FLASH_PGSERR (1 << 18) /* Programming sequence error */
-#define FLASH_STRBERR (1 << 19) /* Strobe error */
-#define FLASH_INCERR (1 << 21) /* Inconsistency error */
-#define FLASH_OPERR (1 << 22) /* Operation error */
-#define FLASH_RDPERR (1 << 23) /* Read Protection error */
-#define FLASH_RDSERR (1 << 24) /* Secure Protection error */
-#define FLASH_SNECCERR (1 << 25) /* Single ECC error */
-#define FLASH_DBECCERR (1 << 26) /* Double ECC error */
+#define FLASH_BSY BIT(0) /* Operation in progress */
+#define FLASH_QW BIT(2) /* Operation queue in progress */
+#define FLASH_WRPERR BIT(17) /* Write protection error */
+#define FLASH_PGSERR BIT(18) /* Programming sequence error */
+#define FLASH_STRBERR BIT(19) /* Strobe error */
+#define FLASH_INCERR BIT(21) /* Inconsistency error */
+#define FLASH_OPERR BIT(22) /* Operation error */
+#define FLASH_RDPERR BIT(23) /* Read Protection error */
+#define FLASH_RDSERR BIT(24) /* Secure Protection error */
+#define FLASH_SNECCERR BIT(25) /* Single ECC error */
+#define FLASH_DBECCERR BIT(26) /* Double ECC error */
#define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \
FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR)
+/* Possible errors for H7RS */
+#define FLASH_ERROR_H7RS (FLASH_CRCRDERRF | FLASH_CRCENDF | FLASH_DBECCERRF | FLASH_SNECCERRF | FLASH_RDSERRF | \
+ FLASH_INCERRF | FLASH_OBLERRF | FLASH_STRBERRF | FLASH_PGSERRF | FLASH_WRPERRF | FLASH_EOPF)
/* FLASH_OPTCR register bits */
-#define OPT_LOCK (1 << 0)
-#define OPT_START (1 << 1)
+#define OPT_LOCK BIT(0)
+#define OPT_START BIT(1)
/* FLASH_OPTSR register bits */
-#define OPT_BSY (1 << 0)
+#define OPT_BSY BIT(0)
#define OPT_RDP_POS 8
#define OPT_RDP_MASK (0xff << OPT_RDP_POS)
-#define OPT_OPTCHANGEERR (1 << 30)
+#define OPT_OPTCHANGEERR BIT(30)
/* FLASH_OPTCCR register bits */
-#define OPT_CLR_OPTCHANGEERR (1 << 30)
+#define OPT_CLR_OPTCHANGEERR BIT(30)
/* register unlock keys */
#define KEY1 0x45670123
@@ -93,19 +149,20 @@
#define DEVID_STM32H74_H75XX 0x450
#define DEVID_STM32H7A_H7BXX 0x480
#define DEVID_STM32H72_H73XX 0x483
+#define DEVID_STM32H7R_H7SXX 0x485
-struct stm32h7x_rev {
+struct stm32h7_rev {
uint16_t rev;
const char *str;
};
-/* stm32h7x_part_info permits the store each device information and specificities.
+/* stm32h7_part_info permits the store each device information and specificities.
* the default unit is byte unless the suffix '_kb' is used. */
-struct stm32h7x_part_info {
+struct stm32h7_part_info {
uint16_t id;
const char *device_str;
- const struct stm32h7x_rev *revs;
+ const struct stm32h7_rev *revs;
size_t num_revs;
unsigned int page_size_kb;
unsigned int block_size; /* flash write word size in bytes */
@@ -117,40 +174,49 @@ struct stm32h7x_part_info {
uint32_t wps_mask;
/* function to compute flash_cr register values */
uint32_t (*compute_flash_cr)(uint32_t cmd, int snb);
+ int (*get_flash_error_status)(struct flash_bank *bank, uint32_t *status);
+ uint32_t flash_error;
+ const uint8_t *write_code;
+ size_t write_code_size;
};
-struct stm32h7x_flash_bank {
+struct stm32h7_flash_bank {
bool probed;
uint32_t idcode;
uint32_t user_bank_size;
uint32_t flash_regs_base; /* Address of flash reg controller */
- const struct stm32h7x_part_info *part_info;
+ const uint32_t *flash_regs;
+ const struct stm32h7_part_info *part_info;
};
-enum stm32h7x_opt_rdp {
+enum stm32h7_opt_rdp {
OPT_RDP_L0 = 0xaa,
OPT_RDP_L1 = 0x00,
OPT_RDP_L2 = 0xcc
};
-static const struct stm32h7x_rev stm32h74_h75xx_revs[] = {
+static const struct stm32h7_rev stm32h74_h75xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, { 0x2003, "V" },
};
-static const struct stm32h7x_rev stm32h7a_h7bxx_revs[] = {
+static const struct stm32h7_rev stm32h7a_h7bxx_revs[] = {
{ 0x1000, "A"},
};
-static const struct stm32h7x_rev stm32h72_h73xx_revs[] = {
+static const struct stm32h7_rev stm32h72_h73xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" },
};
+static const struct stm32h7_rev stm32h7r_h7sxx_revs[] = {
+ { 0x1000, "A" }, { 0x2000, "B" },
+};
+
static uint32_t stm32h74_h75xx_compute_flash_cr(uint32_t cmd, int snb)
{
return cmd | (snb << 8);
}
-static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb)
+static uint32_t stm32h7a_h7b_h7r_h7sxx_compute_flash_cr(uint32_t cmd, int snb)
{
/* save FW and START bits, to be right shifted by 2 bits later */
const uint32_t tmp = cmd & (FLASH_FW | FLASH_START);
@@ -161,81 +227,115 @@ static uint32_t stm32h7a_h7bxx_compute_flash_cr(uint32_t cmd, int snb)
return cmd | (tmp >> 2) | (snb << 6);
}
-static const struct stm32h7x_part_info stm32h7x_parts[] = {
+static int stm32h7_get_flash_status(struct flash_bank *bank, uint32_t *status);
+static int stm32h7rs_get_flash_status(struct flash_bank *bank, uint32_t *status);
+
+static const struct stm32h7_part_info stm32h7_parts[] = {
+ {
+ .id = DEVID_STM32H74_H75XX,
+ .revs = stm32h74_h75xx_revs,
+ .num_revs = ARRAY_SIZE(stm32h74_h75xx_revs),
+ .device_str = "STM32H74x/75x",
+ .page_size_kb = 128,
+ .block_size = 32,
+ .max_flash_size_kb = 2048,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x1FF1E880,
+ .wps_group_size = 1,
+ .wps_mask = 0xFF,
+ .compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
+ .get_flash_error_status = stm32h7_get_flash_status,
+ .flash_error = FLASH_ERROR,
+ .write_code = stm32h7_flash_write_code,
+ .write_code_size = sizeof(stm32h7_flash_write_code),
+ },
{
- .id = DEVID_STM32H74_H75XX,
- .revs = stm32h74_h75xx_revs,
- .num_revs = ARRAY_SIZE(stm32h74_h75xx_revs),
- .device_str = "STM32H74x/75x",
- .page_size_kb = 128,
- .block_size = 32,
- .max_flash_size_kb = 2048,
- .max_bank_size_kb = 1024,
- .has_dual_bank = true,
- .fsize_addr = 0x1FF1E880,
- .wps_group_size = 1,
- .wps_mask = 0xFF,
- .compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
+ .id = DEVID_STM32H7A_H7BXX,
+ .revs = stm32h7a_h7bxx_revs,
+ .num_revs = ARRAY_SIZE(stm32h7a_h7bxx_revs),
+ .device_str = "STM32H7Ax/7Bx",
+ .page_size_kb = 8,
+ .block_size = 16,
+ .max_flash_size_kb = 2048,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = true,
+ .fsize_addr = 0x08FFF80C,
+ .wps_group_size = 4,
+ .wps_mask = 0xFFFFFFFF,
+ .compute_flash_cr = stm32h7a_h7b_h7r_h7sxx_compute_flash_cr,
+ .get_flash_error_status = stm32h7_get_flash_status,
+ .flash_error = FLASH_ERROR,
+ .write_code = stm32h7_flash_write_code,
+ .write_code_size = sizeof(stm32h7_flash_write_code),
},
{
- .id = DEVID_STM32H7A_H7BXX,
- .revs = stm32h7a_h7bxx_revs,
- .num_revs = ARRAY_SIZE(stm32h7a_h7bxx_revs),
- .device_str = "STM32H7Ax/7Bx",
- .page_size_kb = 8,
- .block_size = 16,
- .max_flash_size_kb = 2048,
- .max_bank_size_kb = 1024,
- .has_dual_bank = true,
- .fsize_addr = 0x08FFF80C,
- .wps_group_size = 4,
- .wps_mask = 0xFFFFFFFF,
- .compute_flash_cr = stm32h7a_h7bxx_compute_flash_cr,
+ .id = DEVID_STM32H72_H73XX,
+ .revs = stm32h72_h73xx_revs,
+ .num_revs = ARRAY_SIZE(stm32h72_h73xx_revs),
+ .device_str = "STM32H72x/73x",
+ .page_size_kb = 128,
+ .block_size = 32,
+ .max_flash_size_kb = 1024,
+ .max_bank_size_kb = 1024,
+ .has_dual_bank = false,
+ .fsize_addr = 0x1FF1E880,
+ .wps_group_size = 1,
+ .wps_mask = 0xFF,
+ .compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
+ .get_flash_error_status = stm32h7_get_flash_status,
+ .flash_error = FLASH_ERROR,
+ .write_code = stm32h7_flash_write_code,
+ .write_code_size = sizeof(stm32h7_flash_write_code),
},
{
- .id = DEVID_STM32H72_H73XX,
- .revs = stm32h72_h73xx_revs,
- .num_revs = ARRAY_SIZE(stm32h72_h73xx_revs),
- .device_str = "STM32H72x/73x",
- .page_size_kb = 128,
- .block_size = 32,
- .max_flash_size_kb = 1024,
- .max_bank_size_kb = 1024,
- .has_dual_bank = false,
- .fsize_addr = 0x1FF1E880,
- .wps_group_size = 1,
- .wps_mask = 0xFF,
- .compute_flash_cr = stm32h74_h75xx_compute_flash_cr,
+ .id = DEVID_STM32H7R_H7SXX,
+ .revs = stm32h7r_h7sxx_revs,
+ .num_revs = ARRAY_SIZE(stm32h7r_h7sxx_revs),
+ .device_str = "STM32H7Rx/7Sx",
+ .page_size_kb = 8,
+ .block_size = 16,
+ .max_flash_size_kb = 64,
+ .max_bank_size_kb = 64,
+ .has_dual_bank = false,
+ .fsize_addr = 0x08FFF80C,
+ .wps_group_size = 1,
+ .wps_mask = 0xFF,
+ .compute_flash_cr = stm32h7a_h7b_h7r_h7sxx_compute_flash_cr,
+ .get_flash_error_status = stm32h7rs_get_flash_status,
+ .flash_error = FLASH_ERROR_H7RS,
+ .write_code = stm32h7rs_flash_write_code,
+ .write_code_size = sizeof(stm32h7rs_flash_write_code),
},
};
/* flash bank stm32x 0 0 */
-FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
+FLASH_BANK_COMMAND_HANDLER(stm32h7_flash_bank_command)
{
- struct stm32h7x_flash_bank *stm32x_info;
+ struct stm32h7_flash_bank *stm32h7_info;
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
- stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank));
- bank->driver_priv = stm32x_info;
+ stm32h7_info = malloc(sizeof(struct stm32h7_flash_bank));
+ bank->driver_priv = stm32h7_info;
- stm32x_info->probed = false;
- stm32x_info->user_bank_size = bank->size;
+ stm32h7_info->probed = false;
+ stm32h7_info->user_bank_size = bank->size;
return ERROR_OK;
}
-static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
+static inline uint32_t stm32h7_get_flash_reg(struct flash_bank *bank, uint32_t reg_offset)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- return reg_offset + stm32x_info->flash_regs_base;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
+ return reg_offset + stm32h7_info->flash_regs_base;
}
-static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
+static int stm32h7_read_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t *value)
{
- uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ uint32_t reg_addr = stm32h7_get_flash_reg(bank, reg_offset);
int retval = target_read_u32(bank->target, reg_addr, value);
if (retval != ERROR_OK)
@@ -244,9 +344,16 @@ static inline int stm32x_read_flash_reg(struct flash_bank *bank, uint32_t reg_of
return retval;
}
-static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+static inline int stm32h7_read_flash_reg_by_index(struct flash_bank *bank,
+ enum stm32h7_flash_reg_index reg_index, uint32_t *value)
{
- uint32_t reg_addr = stm32x_get_flash_reg(bank, reg_offset);
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
+ return stm32h7_read_flash_reg(bank, stm32h7_info->flash_regs[reg_index], value);
+}
+
+static int stm32h7_write_flash_reg(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+{
+ uint32_t reg_addr = stm32h7_get_flash_reg(bank, reg_offset);
int retval = target_write_u32(bank->target, reg_addr, value);
if (retval != ERROR_OK)
@@ -255,19 +362,32 @@ static inline int stm32x_write_flash_reg(struct flash_bank *bank, uint32_t reg_o
return retval;
}
-static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status)
+static inline int stm32h7_write_flash_reg_by_index(struct flash_bank *bank,
+ enum stm32h7_flash_reg_index reg_index, uint32_t value)
+{
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
+ return stm32h7_write_flash_reg(bank, stm32h7_info->flash_regs[reg_index], value);
+}
+
+static int stm32h7_get_flash_status(struct flash_bank *bank, uint32_t *status)
+{
+ return stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, status);
+}
+
+static int stm32h7rs_get_flash_status(struct flash_bank *bank, uint32_t *status)
{
- return stm32x_read_flash_reg(bank, FLASH_SR, status);
+ return stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_ISR_INDEX, status);
}
-static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
+static int stm32h7_wait_flash_op_queue(struct flash_bank *bank, int timeout)
{
uint32_t status;
int retval;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
/* wait for flash operations completion */
for (;;) {
- retval = stm32x_get_flash_status(bank, &status);
+ retval = stm32h7_get_flash_status(bank, &status);
if (retval != ERROR_OK)
return retval;
@@ -282,28 +402,28 @@ static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout)
}
if (status & FLASH_WRPERR) {
- LOG_ERROR("wait_flash_op_queue, WRPERR detected");
+ LOG_ERROR("wait_flash_op_queue, write protection error");
retval = ERROR_FAIL;
}
/* Clear error + EOP flags but report errors */
- if (status & FLASH_ERROR) {
+ if (status & stm32h7_info->part_info->flash_error) {
if (retval == ERROR_OK)
retval = ERROR_FAIL;
/* If this operation fails, we ignore it and report the original retval */
- stm32x_write_flash_reg(bank, FLASH_CCR, status);
+ stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_ICR_CCR_INDEX, status);
}
return retval;
}
-static int stm32x_unlock_reg(struct flash_bank *bank)
+static int stm32h7_unlock_reg(struct flash_bank *bank)
{
uint32_t ctrl;
/* first check if not already unlocked
* otherwise writing on FLASH_KEYR will fail
*/
- int retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
+ int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -311,15 +431,15 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock flash registers for bank */
- retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY1);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY1);
if (retval != ERROR_OK)
return retval;
- retval = stm32x_write_flash_reg(bank, FLASH_KEYR, KEY2);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_KEYR_INDEX, KEY2);
if (retval != ERROR_OK)
return retval;
- retval = stm32x_read_flash_reg(bank, FLASH_CR, &ctrl);
+ retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -330,11 +450,11 @@ static int stm32x_unlock_reg(struct flash_bank *bank)
return ERROR_OK;
}
-static int stm32x_unlock_option_reg(struct flash_bank *bank)
+static int stm32h7_unlock_option_reg(struct flash_bank *bank)
{
uint32_t ctrl;
- int retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
+ int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -342,15 +462,15 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
/* unlock option registers */
- retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY1);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY1);
if (retval != ERROR_OK)
return retval;
- retval = stm32x_write_flash_reg(bank, FLASH_OPTKEYR, OPTKEY2);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTKEYR_INDEX, OPTKEY2);
if (retval != ERROR_OK)
return retval;
- retval = stm32x_read_flash_reg(bank, FLASH_OPTCR, &ctrl);
+ retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, &ctrl);
if (retval != ERROR_OK)
return retval;
@@ -362,37 +482,37 @@ static int stm32x_unlock_option_reg(struct flash_bank *bank)
return ERROR_OK;
}
-static inline int stm32x_lock_reg(struct flash_bank *bank)
+static inline int stm32h7_lock_reg(struct flash_bank *bank)
{
- return stm32x_write_flash_reg(bank, FLASH_CR, FLASH_LOCK);
+ return stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK);
}
-static inline int stm32x_lock_option_reg(struct flash_bank *bank)
+static inline int stm32h7_lock_option_reg(struct flash_bank *bank)
{
- return stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_LOCK);
+ return stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, OPT_LOCK);
}
-static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
+static int stm32h7_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value)
{
int retval, retval2;
/* unlock option bytes for modification */
- retval = stm32x_unlock_option_reg(bank);
+ retval = stm32h7_unlock_option_reg(bank);
if (retval != ERROR_OK)
goto flash_options_lock;
/* write option bytes */
- retval = stm32x_write_flash_reg(bank, reg_offset, value);
+ retval = stm32h7_write_flash_reg_by_index(bank, reg_offset, value);
if (retval != ERROR_OK)
goto flash_options_lock;
/* Remove OPT error flag before programming */
- retval = stm32x_write_flash_reg(bank, FLASH_OPTCCR, OPT_CLR_OPTCHANGEERR);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCCR_INDEX, OPT_CLR_OPTCHANGEERR);
if (retval != ERROR_OK)
goto flash_options_lock;
/* start programming cycle */
- retval = stm32x_write_flash_reg(bank, FLASH_OPTCR, OPT_START);
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_OPTCR_INDEX, OPT_START);
if (retval != ERROR_OK)
goto flash_options_lock;
@@ -400,9 +520,9 @@ static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uin
int timeout = FLASH_ERASE_TIMEOUT;
uint32_t status;
for (;;) {
- retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_CUR, &status);
+ retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTSR_CUR_INDEX, &status);
if (retval != ERROR_OK) {
- LOG_ERROR("stm32x_options_program: failed to read FLASH_OPTSR_CUR");
+ LOG_ERROR("stm32h7_options_program: failed to read FLASH_OPTSR_CUR");
goto flash_options_lock;
}
if ((status & OPT_BSY) == 0)
@@ -423,32 +543,32 @@ static int stm32x_write_option(struct flash_bank *bank, uint32_t reg_offset, uin
}
flash_options_lock:
- retval2 = stm32x_lock_option_reg(bank);
+ retval2 = stm32h7_lock_option_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash options");
return (retval == ERROR_OK) ? retval2 : retval;
}
-static int stm32x_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask)
+static int stm32h7_modify_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask)
{
uint32_t data;
- int retval = stm32x_read_flash_reg(bank, reg_offset, &data);
+ int retval = stm32h7_read_flash_reg_by_index(bank, reg_offset, &data);
if (retval != ERROR_OK)
return retval;
data = (data & ~mask) | (value & mask);
- return stm32x_write_option(bank, reg_offset, data);
+ return stm32h7_write_option(bank, reg_offset, data);
}
-static int stm32x_protect_check(struct flash_bank *bank)
+static int stm32h7_protect_check(struct flash_bank *bank)
{
uint32_t protection;
/* read 'write protection' settings */
- int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
+ int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_WPSN_CUR_INDEX, &protection);
if (retval != ERROR_OK) {
LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
@@ -460,10 +580,10 @@ static int stm32x_protect_check(struct flash_bank *bank)
return ERROR_OK;
}
-static int stm32x_erase(struct flash_bank *bank, unsigned int first,
+static int stm32h7_erase(struct flash_bank *bank, unsigned int first,
unsigned int last)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
int retval, retval2;
assert(first < bank->num_sectors);
@@ -472,7 +592,7 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first,
if (bank->target->state != TARGET_HALTED)
return ERROR_TARGET_NOT_HALTED;
- retval = stm32x_unlock_reg(bank);
+ retval = stm32h7_unlock_reg(bank);
if (retval != ERROR_OK)
goto flash_lock;
@@ -488,19 +608,19 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first,
*/
for (unsigned int i = first; i <= last; i++) {
LOG_DEBUG("erase sector %u", i);
- retval = stm32x_write_flash_reg(bank, FLASH_CR,
- stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i));
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX,
+ stm32h7_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %u", i);
goto flash_lock;
}
- retval = stm32x_write_flash_reg(bank, FLASH_CR,
- stm32x_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i));
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX,
+ stm32h7_info->part_info->compute_flash_cr(FLASH_SER | FLASH_PSIZE_64 | FLASH_START, i));
if (retval != ERROR_OK) {
LOG_ERROR("Error erase sector %u", i);
goto flash_lock;
}
- retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT);
+ retval = stm32h7_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK) {
LOG_ERROR("erase time-out or operation error sector %u", i);
@@ -509,18 +629,18 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first,
}
flash_lock:
- retval2 = stm32x_lock_reg(bank);
+ retval2 = stm32h7_lock_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
return (retval == ERROR_OK) ? retval2 : retval;
}
-static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
+static int stm32h7_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
uint32_t protection;
if (target->state != TARGET_HALTED) {
@@ -529,7 +649,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
}
/* read 'write protection' settings */
- int retval = stm32x_read_flash_reg(bank, FLASH_WPSN_CUR, &protection);
+ int retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_WPSN_CUR_INDEX, &protection);
if (retval != ERROR_OK) {
LOG_DEBUG("unable to read WPSN_CUR register");
return retval;
@@ -543,24 +663,24 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
}
/* apply WRPSN mask */
- protection &= stm32x_info->part_info->wps_mask;
+ protection &= stm32h7_info->part_info->wps_mask;
- LOG_DEBUG("stm32x_protect, option_bytes written WPSN 0x%" PRIx32, protection);
+ LOG_DEBUG("stm32h7_protect, option_bytes written WPSN 0x%" PRIx32, protection);
/* apply new option value */
- return stm32x_write_option(bank, FLASH_WPSN_PRG, protection);
+ return stm32h7_write_option(bank, STM32_FLASH_WPSN_PRG_INDEX, protection);
}
-static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
+static int stm32h7_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
/*
* If the size of the data part of the buffer is not a multiple of .block_size, we get
* "corrupted fifo read" pointer in target_run_flash_async_algorithm()
*/
- uint32_t data_size = 512 * stm32x_info->part_info->block_size;
+ uint32_t data_size = 512 * stm32h7_info->part_info->block_size;
uint32_t buffer_size = 8 + data_size;
struct working_area *write_algorithm;
struct working_area *source;
@@ -569,24 +689,21 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
struct armv7m_algorithm armv7m_info;
int retval = ERROR_OK;
- static const uint8_t stm32x_flash_write_code[] = {
-#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc"
- };
-
- if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
+ if (target_alloc_working_area(target, stm32h7_info->part_info->write_code_size,
&write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
retval = target_write_buffer(target, write_algorithm->address,
- sizeof(stm32x_flash_write_code),
- stm32x_flash_write_code);
+ stm32h7_info->part_info->write_code_size,
+ stm32h7_info->part_info->write_code);
if (retval != ERROR_OK) {
target_free_working_area(target, write_algorithm);
return retval;
}
+
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
data_size /= 2;
@@ -617,13 +734,13 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
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, count);
- buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->part_info->block_size);
- buf_set_u32(reg_params[5].value, 0, 32, stm32x_info->flash_regs_base);
+ buf_set_u32(reg_params[4].value, 0, 32, stm32h7_info->part_info->block_size);
+ buf_set_u32(reg_params[5].value, 0, 32, stm32h7_info->flash_regs_base);
retval = target_run_flash_async_algorithm(target,
buffer,
count,
- stm32x_info->part_info->block_size,
+ stm32h7_info->part_info->block_size,
0, NULL,
ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
@@ -631,17 +748,17 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_ERROR("error executing stm32h7x flash write algorithm");
+ LOG_ERROR("error executing stm32h7 flash write algorithm");
uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32);
if (flash_sr & FLASH_WRPERR)
LOG_ERROR("flash memory write protected");
- if ((flash_sr & FLASH_ERROR) != 0) {
- LOG_ERROR("flash write failed, FLASH_SR = 0x%08" PRIx32, flash_sr);
+ if ((flash_sr & stm32h7_info->part_info->flash_error) != 0) {
+ LOG_ERROR("flash write failed, status = 0x%08" PRIx32, flash_sr);
/* Clear error + EOP flags but report errors */
- stm32x_write_flash_reg(bank, FLASH_CCR, flash_sr);
+ stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_ICR_CCR_INDEX, flash_sr);
retval = ERROR_FAIL;
}
}
@@ -658,11 +775,11 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
return retval;
}
-static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
+static int stm32h7_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
uint32_t address = bank->base + offset;
int retval, retval2;
@@ -672,20 +789,20 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
}
/* should be enforced via bank->write_start_alignment */
- assert(!(offset % stm32x_info->part_info->block_size));
+ assert(!(offset % stm32h7_info->part_info->block_size));
/* should be enforced via bank->write_end_alignment */
- assert(!(count % stm32x_info->part_info->block_size));
+ assert(!(count % stm32h7_info->part_info->block_size));
- retval = stm32x_unlock_reg(bank);
+ retval = stm32h7_unlock_reg(bank);
if (retval != ERROR_OK)
goto flash_lock;
- uint32_t blocks_remaining = count / stm32x_info->part_info->block_size;
+ uint32_t blocks_remaining = count / stm32h7_info->part_info->block_size;
/* multiple words (n * .block_size) to be programmed in block */
if (blocks_remaining) {
- retval = stm32x_write_block(bank, buffer, offset, blocks_remaining);
+ retval = stm32h7_write_block(bank, buffer, offset, blocks_remaining);
if (retval != ERROR_OK) {
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
/* if block write failed (no sufficient working area),
@@ -693,8 +810,8 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
}
} else {
- buffer += blocks_remaining * stm32x_info->part_info->block_size;
- address += blocks_remaining * stm32x_info->part_info->block_size;
+ buffer += blocks_remaining * stm32h7_info->part_info->block_size;
+ address += blocks_remaining * stm32h7_info->part_info->block_size;
blocks_remaining = 0;
}
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
@@ -711,33 +828,33 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
4. Wait for flash operations completion
*/
while (blocks_remaining > 0) {
- retval = stm32x_write_flash_reg(bank, FLASH_CR,
- stm32x_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0));
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX,
+ stm32h7_info->part_info->compute_flash_cr(FLASH_PG | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
goto flash_lock;
- retval = target_write_buffer(target, address, stm32x_info->part_info->block_size, buffer);
+ retval = target_write_buffer(target, address, stm32h7_info->part_info->block_size, buffer);
if (retval != ERROR_OK)
goto flash_lock;
- retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT);
+ retval = stm32h7_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT);
if (retval != ERROR_OK)
goto flash_lock;
- buffer += stm32x_info->part_info->block_size;
- address += stm32x_info->part_info->block_size;
+ buffer += stm32h7_info->part_info->block_size;
+ address += stm32h7_info->part_info->block_size;
blocks_remaining--;
}
flash_lock:
- retval2 = stm32x_lock_reg(bank);
+ retval2 = stm32h7_lock_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
return (retval == ERROR_OK) ? retval2 : retval;
}
-static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
+static int stm32h7_read_id_code(struct flash_bank *bank, uint32_t *id)
{
/* read stm32 device id register */
int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id);
@@ -746,50 +863,55 @@ static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id)
return ERROR_OK;
}
-static int stm32x_probe(struct flash_bank *bank)
+static int stm32h7_probe(struct flash_bank *bank)
{
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
uint16_t flash_size_in_kb;
uint32_t device_id;
- stm32x_info->probed = false;
- stm32x_info->part_info = NULL;
+ stm32h7_info->probed = false;
+ stm32h7_info->part_info = NULL;
if (!target_was_examined(target)) {
LOG_ERROR("Target not examined yet");
return ERROR_TARGET_NOT_EXAMINED;
}
- int retval = stm32x_read_id_code(bank, &stm32x_info->idcode);
+ int retval = stm32h7_read_id_code(bank, &stm32h7_info->idcode);
if (retval != ERROR_OK)
return retval;
- LOG_DEBUG("device id = 0x%08" PRIx32, stm32x_info->idcode);
+ LOG_DEBUG("device id = 0x%08" PRIx32, stm32h7_info->idcode);
- device_id = stm32x_info->idcode & 0xfff;
+ device_id = stm32h7_info->idcode & 0xfff;
+ if (device_id == DEVID_STM32H7R_H7SXX) {
+ stm32h7_info->flash_regs = stm32h7rs_flash_regs;
+ } else {
+ stm32h7_info->flash_regs = stm32h7_flash_regs;
+ }
- for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) {
- if (device_id == stm32h7x_parts[n].id)
- stm32x_info->part_info = &stm32h7x_parts[n];
+ for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7_parts); n++) {
+ if (device_id == stm32h7_parts[n].id)
+ stm32h7_info->part_info = &stm32h7_parts[n];
}
- if (!stm32x_info->part_info) {
+ if (!stm32h7_info->part_info) {
LOG_WARNING("Cannot identify target as a STM32H7xx family.");
return ERROR_FAIL;
} else {
- LOG_INFO("Device: %s", stm32x_info->part_info->device_str);
+ LOG_INFO("Device: %s", stm32h7_info->part_info->device_str);
}
/* update the address of controller */
if (bank->base == FLASH_BANK0_ADDRESS)
- stm32x_info->flash_regs_base = FLASH_REG_BASE_B0;
+ stm32h7_info->flash_regs_base = FLASH_REG_BASE_B0;
else if (bank->base == FLASH_BANK1_ADDRESS)
- stm32x_info->flash_regs_base = FLASH_REG_BASE_B1;
+ stm32h7_info->flash_regs_base = FLASH_REG_BASE_B1;
else {
LOG_WARNING("Flash register base not defined for bank %u", bank->bank_number);
return ERROR_FAIL;
}
- LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32x_info->flash_regs_base);
+ LOG_DEBUG("flash_regs_base: 0x%" PRIx32, stm32h7_info->flash_regs_base);
/* get flash size from target */
/* STM32H74x/H75x, the second core (Cortex-M4) cannot read the flash size */
@@ -798,19 +920,19 @@ static int stm32x_probe(struct flash_bank *bank)
&& cortex_m_get_impl_part(target) == CORTEX_M4_PARTNO)
LOG_WARNING("%s cannot read the flash size register", target_name(target));
else
- retval = target_read_u16(target, stm32x_info->part_info->fsize_addr, &flash_size_in_kb);
+ retval = target_read_u16(target, stm32h7_info->part_info->fsize_addr, &flash_size_in_kb);
if (retval != ERROR_OK) {
/* read error when device has invalid value, set max flash size */
- flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb;
+ flash_size_in_kb = stm32h7_info->part_info->max_flash_size_kb;
LOG_INFO("assuming %" PRIu16 "k flash", flash_size_in_kb);
} else
LOG_INFO("flash size probed value %" PRIu16 "k", flash_size_in_kb);
/* setup bank size */
const uint32_t bank1_base = FLASH_BANK0_ADDRESS;
- const uint32_t bank2_base = bank1_base + stm32x_info->part_info->max_bank_size_kb * 1024;
- bool has_dual_bank = stm32x_info->part_info->has_dual_bank;
+ const uint32_t bank2_base = bank1_base + stm32h7_info->part_info->max_bank_size_kb * 1024;
+ bool has_dual_bank = stm32h7_info->part_info->has_dual_bank;
switch (device_id) {
case DEVID_STM32H74_H75XX:
@@ -828,6 +950,7 @@ static int stm32x_probe(struct flash_bank *bank)
flash_size_in_kb /= 2;
break;
case DEVID_STM32H72_H73XX:
+ case DEVID_STM32H7R_H7SXX:
break;
default:
LOG_ERROR("unsupported device");
@@ -860,27 +983,27 @@ static int stm32x_probe(struct flash_bank *bank)
/* if the user sets the size manually then ignore the probed value
* this allows us to work around devices that have an invalid flash size register value */
- if (stm32x_info->user_bank_size) {
+ if (stm32h7_info->user_bank_size) {
LOG_INFO("ignoring flash probed value, using configured bank size");
- flash_size_in_kb = stm32x_info->user_bank_size / 1024;
+ flash_size_in_kb = stm32h7_info->user_bank_size / 1024;
} else if (flash_size_in_kb == 0xffff) {
/* die flash size */
- flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb;
+ flash_size_in_kb = stm32h7_info->part_info->max_flash_size_kb;
}
/* did we assign flash size? */
assert(flash_size_in_kb != 0xffff);
bank->size = flash_size_in_kb * 1024;
- bank->write_start_alignment = stm32x_info->part_info->block_size;
- bank->write_end_alignment = stm32x_info->part_info->block_size;
+ bank->write_start_alignment = stm32h7_info->part_info->block_size;
+ bank->write_end_alignment = stm32h7_info->part_info->block_size;
/* setup sectors */
- bank->num_sectors = flash_size_in_kb / stm32x_info->part_info->page_size_kb;
+ bank->num_sectors = flash_size_in_kb / stm32h7_info->part_info->page_size_kb;
assert(bank->num_sectors > 0);
free(bank->sectors);
- bank->sectors = alloc_block_array(0, stm32x_info->part_info->page_size_kb * 1024,
+ bank->sectors = alloc_block_array(0, stm32h7_info->part_info->page_size_kb * 1024,
bank->num_sectors);
if (!bank->sectors) {
@@ -889,7 +1012,7 @@ static int stm32x_probe(struct flash_bank *bank)
}
/* setup protection blocks */
- const uint32_t wpsn = stm32x_info->part_info->wps_group_size;
+ const uint32_t wpsn = stm32h7_info->part_info->wps_group_size;
assert(bank->num_sectors % wpsn == 0);
bank->num_prot_blocks = bank->num_sectors / wpsn;
@@ -897,7 +1020,7 @@ static int stm32x_probe(struct flash_bank *bank)
free(bank->prot_blocks);
- bank->prot_blocks = alloc_block_array(0, stm32x_info->part_info->page_size_kb * wpsn * 1024,
+ bank->prot_blocks = alloc_block_array(0, stm32h7_info->part_info->page_size_kb * wpsn * 1024,
bank->num_prot_blocks);
if (!bank->prot_blocks) {
@@ -905,28 +1028,28 @@ static int stm32x_probe(struct flash_bank *bank)
return ERROR_FAIL;
}
- stm32x_info->probed = true;
+ stm32h7_info->probed = true;
return ERROR_OK;
}
-static int stm32x_auto_probe(struct flash_bank *bank)
+static int stm32h7_auto_probe(struct flash_bank *bank)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
- if (stm32x_info->probed)
+ if (stm32h7_info->probed)
return ERROR_OK;
- return stm32x_probe(bank);
+ return stm32h7_probe(bank);
}
/* This method must return a string displaying information about the bank */
-static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *cmd)
+static int stm32h7_get_info(struct flash_bank *bank, struct command_invocation *cmd)
{
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
- const struct stm32h7x_part_info *info = stm32x_info->part_info;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
+ const struct stm32h7_part_info *info = stm32h7_info->part_info;
- if (!stm32x_info->probed) {
- int retval = stm32x_probe(bank);
+ if (!stm32h7_info->probed) {
+ int retval = stm32h7_probe(bank);
if (retval != ERROR_OK) {
command_print_sameline(cmd, "Unable to find bank information.");
return retval;
@@ -935,7 +1058,7 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c
if (info) {
const char *rev_str = NULL;
- uint16_t rev_id = stm32x_info->idcode >> 16;
+ uint16_t rev_id = stm32h7_info->idcode >> 16;
for (unsigned int i = 0; i < info->num_revs; i++)
if (rev_id == info->revs[i].rev)
@@ -943,11 +1066,11 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c
if (rev_str) {
command_print_sameline(cmd, "%s - Rev: %s",
- stm32x_info->part_info->device_str, rev_str);
+ stm32h7_info->part_info->device_str, rev_str);
} else {
command_print_sameline(cmd,
"%s - Rev: unknown (0x%04" PRIx16 ")",
- stm32x_info->part_info->device_str, rev_id);
+ stm32h7_info->part_info->device_str, rev_id);
}
} else {
command_print_sameline(cmd, "Cannot identify target as a STM32H7x");
@@ -956,7 +1079,7 @@ static int stm32x_get_info(struct flash_bank *bank, struct command_invocation *c
return ERROR_OK;
}
-static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp)
+static int stm32h7_set_rdp(struct flash_bank *bank, enum stm32h7_opt_rdp new_rdp)
{
struct target *target = bank->target;
uint32_t optsr, cur_rdp;
@@ -967,7 +1090,7 @@ static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp
return ERROR_TARGET_NOT_HALTED;
}
- retval = stm32x_read_flash_reg(bank, FLASH_OPTSR_PRG, &optsr);
+ retval = stm32h7_read_flash_reg_by_index(bank, STM32_FLASH_OPTSR_PRG_INDEX, &optsr);
if (retval != ERROR_OK) {
LOG_DEBUG("unable to read FLASH_OPTSR_PRG register");
@@ -997,10 +1120,10 @@ static int stm32x_set_rdp(struct flash_bank *bank, enum stm32h7x_opt_rdp new_rdp
optsr = (optsr & ~OPT_RDP_MASK) | (new_rdp << OPT_RDP_POS);
/* apply new option value */
- return stm32x_write_option(bank, FLASH_OPTSR_PRG, optsr);
+ return stm32h7_write_option(bank, STM32_FLASH_OPTSR_PRG_INDEX, optsr);
}
-COMMAND_HANDLER(stm32x_handle_lock_command)
+COMMAND_HANDLER(stm32h7_handle_lock_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1010,7 +1133,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
if (retval != ERROR_OK)
return retval;
- retval = stm32x_set_rdp(bank, OPT_RDP_L1);
+ retval = stm32h7_set_rdp(bank, OPT_RDP_L1);
if (retval != ERROR_OK)
command_print(CMD, "%s failed to lock device", bank->driver->name);
@@ -1020,7 +1143,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
return retval;
}
-COMMAND_HANDLER(stm32x_handle_unlock_command)
+COMMAND_HANDLER(stm32h7_handle_unlock_command)
{
if (CMD_ARGC < 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1030,7 +1153,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
if (retval != ERROR_OK)
return retval;
- retval = stm32x_set_rdp(bank, OPT_RDP_L0);
+ retval = stm32h7_set_rdp(bank, OPT_RDP_L0);
if (retval != ERROR_OK)
command_print(CMD, "%s failed to unlock device", bank->driver->name);
@@ -1040,45 +1163,45 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
return retval;
}
-static int stm32x_mass_erase(struct flash_bank *bank)
+static int stm32h7_mass_erase(struct flash_bank *bank)
{
int retval, retval2;
struct target *target = bank->target;
- struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv;
+ struct stm32h7_flash_bank *stm32h7_info = bank->driver_priv;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- retval = stm32x_unlock_reg(bank);
+ retval = stm32h7_unlock_reg(bank);
if (retval != ERROR_OK)
goto flash_lock;
/* mass erase flash memory bank */
- retval = stm32x_write_flash_reg(bank, FLASH_CR,
- stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0));
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX,
+ stm32h7_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64, 0));
if (retval != ERROR_OK)
goto flash_lock;
- retval = stm32x_write_flash_reg(bank, FLASH_CR,
- stm32x_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0));
+ retval = stm32h7_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX,
+ stm32h7_info->part_info->compute_flash_cr(FLASH_BER | FLASH_PSIZE_64 | FLASH_START, 0));
if (retval != ERROR_OK)
goto flash_lock;
- retval = stm32x_wait_flash_op_queue(bank, 30000);
+ retval = stm32h7_wait_flash_op_queue(bank, MASS_ERASE_TIMEOUT);
if (retval != ERROR_OK)
goto flash_lock;
flash_lock:
- retval2 = stm32x_lock_reg(bank);
+ retval2 = stm32h7_lock_reg(bank);
if (retval2 != ERROR_OK)
LOG_ERROR("error during the lock of flash");
return (retval == ERROR_OK) ? retval2 : retval;
}
-COMMAND_HANDLER(stm32x_handle_mass_erase_command)
+COMMAND_HANDLER(stm32h7_handle_mass_erase_command)
{
if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1088,7 +1211,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
if (retval != ERROR_OK)
return retval;
- retval = stm32x_mass_erase(bank);
+ retval = stm32h7_mass_erase(bank);
if (retval == ERROR_OK)
command_print(CMD, "stm32h7x mass erase complete");
else
@@ -1097,7 +1220,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command)
return retval;
}
-COMMAND_HANDLER(stm32x_handle_option_read_command)
+COMMAND_HANDLER(stm32h7_handle_option_read_command)
{
if (CMD_ARGC != 2)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1110,17 +1233,16 @@ COMMAND_HANDLER(stm32x_handle_option_read_command)
uint32_t reg_offset, value;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
- retval = stm32x_read_flash_reg(bank, reg_offset, &value);
+ retval = stm32h7_read_flash_reg_by_index(bank, reg_offset, &value);
if (retval != ERROR_OK)
return retval;
- command_print(CMD, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32,
- stm32x_get_flash_reg(bank, reg_offset), value);
+ command_print(CMD, "0x%" PRIx32, value);
- return retval;
+ return ERROR_OK;
}
-COMMAND_HANDLER(stm32x_handle_option_write_command)
+COMMAND_HANDLER(stm32h7_handle_option_write_command)
{
if (CMD_ARGC != 3 && CMD_ARGC != 4)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -1137,41 +1259,41 @@ COMMAND_HANDLER(stm32x_handle_option_write_command)
if (CMD_ARGC > 3)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], mask);
- return stm32x_modify_option(bank, reg_offset, value, mask);
+ return stm32h7_modify_option(bank, reg_offset, value, mask);
}
-static const struct command_registration stm32h7x_exec_command_handlers[] = {
+static const struct command_registration stm32h7_exec_command_handlers[] = {
{
.name = "lock",
- .handler = stm32x_handle_lock_command,
+ .handler = stm32h7_handle_lock_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Lock entire flash device.",
},
{
.name = "unlock",
- .handler = stm32x_handle_unlock_command,
+ .handler = stm32h7_handle_unlock_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Unlock entire protected flash device.",
},
{
.name = "mass_erase",
- .handler = stm32x_handle_mass_erase_command,
+ .handler = stm32h7_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Erase entire flash device.",
},
{
.name = "option_read",
- .handler = stm32x_handle_option_read_command,
+ .handler = stm32h7_handle_option_read_command,
.mode = COMMAND_EXEC,
.usage = "bank_id reg_offset",
.help = "Read and display device option bytes.",
},
{
.name = "option_write",
- .handler = stm32x_handle_option_write_command,
+ .handler = stm32h7_handle_option_write_command,
.mode = COMMAND_EXEC,
.usage = "bank_id reg_offset value [mask]",
.help = "Write device option bit fields with provided value.",
@@ -1179,29 +1301,29 @@ static const struct command_registration stm32h7x_exec_command_handlers[] = {
COMMAND_REGISTRATION_DONE
};
-static const struct command_registration stm32h7x_command_handlers[] = {
+static const struct command_registration stm32h7_command_handlers[] = {
{
.name = "stm32h7x",
.mode = COMMAND_ANY,
.help = "stm32h7x flash command group",
.usage = "",
- .chain = stm32h7x_exec_command_handlers,
+ .chain = stm32h7_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
const struct flash_driver stm32h7x_flash = {
.name = "stm32h7x",
- .commands = stm32h7x_command_handlers,
- .flash_bank_command = stm32x_flash_bank_command,
- .erase = stm32x_erase,
- .protect = stm32x_protect,
- .write = stm32x_write,
+ .commands = stm32h7_command_handlers,
+ .flash_bank_command = stm32h7_flash_bank_command,
+ .erase = stm32h7_erase,
+ .protect = stm32h7_protect,
+ .write = stm32h7_write,
.read = default_flash_read,
- .probe = stm32x_probe,
- .auto_probe = stm32x_auto_probe,
+ .probe = stm32h7_probe,
+ .auto_probe = stm32h7_auto_probe,
.erase_check = default_flash_blank_check,
- .protect_check = stm32x_protect_check,
- .info = stm32x_get_info,
+ .protect_check = stm32h7_protect_check,
+ .info = stm32h7_get_info,
.free_driver_priv = default_flash_free_driver_priv,
};
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index f16333201b..34676659b2 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,12 +287,16 @@ 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/WBA/WL";
static const struct stm32l4_rev stm32l47_l48xx_revs[] = {
{ 0x1000, "1" }, { 0x1001, "2" }, { 0x1003, "3" }, { 0x1007, "4" }
};
+static const struct stm32l4_rev stm32u3b_u3cxx_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
static const struct stm32l4_rev stm32l43_l44xx_revs[] = {
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
};
@@ -347,6 +354,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" },
};
@@ -393,6 +404,14 @@ static const struct stm32l4_rev stm32wba5x_revs[] = {
{ 0x1000, "A" },
};
+static const struct stm32l4_rev stm32wba6x_revs[] = {
+ { 0x1000, "A" }, { 0x1001, "Z" },
+};
+
+static const struct stm32l4_rev stm32wba2x_revs[] = {
+ { 0x1000, "A" },
+};
+
static const struct stm32l4_rev stm32wb1xx_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" },
};
@@ -422,6 +441,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.otp_base = 0x1FFF7000,
.otp_size = 1024,
},
+ {
+ .id = DEVID_STM32U3B_U3CXX,
+ .revs = stm32u3b_u3cxx_revs,
+ .num_revs = ARRAY_SIZE(stm32u3b_u3cxx_revs),
+ .device_str = "STM32U3B/U3Cxx",
+ .max_flash_size_kb = 2048,
+ .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_STM32L43_L44XX,
.revs = stm32l43_l44xx_revs,
@@ -500,7 +531,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 +718,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 +749,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 +762,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,
@@ -728,10 +775,36 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
.num_revs = ARRAY_SIZE(stm32wba5x_revs),
.device_str = "STM32WBA5x",
.max_flash_size_kb = 1024,
- .flags = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS,
+ .flags = F_QUAD_WORD_PROG | F_HAS_TZ | F_HAS_L5_FLASH_REGS
+ | F_WRP_HAS_LOCK,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x0BF907A0,
+ .otp_base = 0x0BF90000,
+ .otp_size = 512,
+ },
+ {
+ .id = DEVID_STM32WBA6X,
+ .revs = stm32wba6x_revs,
+ .num_revs = ARRAY_SIZE(stm32wba6x_revs),
+ .device_str = "STM32WBA6x",
+ .max_flash_size_kb = 2048,
+ .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 = 0x0FF907A0,
- .otp_base = 0x0FF90000,
+ .fsize_addr = 0x0BFA07A0,
+ .otp_base = 0x0BFA0000,
+ .otp_size = 512,
+ },
+ {
+ .id = DEVID_STM32WBA2X,
+ .revs = stm32wba2x_revs,
+ .num_revs = ARRAY_SIZE(stm32wba2x_revs),
+ .device_str = "STM32WBA2x",
+ .max_flash_size_kb = 512,
+ .flags = F_HAS_TZ | F_HAS_L5_FLASH_REGS | F_WRP_HAS_LOCK,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x0BF8D7A0,
+ .otp_base = 0x0BF8D000,
.otp_size = 512,
},
{
@@ -974,7 +1047,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 +1360,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 +1446,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 +1855,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.
@@ -1818,7 +1900,7 @@ static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
struct target *target = bank->target;
/* try reading possible IDCODE registers, in the following order */
- uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
+ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_L5, DBGMCU_IDCODE_G0};
for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) {
retval = target_read_u32(target, dbgmcu_idcode[i], id);
@@ -2142,6 +2224,16 @@ static int stm32l4_probe(struct flash_bank *bank)
stm32l4_info->bank1_sectors = num_pages / 2;
}
break;
+ case DEVID_STM32U3B_U3CXX:
+ 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:
@@ -2168,13 +2260,25 @@ static int stm32l4_probe(struct flash_bank *bank)
}
break;
case DEVID_STM32WBA5X:
- /* single bank flash */
+ case DEVID_STM32WBA6X:
+ /* according to RM0493 Rev 7, Chapter 7.3.1
+ * WBA5xx have 8K page size and are always
+ * single bank.
+ * According to RM0515 Rev 4, Chapter 7.3.1
+ * WBA6xx have 8K page size and are always
+ * DUAL BANK
+ */
page_size_kb = 8;
num_pages = flash_size_kb / page_size_kb;
stm32l4_info->bank1_sectors = num_pages;
+ if (stm32l4_info->optr & FLASH_U5_DUALBANK) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
break;
case DEVID_STM32WB5XX:
case DEVID_STM32WB3XX:
+ case DEVID_STM32WBA2X:
/* single bank flash */
page_size_kb = 4;
num_pages = flash_size_kb / page_size_kb;
@@ -2400,19 +2504,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)
@@ -2439,8 +2542,7 @@ COMMAND_HANDLER(stm32l4_handle_option_write_command)
"INFO: a reset or power cycle is required "
"for the new settings to take effect.", bank->driver->name);
- retval = stm32l4_write_option(bank, reg_offset, value, mask);
- return retval;
+ return stm32l4_write_option(bank, reg_offset, value, mask);
}
COMMAND_HANDLER(stm32l4_handle_trustzone_command)
diff --git a/src/flash/nor/stm32l4x.h b/src/flash/nor/stm32l4x.h
index 07b3615a24..7ee62d6636 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))
@@ -86,11 +89,13 @@
/* Supported device IDs */
#define DEVID_STM32L47_L48XX 0x415
+#define DEVID_STM32U3B_U3CXX 0x42A
#define DEVID_STM32L43_L44XX 0x435
#define DEVID_STM32C01XX 0x443
#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
@@ -116,6 +121,8 @@
#define DEVID_STM32WB5XX 0x495
#define DEVID_STM32WB3XX 0x496
#define DEVID_STM32WLE_WL5XX 0x497
+#define DEVID_STM32WBA6X 0x4B0
+#define DEVID_STM32WBA2X 0x4B2
/* known Flash base addresses */
#define STM32_FLASH_BANK_BASE 0x08000000
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index 1459e942d1..2e949c5dba 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -90,6 +90,7 @@ static int stm32lx_lock_program_memory(struct flash_bank *bank);
static int stm32lx_enable_write_half_page(struct flash_bank *bank);
static int stm32lx_erase_sector(struct flash_bank *bank, int sector);
static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank);
+static int stm32lx_obl_launch(struct flash_bank *bank);
static int stm32lx_lock(struct flash_bank *bank);
static int stm32lx_unlock(struct flash_bank *bank);
static int stm32lx_mass_erase(struct flash_bank *bank);
@@ -354,6 +355,26 @@ COMMAND_HANDLER(stm32lx_handle_unlock_command)
return retval;
}
+COMMAND_HANDLER(stm32lx_handle_option_load_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 = stm32lx_obl_launch(bank);
+ if (retval != ERROR_OK) {
+ command_print(CMD, "failed to load option bytes");
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
static int stm32lx_protect_check(struct flash_bank *bank)
{
int retval;
@@ -745,7 +766,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) {
@@ -921,6 +942,13 @@ static const struct command_registration stm32lx_exec_command_handlers[] = {
.usage = "bank_id",
.help = "Lower the readout protection from Level 1 to 0.",
},
+ {
+ .name = "option_load",
+ .handler = stm32lx_handle_option_load_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "Force re-load of device options (will cause device reset).",
+ },
COMMAND_REGISTRATION_DONE
};
@@ -1048,10 +1076,8 @@ static int stm32lx_enable_write_half_page(struct flash_bank *bank)
return retval;
reg32 |= FLASH_PECR__PROG;
- retval = target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
+ return target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
reg32);
-
- return retval;
}
static int stm32lx_lock_program_memory(struct flash_bank *bank)
@@ -1204,7 +1230,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;
@@ -1238,7 +1264,10 @@ static int stm32lx_obl_launch(struct flash_bank *bank)
{
struct target *target = bank->target;
struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv;
- int retval;
+
+ int retval = stm32lx_unlock_options_bytes(bank);
+ if (retval != ERROR_OK)
+ return retval;
/* This will fail as the target gets immediately rebooted */
target_write_u32(target, stm32lx_info->flash_base + FLASH_PECR,
diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c
index df58f6c55d..174643b7e6 100644
--- a/src/flash/nor/stmqspi.c
+++ b/src/flash/nor/stmqspi.c
@@ -1800,9 +1800,7 @@ static int find_sfdp_dummy(struct flash_bank *bank, int len)
err:
/* Abort operation */
- retval = stmqspi_abort(bank);
-
- return retval;
+ return stmqspi_abort(bank);
}
/* Read SFDP parameter block */
@@ -1978,24 +1976,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..e84721333b 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);
@@ -736,7 +736,7 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command)
target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®);
protection_regs = ~(reg >> 16);
- while (((protection_regs) != 0) && (protection_level < 16)) {
+ while ((protection_regs != 0) && (protection_level < 16)) {
protection_regs >>= 1;
protection_level++;
}
@@ -753,7 +753,7 @@ COMMAND_HANDLER(str7x_handle_disable_jtag_command)
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC);
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0),
- ~(1 << (15 + protection_level)));
+ ~(1U << (15 + protection_level)));
flash_cmd = FLASH_SPR | FLASH_WMS;
target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd);
}
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..b7156a1ae2 100644
--- a/src/flash/nor/str9xpec.c
+++ b/src/flash/nor/str9xpec.c
@@ -171,7 +171,6 @@ static int str9xpec_isc_disable(struct flash_bank *bank)
static int str9xpec_read_config(struct flash_bank *bank)
{
struct scan_field field;
- uint8_t status;
struct jtag_tap *tap;
struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv;
@@ -190,9 +189,7 @@ static int str9xpec_read_config(struct flash_bank *bank)
jtag_add_dr_scan(tap, 1, &field, TAP_IDLE);
jtag_execute_queue();
- status = str9xpec_isc_status(tap);
-
- return status;
+ return str9xpec_isc_status(tap);
}
static int str9xpec_build_block_list(struct flash_bank *bank)
@@ -206,28 +203,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;
@@ -487,11 +484,7 @@ static int str9xpec_lock_device(struct flash_bank *bank)
static int str9xpec_unlock_device(struct flash_bank *bank)
{
- uint8_t status;
-
- status = str9xpec_erase_area(bank, 0, 255);
-
- return status;
+ return str9xpec_erase_area(bank, 0, 255);
}
static int str9xpec_protect(struct flash_bank *bank, int set,
@@ -735,7 +728,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/swm050.c b/src/flash/nor/swm050.c
index dcf59d380e..880c44e198 100644
--- a/src/flash/nor/swm050.c
+++ b/src/flash/nor/swm050.c
@@ -67,8 +67,7 @@ static int swm050_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
- retval = ERROR_TARGET_NOT_HALTED;
- return retval;
+ return ERROR_TARGET_NOT_HALTED;
}
/* Perform write */
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index a19b1a6833..57e53dca1e 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -192,7 +192,7 @@ COMMAND_HANDLER(handle_flash_erase_check_command)
command_print(CMD, "successfully checked erase state");
else {
command_print(CMD,
- "unknown error when checking erase state of flash bank #%s at "
+ "Error: checking erase state of flash bank #%s at "
TARGET_ADDR_FMT,
CMD_ARGV[0],
p->base);
@@ -275,7 +275,7 @@ COMMAND_HANDLER(handle_flash_erase_address_command)
if (retval == ERROR_OK)
retval = flash_erase_address_range(target, do_pad, address, length);
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "erased address " TARGET_ADDR_FMT " (length %" PRIu32 ")"
" in %fs (%0.3f KiB/s)", address, length,
duration_elapsed(&bench), duration_kbps(&bench, length));
@@ -323,7 +323,7 @@ COMMAND_HANDLER(handle_flash_erase_command)
retval = flash_driver_erase(p, first, last);
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "erased sectors %" PRIu32 " "
"through %" PRIu32 " on flash bank %u "
"in %fs", first, last, p->bank_number, duration_elapsed(&bench));
@@ -449,7 +449,7 @@ COMMAND_HANDLER(handle_flash_write_image_command)
return retval;
}
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "wrote %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", written, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, written));
@@ -501,7 +501,7 @@ COMMAND_HANDLER(handle_flash_verify_image_command)
return retval;
}
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "verified %" PRIu32 " bytes from file %s "
"in %fs (%0.3f KiB/s)", verified, CMD_ARGV[0],
duration_elapsed(&bench), duration_kbps(&bench, verified));
@@ -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(
@@ -655,7 +655,7 @@ COMMAND_HANDLER(handle_flash_fill_command)
ptr += wordsize;
}
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "wrote %" PRIu32 " bytes to " TARGET_ADDR_FMT
" in %fs (%0.3f KiB/s)", size_bytes, address,
duration_elapsed(&bench), duration_kbps(&bench, size_bytes));
@@ -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)
{
@@ -832,7 +950,7 @@ COMMAND_HANDLER(handle_flash_write_bank_command)
free(buffer);
- if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) {
+ if (retval == ERROR_OK && duration_measure(&bench) == ERROR_OK) {
command_print(CMD, "wrote %zu bytes from file %s to flash bank %u"
" at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)",
length, CMD_ARGV[1], bank->bank_number, offset,
@@ -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,
@@ -1317,8 +1442,7 @@ COMMAND_HANDLER(handle_flash_banks_command)
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
- unsigned int n = 0;
- for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) {
+ for (struct flash_bank *p = flash_bank_list(); p; p = p->next) {
command_print(CMD, "#%d : %s (%s) at " TARGET_ADDR_FMT ", size 0x%8.8" PRIx32 ", "
"buswidth %u, chipwidth %u", p->bank_number,
p->name, p->driver->name, p->base, p->size,
@@ -1335,7 +1459,7 @@ COMMAND_HANDLER(handle_flash_list)
for (struct flash_bank *p = flash_bank_list(); p; p = p->next) {
command_print(CMD,
"{\n"
- " name %s\n"
+ " name {%s}\n"
" driver %s\n"
" base " TARGET_ADDR_FMT "\n"
" size 0x%" PRIx32 "\n"
diff --git a/src/flash/nor/tms470.c b/src/flash/nor/tms470.c
index 00ee77bb80..1c8432a205 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]);
}
@@ -490,7 +490,6 @@ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *ban
uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk;
struct target *target = bank->target;
struct tms470_flash_bank *tms470_info = bank->driver_priv;
- int result = ERROR_OK;
/*
* Select the desired bank to be programmed by writing BANK[2:0] of
@@ -500,7 +499,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 +507,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 +541,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,58 +561,58 @@ 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;
+ return ERROR_OK;
}
/* ---------------------------------------------------------------------- */
@@ -625,7 +624,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 +679,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 +696,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 +728,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 +919,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 +939,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 +948,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/virtual.c b/src/flash/nor/virtual.c
index c5e33385e6..5b8a3c5b7a 100644
--- a/src/flash/nor/virtual.c
+++ b/src/flash/nor/virtual.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-/***************************************************************************
- * Copyright (C) 2010 by Spencer Oliver *
- * spen@spen-soft.co.uk *
- ***************************************************************************/
+/*
+ * Copyright (C) 2010 by Spencer Oliver
+ *
+ * Copyright (C) 2019 by Tomas Vanek
+ */
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -31,6 +32,9 @@ static void virtual_update_bank_info(struct flash_bank *bank)
/* update the info we do not have */
bank->size = master_bank->size;
+ if (bank->read_only)
+ return;
+
bank->chip_width = master_bank->chip_width;
bank->bus_width = master_bank->bus_width;
bank->erased_value = master_bank->erased_value;
@@ -93,34 +97,24 @@ static int virtual_erase(struct flash_bank *bank, unsigned int first,
unsigned int last)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
- int retval;
if (!master_bank)
return ERROR_FLASH_OPERATION_FAILED;
/* call master handler */
- retval = master_bank->driver->erase(master_bank, first, last);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return master_bank->driver->erase(master_bank, first, last);
}
static int virtual_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
- int retval;
if (!master_bank)
return ERROR_FLASH_OPERATION_FAILED;
/* call master handler */
- retval = master_bank->driver->write(master_bank, buffer, offset, count);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return master_bank->driver->write(master_bank, buffer, offset, count);
}
static int virtual_probe(struct flash_bank *bank)
@@ -177,34 +171,37 @@ static int virtual_info(struct flash_bank *bank, struct command_invocation *cmd)
static int virtual_blank_check(struct flash_bank *bank)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
- int retval;
if (!master_bank)
return ERROR_FLASH_OPERATION_FAILED;
/* call master handler */
- retval = master_bank->driver->erase_check(master_bank);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return master_bank->driver->erase_check(master_bank);
}
static int virtual_flash_read(struct flash_bank *bank,
uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct flash_bank *master_bank = virtual_get_master_bank(bank);
- int retval;
if (!master_bank)
return ERROR_FLASH_OPERATION_FAILED;
/* call master handler */
- retval = master_bank->driver->read(master_bank, buffer, offset, count);
- if (retval != ERROR_OK)
- return retval;
+ return master_bank->driver->read(master_bank, buffer, offset, count);
+}
- return ERROR_OK;
+void virtual_flash_free_driver_priv(struct flash_bank *bank)
+{
+ free(bank->driver_priv);
+ bank->driver_priv = NULL;
+
+ /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from
+ * master flash_bank structure. They point to memory locations allocated by master flash driver
+ * so master driver is responsible for releasing them.
+ * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */
+ bank->sectors = NULL;
+ bank->prot_blocks = NULL;
}
const struct flash_driver virtual_flash = {
@@ -219,5 +216,62 @@ const struct flash_driver virtual_flash = {
.erase_check = virtual_blank_check,
.protect_check = virtual_protect_check,
.info = virtual_info,
- .free_driver_priv = default_flash_free_driver_priv,
+ .free_driver_priv = virtual_flash_free_driver_priv,
+};
+
+FLASH_BANK_COMMAND_HANDLER(ro_alias_bank_command)
+{
+ if (CMD_ARGC < 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ // get the master flash bank
+ const char *bank_name = CMD_ARGV[6];
+ struct flash_bank *master_bank = get_flash_bank_by_name_noprobe(bank_name);
+
+ if (!master_bank) {
+ LOG_ERROR("master flash bank '%s' does not exist", bank_name);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ // save master bank name - use this to get settings later
+ bank->driver_priv = strdup(bank_name);
+
+ bank->read_only = true;
+
+ return ERROR_OK;
+}
+
+static int ro_alias_erase(struct flash_bank *bank,
+ unsigned int first, unsigned int last)
+{
+ char *bank_name = bank->driver_priv;
+
+ LOG_ERROR("Erase of read-only flash alias refused. Use master flash bank '%s'",
+ bank_name);
+
+ return ERROR_FAIL;
+}
+
+static int ro_alias_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ char *bank_name = bank->driver_priv;
+
+ LOG_ERROR("Write to read-only flash alias refused. Use master flash bank '%s'",
+ bank_name);
+
+ return ERROR_FAIL;
+}
+
+const struct flash_driver ro_alias_flash = {
+ .name = "ro_alias",
+ .flash_bank_command = ro_alias_bank_command,
+ .erase = ro_alias_erase,
+ .write = ro_alias_write,
+ .read = virtual_flash_read,
+ .probe = virtual_probe,
+ .auto_probe = virtual_auto_probe,
+ .erase_check = virtual_blank_check,
+ .info = virtual_info,
+ .free_driver_priv = virtual_flash_free_driver_priv,
};
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/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c
index 54fd5a5867..ceed055fcb 100644
--- a/src/flash/nor/xmc4xxx.c
+++ b/src/flash/nor/xmc4xxx.c
@@ -231,12 +231,12 @@ struct xmc4xxx_command_seq {
};
/* Sector capacities. See section 8 of xmc4x00_rm */
-static const unsigned int sector_capacity_8[8] = {
- 16, 16, 16, 16, 16, 16, 16, 128
+static const unsigned int sector_capacity_9[9] = {
+ 16, 16, 16, 16, 16, 16, 16, 16, 128
};
-static const unsigned int sector_capacity_9[9] = {
- 16, 16, 16, 16, 16, 16, 16, 128, 256
+static const unsigned int sector_capacity_10[10] = {
+ 16, 16, 16, 16, 16, 16, 16, 16, 128, 256
};
static const unsigned int sector_capacity_12[12] = {
@@ -272,12 +272,12 @@ static int xmc4xxx_load_bank_layout(struct flash_bank *bank)
LOG_DEBUG("%u sectors", bank->num_sectors);
switch (bank->num_sectors) {
- case 8:
- capacity = sector_capacity_8;
- break;
case 9:
capacity = sector_capacity_9;
break;
+ case 10:
+ capacity = sector_capacity_10;
+ break;
case 12:
capacity = sector_capacity_12;
break;
@@ -361,11 +361,11 @@ static int xmc4xxx_probe(struct flash_bank *bank)
* we understand the type of controller we're dealing with */
switch (flash_id) {
case FLASH_ID_XMC4100_4200:
- bank->num_sectors = 8;
+ bank->num_sectors = 9;
LOG_DEBUG("XMC4xxx: XMC4100/4200 detected.");
break;
case FLASH_ID_XMC4400:
- bank->num_sectors = 9;
+ bank->num_sectors = 10;
LOG_DEBUG("XMC4xxx: XMC4400 detected.");
break;
case FLASH_ID_XMC4500:
@@ -522,9 +522,7 @@ static int xmc4xxx_erase_sector(struct flash_bank *bank, uint32_t address,
}
/* Now we must wait for the erase operation to end */
- res = xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT);
-
- return res;
+ return xmc4xxx_wait_status_busy(bank, FLASH_OP_TIMEOUT);
}
static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first,
@@ -569,8 +567,7 @@ static int xmc4xxx_erase(struct flash_bank *bank, unsigned int first,
}
clear_status_and_exit:
- res = xmc4xxx_clear_flash_status(bank);
- return res;
+ return xmc4xxx_clear_flash_status(bank);
}
@@ -1131,7 +1128,6 @@ static int xmc4xxx_flash_protect(struct flash_bank *bank, int level, bool read_p
static int xmc4xxx_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
- int ret;
struct xmc4xxx_flash_bank *fb = bank->driver_priv;
/* Check for flash passwords */
@@ -1144,14 +1140,11 @@ static int xmc4xxx_protect(struct flash_bank *bank, int set, unsigned int first,
if (set == 0) {
LOG_WARNING("Flash protection will be temporarily disabled"
" for all pages (User 0 only)!");
- ret = xmc4xxx_temp_unprotect(bank, 0);
- return ret;
+ return xmc4xxx_temp_unprotect(bank, 0);
}
/* Install write protection for user 0 on the specified pages */
- ret = xmc4xxx_flash_protect(bank, 0, false, first, last);
-
- return ret;
+ return xmc4xxx_flash_protect(bank, 0, false, first, last);
}
static int xmc4xxx_protect_check(struct flash_bank *bank)
@@ -1290,9 +1283,7 @@ COMMAND_HANDLER(xmc4xxx_handle_flash_unprotect_command)
COMMAND_PARSE_NUMBER(s32, CMD_ARGV[1], level);
- res = xmc4xxx_flash_unprotect(bank, level);
-
- return res;
+ return xmc4xxx_flash_unprotect(bank, level);
}
static const struct command_registration xmc4xxx_exec_command_handlers[] = {
diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am
index 39d93d66ac..1a61f78719 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,13 +32,12 @@ 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 \
%D%/jep106.inc \
%D%/jim-nvp.h \
- %D%/base64.c \
- %D%/base64.h \
%D%/nvp.h \
%D%/compiler.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..bf2c91814e 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)
@@ -350,50 +345,54 @@ void command_output_text(struct command_context *context, const char *data)
context->output_handler(context, data);
}
-void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
+static void command_vprint(struct command_invocation *cmd,
+ va_list ap, const char *format, bool add_lf)
{
- char *string;
+ assert(cmd);
+
+ // Quit on previous allocation error
+ if (cmd->output == CMD_PRINT_OOM)
+ return;
+ char *string = alloc_vprintf(format, ap);
+ if (!string)
+ goto alloc_error;
+
+ char *output = cmd->output ? cmd->output : "";
+ output = alloc_printf("%s%s%s", output, string, add_lf ? "\n" : "");
+ free(string);
+ if (!output)
+ goto alloc_error;
+
+ free(cmd->output);
+ cmd->output = output;
+
+ return;
+
+alloc_error:
+ LOG_ERROR("Out of memory");
+ free(cmd->output);
+ cmd->output = CMD_PRINT_OOM;
+}
+
+void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
+{
va_list ap;
va_start(ap, format);
- string = alloc_vprintf(format, ap);
- if (string && cmd) {
- /* we want this collected in the log + we also want to pick it up as a tcl return
- * value.
- *
- * The latter bit isn't precisely neat, but will do for now.
- */
- Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
- /* We already printed it above
- * command_output_text(context, string); */
- free(string);
- }
+ bool add_lf = false;
+ command_vprint(cmd, ap, format, add_lf);
va_end(ap);
}
void command_print(struct command_invocation *cmd, const char *format, ...)
{
- char *string;
-
va_list ap;
va_start(ap, format);
- string = alloc_vprintf(format, ap);
- if (string && cmd) {
- strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one
- *char longer */
- /* we want this collected in the log + we also want to pick it up as a tcl return
- * value.
- *
- * The latter bit isn't precisely neat, but will do for now.
- */
- Jim_AppendString(cmd->ctx->interp, cmd->output, string, -1);
- /* We already printed it above
- * command_output_text(context, string); */
- free(string);
- }
+ bool add_lf = true;
+ command_vprint(cmd, ap, format, add_lf);
va_end(ap);
}
@@ -406,28 +405,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) {
@@ -445,36 +441,57 @@ static int exec_command(Jim_Interp *interp, struct command_context *context,
.argc = argc - 1,
.argv = words + 1,
.jimtcl_argv = argv + 1,
+ .output = NULL,
};
- cmd.output = Jim_NewEmptyStringObj(context->interp);
- Jim_IncrRefCount(cmd.output);
-
int retval = c->handler(&cmd);
+
+ // Handle allocation error in command_print()
+ if (cmd.output == CMD_PRINT_OOM) {
+ cmd.output = NULL;
+ if (retval == ERROR_OK)
+ retval = ERROR_FAIL;
+ }
+
if (retval == ERROR_COMMAND_SYNTAX_ERROR) {
- /* Print help for command */
- command_run_linef(context, "usage %s", words[0]);
+ // Print command syntax
+ Jim_EvalObjPrefix(context->interp, Jim_NewStringObj(context->interp, "usage", -1), 1, argv);
} else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) {
/* just fall through for a shutdown request */
} else {
if (retval != ERROR_OK)
LOG_DEBUG("Command '%s' failed with error code %d",
words[0], retval);
- /*
- * Use the command output as the Tcl result.
- * Drop last '\n' to allow command output concatenation
- * while keep using command_print() everywhere.
- */
- const char *output_txt = Jim_String(cmd.output);
- int len = strlen(output_txt);
- if (len && output_txt[len - 1] == '\n')
- --len;
- Jim_SetResultString(context->interp, output_txt, len);
+ if (cmd.output) {
+ /*
+ * Use the command output as the Tcl result.
+ * Drop last '\n' to allow command output concatenation
+ * while keep using command_print() everywhere.
+ */
+ int len = strlen(cmd.output);
+ if (len && cmd.output[len - 1] == '\n')
+ --len;
+ Jim_SetResultString(context->interp, cmd.output, len);
+ } else {
+ Jim_SetEmptyResult(context->interp);
+ }
}
- Jim_DecrRefCount(context->interp, cmd.output);
-
+ free(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;
+
+ Jim_Obj *error_code = Jim_NewListObj(context->interp, NULL, 0);
+ Jim_ListAppendElement(context->interp, error_code, Jim_NewStringObj(context->interp, "OpenOCD", -1));
+ Jim_ListAppendElement(context->interp, error_code, Jim_NewIntObj(context->interp, retval));
+ Jim_SetGlobalVariableStr(context->interp, "errorCode", error_code);
+
+ return JIM_ERR;
}
int command_run_line(struct command_context *context, char *line)
@@ -484,7 +501,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 +515,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 +535,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, ...)
@@ -684,12 +691,16 @@ static COMMAND_HELPER(command_help_show_list, bool show_help, const char *cmd_ma
#define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
-static void command_help_show_indent(unsigned int n)
+static COMMAND_HELPER(command_help_show_indent, unsigned int n)
{
for (unsigned int i = 0; i < n; i++)
- LOG_USER_N(" ");
+ command_print_sameline(CMD, " ");
+
+ return ERROR_OK;
}
-static void command_help_show_wrap(const char *str, unsigned int n, unsigned int n2)
+
+static COMMAND_HELPER(command_help_show_wrap,
+ const char *str, unsigned int n, unsigned int n2)
{
const char *cp = str, *last = str;
while (*cp) {
@@ -702,11 +713,13 @@ static void command_help_show_wrap(const char *str, unsigned int n, unsigned int
} while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
if (next - last < HELP_LINE_WIDTH(n))
cp = next;
- command_help_show_indent(n);
- LOG_USER("%.*s", (int)(cp - last), last);
+ CALL_COMMAND_HANDLER(command_help_show_indent, n);
+ command_print(CMD, "%.*s", (int)(cp - last), last);
last = cp + 1;
n = n2;
}
+
+ return ERROR_OK;
}
static COMMAND_HELPER(command_help_show, struct help_entry *c,
@@ -725,10 +738,10 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
if (is_match) {
if (c->usage && strlen(c->usage) > 0) {
char *msg = alloc_printf("%s %s", c->cmd_name, c->usage);
- command_help_show_wrap(msg, n, n + 5);
+ CALL_COMMAND_HANDLER(command_help_show_wrap, msg, n, n + 5);
free(msg);
} else {
- command_help_show_wrap(c->cmd_name, n, n + 5);
+ CALL_COMMAND_HANDLER(command_help_show_wrap, c->cmd_name, n, n + 5);
}
}
@@ -742,16 +755,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
@@ -762,7 +775,7 @@ static COMMAND_HELPER(command_help_show, struct help_entry *c,
return ERROR_FAIL;
}
- command_help_show_wrap(msg, n + 3, n + 3);
+ CALL_COMMAND_HANDLER(command_help_show_wrap, msg, n + 3, n + 3);
free(msg);
}
@@ -841,7 +854,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 +880,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 +925,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 +1342,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..aa23574067 100644
--- a/src/helper/command.h
+++ b/src/helper/command.h
@@ -80,9 +80,14 @@ struct command_invocation {
unsigned int argc;
const char **argv;
Jim_Obj * const *jimtcl_argv;
- Jim_Obj *output;
+ char *output;
};
+/**
+ * Assigned to command_invocation::output on allocation error
+ */
+#define CMD_PRINT_OOM ((char *)(-1L))
+
/**
* Return true if the command @c cmd is registered by OpenOCD.
*/
@@ -197,7 +202,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 +238,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..a066f0a2e4 100644
--- a/src/helper/jep106.inc
+++ b/src/helper/jep106.inc
@@ -2,13 +2,13 @@
/*
* The manufacturer's standard identification code list appears in JEP106.
- * Copyright (c) 2025 JEDEC. All rights reserved.
+ * Copyright (c) 2026 JEDEC. All rights reserved.
*
* JEP106 is regularly updated. For the current manufacturer's standard
* 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 JEP106BO May 2026. */
[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",
@@ -205,7 +205,7 @@
[1][0x43 - 1] = "Suwa Electronics",
[1][0x44 - 1] = "Transmeta",
[1][0x45 - 1] = "Micron CMS",
-[1][0x46 - 1] = "American Computer & Digital Components Inc",
+[1][0x46 - 1] = "American Computer Digital Components",
[1][0x47 - 1] = "Enhance 3000 Inc",
[1][0x48 - 1] = "Tower Semiconductor",
[1][0x49 - 1] = "CPU Design",
@@ -1450,7 +1450,7 @@
[11][0x34 - 1] = "Acacia Communications",
[11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd",
[11][0x36 - 1] = "Zyzyx",
-[11][0x37 - 1] = "C-SKY Microsystems Co Ltd",
+[11][0x37 - 1] = "C-SKY Microsystems Co Ltd (XuanTie)",
[11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd",
[11][0x39 - 1] = "Syzexion",
[11][0x3a - 1] = "Kembona",
@@ -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",
@@ -1900,7 +1900,7 @@
[14][0x7c - 1] = "ForwardEdge ASIC",
[14][0x7d - 1] = "Beijing Future Signet Technology Co Ltd",
[14][0x7e - 1] = "Fine Made Microelectronics Group Co Ltd",
-[15][0x01 - 1] = "Changxin Memory Technology (Shanghai)",
+[15][0x01 - 1] = "CXSH",
[15][0x02 - 1] = "Synconv",
[15][0x03 - 1] = "MULTIUNIT",
[15][0x04 - 1] = "Zero ASIC Corporation",
@@ -1915,7 +1915,7 @@
[15][0x0d - 1] = "AUTOTALKS",
[15][0x0e - 1] = "Shenzhen Ranshuo Technology Co Limited",
[15][0x0f - 1] = "ScaleFlux",
-[15][0x10 - 1] = "XC Memory",
+[15][0x10 - 1] = "XCMemory Co Ltd",
[15][0x11 - 1] = "Guangzhou Beimu Technology Co Ltd",
[15][0x12 - 1] = "Rays Semiconductor Nanjing Co Ltd",
[15][0x13 - 1] = "Milli-Centi Intelligence Technology Jiangsu",
@@ -2049,4 +2049,167 @@
[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",
+[16][0x3b - 1] = "HRDWYR Ventures Private Limited",
+[16][0x3c - 1] = "ENE Technology Inc",
+[16][0x3d - 1] = "GOFATOO",
+[16][0x3e - 1] = "Shenzhen Jingchu Technology Co Ltd",
+[16][0x3f - 1] = "NEVETA",
+[16][0x40 - 1] = "RZX",
+[16][0x41 - 1] = "Shenzhen Zhongcheng Qingcong Technology Co",
+[16][0x42 - 1] = "Shenzhen Heyloo Electronic Technology Co",
+[16][0x43 - 1] = "Shenzhen Shanghaowang Electronic Technology",
+[16][0x44 - 1] = "Shanghai Qimingxin Semiconductor Technology",
+[16][0x45 - 1] = "Great Wall Global Information Technology",
+[16][0x46 - 1] = "Beijing Memsilicon Technology Co Ltd",
+[16][0x47 - 1] = "Openchip & Software Technologies S L",
+[16][0x48 - 1] = "FlashLeap Tech (Shenzhen) Co Ltd",
+[16][0x49 - 1] = "Shenzhen JinShanDe Technology Co Ltd",
+[16][0x4a - 1] = "RUIBOHU",
+[16][0x4b - 1] = "ETA Semiconductor Ltd",
+[16][0x4c - 1] = "L&T Semiconductor Technologies Limited",
+[16][0x4d - 1] = "RAYSMEM",
+[16][0x4e - 1] = "Sichuan Zhongzhao Yongye Semiconductor",
+[16][0x4f - 1] = "Shenzhen Ruiyuanchuangxin Technology",
+[16][0x50 - 1] = "CSSI South Africa (Pty) Ltd",
+[16][0x51 - 1] = "Jeju Semiconductor Corp",
+[16][0x52 - 1] = "Origin Code LLC",
+[16][0x53 - 1] = "Chengdu Masscore Microelectronics Tech",
+[16][0x54 - 1] = "Shenzhen Whalekom Technology Co Ltd",
+[16][0x55 - 1] = "femtoAI",
+[16][0x56 - 1] = "Shanghai Chip4Tao Technology Co Ltd",
+[16][0x57 - 1] = "Shenzhenshijimokkejiyouxiangongsi",
+[16][0x58 - 1] = "DEGUA",
+[16][0x59 - 1] = "TENGYIN CELESTIALSTORAGE",
+[16][0x5a - 1] = "Shenzhen Minder Semiconductor Co Ltd",
+[16][0x5b - 1] = "GUANGSUJIE",
+[16][0x5c - 1] = "HVLANYN Technology",
+[16][0x5d - 1] = "Theo End (Shenzhen) Computing Tech Co",
+[16][0x5e - 1] = "Shenzhen Heroje Electronics Co Ltd",
+[16][0x5f - 1] = "Guangdong Yuecun Microelectronics Co",
+[16][0x60 - 1] = "Foxin Technology",
+[16][0x61 - 1] = "JinTech Semiconductor Co Limited",
+[16][0x62 - 1] = "Shenzhen Hongred Information Technology Co",
+[16][0x63 - 1] = "ZST Inc",
+[16][0x64 - 1] = "Veris Danismanlik Limited Sirketi",
+[16][0x65 - 1] = "Starblaze",
+[16][0x66 - 1] = "Siptechx",
+[16][0x67 - 1] = "Djelec",
+[16][0x68 - 1] = "Ambarella Corporation",
+[16][0x69 - 1] = "SiliconX",
+[16][0x6a - 1] = "Shenzhen Tencent Computer System Co",
+[16][0x6b - 1] = "Shenzhen Econo Electronic Co Ltd (China)",
+[16][0x6c - 1] = "Pu Sl Technology (Shenzhen) Co Limited",
+[16][0x6d - 1] = "Shenzhen Kimviking Technology Co Ltd",
+[16][0x6e - 1] = "Shenzhen Touch Think Intelligence Co Ltd",
+[16][0x6f - 1] = "Beijing Institute of Open Source Chip",
+[16][0x70 - 1] = "BYTE International Co Ltd",
+[16][0x71 - 1] = "Shenzhen ITZR Technology Co Ltd",
+[16][0x72 - 1] = "Centre Development Advanced Computing",
+[16][0x73 - 1] = "Overlord Labs",
+[16][0x74 - 1] = "Shenzhen Chaocun Technology Co Ltd",
+[16][0x75 - 1] = "Shenzhen Yuqi Electronics Co Ltd",
+[16][0x76 - 1] = "Transsemi Miceoelectronics Co Ltd",
+[16][0x77 - 1] = "Pu Sl Technology (Shenzhen) Co Limited",
+[16][0x78 - 1] = "Shenzhen Xingjiachen Electronics Co Ltd",
+[16][0x79 - 1] = "Shenzhen Xingjiachen Electronics Co Ltd",
+[16][0x7a - 1] = "Shenyang Lianxin Chuangxiang Technology",
+[16][0x7b - 1] = "Plusetech Technology (Shenzhen) Co Ltd",
+[16][0x7c - 1] = "ChongQing YuJia Smart Storage Digital",
+[16][0x7d - 1] = "CTST Co Ltd",
+[16][0x7e - 1] = "SSK Corporation",
+[17][0x01 - 1] = "Shenzhen Xinruiyun Storage Technology",
+[17][0x02 - 1] = "JSC Megapolis-Telecom Region",
+[17][0x03 - 1] = "Minpo Corporation",
+[17][0x04 - 1] = "Shenzhen Yingzhong Technology Co Ltd",
+[17][0x05 - 1] = "Moment Semiconductor Inc",
+[17][0x06 - 1] = "Yiweihong (Shenzhen) Electronic Technology Co",
+[17][0x07 - 1] = "Shenzhen Dawei Microelectronics Technology Co",
+[17][0x08 - 1] = "Shenzhen Zhuoran Electronics Co Ltd",
+[17][0x09 - 1] = "Mengxw Electron Ltd",
+[17][0x0a - 1] = "Origin Storage Ltd",
+[17][0x0b - 1] = "Shanghai RuiPan Electronic Information Tech",
+[17][0x0c - 1] = "Fortell Research Inc",
+[17][0x0d - 1] = "Jiyi Semiconductor Co Ltd",
+[17][0x0e - 1] = "Shenzhen Silicon Hermit Technology Ltd",
+[17][0x0f - 1] = "HuiRong Electronic System Engineering Co LTD",
+[17][0x10 - 1] = "ALBSEMI (Hangzhou) Co Ltd",
+[17][0x11 - 1] = "ULX",
+[17][0x12 - 1] = "Sichuan Huazhixincun Technology Co Ltd",
+[17][0x13 - 1] = "Shenzhen Yunyue Semiconductor Co Ltd.",
+[17][0x14 - 1] = "Fortune Sky Enterprise Limited",
+[17][0x15 - 1] = "Shenzhen Tianchuang Weiye Technology",
+[17][0x16 - 1] = "Shanghai Simchip Technology Group",
+[17][0x17 - 1] = "SVOD Project SRO",
+[17][0x18 - 1] = "Shenzhen Xunnaying Technology Co Ltd",
+[17][0x19 - 1] = "Zhejiang Xinhan Intelligent Manufacturing",
+[17][0x1a - 1] = "Shenzhen Tranvita Technology Co Ltd",
+[17][0x1b - 1] = "Zhongke Zhichun (Zhuhai) Technology Co",
+[17][0x1c - 1] = "Shenzhen Yunmemory AI Technology Co",
+[17][0x1d - 1] = "Shenzhen KEHB Electronics Co Ltd",
+[17][0x1e - 1] = "Shenzhen EVOC Storage Technology Co",
+[17][0x1f - 1] = "Beijing ZhanChuang ZhenHua Technology Co",
+[17][0x20 - 1] = "Sichuan Huakun Zhenyu Intelligent Technology",
+[17][0x21 - 1] = "Hunan Hongen Electronics Co Ltd",
+[17][0x22 - 1] = "Shenzhen Youjing Microelectronics Technology",
+[17][0x23 - 1] = "Shenzhen Coosure Electronics Co Ltd",
+[17][0x24 - 1] = "Seavo Future Technology (Shenzhen) Co Ltd",
+[17][0x25 - 1] = "ShenZhen Goodtimes Technology Co Ltd",
+[17][0x26 - 1] = "Shanxi Bluestone Guangzhi Technology Co Ltd",
+[17][0x27 - 1] = "Shenzhen Lianrunfeng Electronic Technology Co",
+[17][0x28 - 1] = "Shenzhen Seapiy Technology Co Ltd",
+[17][0x29 - 1] = "Aivres Systems Inc",
+[17][0x2a - 1] = "Liveseek",
+[17][0x2b - 1] = "Shenzhen KingSpec Electronics Technology",
+[17][0x2c - 1] = "Shenzhen Qiben Electronics Co Ltd",
+[17][0x2d - 1] = "Guangdong Shunwei Microelectronics Tech",
+[17][0x2e - 1] = "Efficient Computer",
+[17][0x2f - 1] = "Shenzhen Powerleader Storage Technology",
+[17][0x30 - 1] = "Shenzhen Chuangzhan Semiconductor Co Ltd",
+[17][0x31 - 1] = "Shenzhen Xbnow Technology Co Ltd",
+[17][0x32 - 1] = "YCHIPWAY Semiconductor Technology",
+[17][0x33 - 1] = "Shenzhen Yansen Industrial Storage Co Ltd",
+[17][0x34 - 1] = "ARIA Sensing Srl",
+[17][0x35 - 1] = "EverModule Technology Co Ltd",
+[17][0x36 - 1] = "The AIO",
+[17][0x37 - 1] = "North Magna Limited",
+[17][0x38 - 1] = "Unisemi Power Inc",
+[17][0x39 - 1] = "Shenzhen RongPei Technology Co Ltd",
+[17][0x3a - 1] = "HKIC International Electronics Limited",
+[17][0x3b - 1] = "Shenzhen DTX Space Technology Co Ltd",
+[17][0x3c - 1] = "Ranxin Technology",
/* EOF */
diff --git a/src/helper/log.c b/src/helper/log.c
index 8f7ab00397..8263cfc601 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -24,24 +24,8 @@
#include
-#ifdef _DEBUG_FREE_SPACE_
-#ifdef HAVE_MALLOC_H
+#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
#include
-#else
-#error "malloc.h is required to use --enable-malloc-logging"
-#endif
-
-#ifdef __GLIBC__
-#if __GLIBC_PREREQ(2, 33)
-#define FORDBLKS_FORMAT " %zu"
-#else
-/* glibc older than 2.33 (2021-02-01) use mallinfo(). Overwrite it */
-#define mallinfo2 mallinfo
-#define FORDBLKS_FORMAT " %d"
-#endif
-#else
-#error "GNU glibc is required to use --enable-malloc-logging"
-#endif
#endif
int debug_level = LOG_LVL_INFO;
@@ -53,16 +37,17 @@ static int64_t last_time;
static int64_t start;
-static const char * const log_strings[6] = {
+static const char * const log_strings[7] = {
"User : ",
"Error: ",
"Warn : ", /* want a space after each colon, all same width, colons aligned */
"Info : ",
"Debug: ",
- "Debug: "
+ "Debug: ",
+ "Debug: ", /* corresponds to LOG_LVL_DEBUG_USB */
};
-static int count;
+static unsigned int count;
/* forward the log to the listeners */
static void log_forward(const char *file, unsigned int line, const char *function, const char *string)
@@ -77,6 +62,32 @@ static void log_forward(const char *file, unsigned int line, const char *functio
}
}
+// whitespace + SIZE_MAX + zero termination
+#define MEM_STR_LEN (1 + 21 + 1)
+static void get_free_memory_space(char *s)
+{
+#if defined(HAVE_MALLINFO2)
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_MALLOC)) {
+ struct mallinfo2 info = mallinfo2();
+ snprintf(s, MEM_STR_LEN, " %zu", info.fordblks);
+ return;
+ }
+#elif defined(HAVE_MALLINFO)
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_MALLOC)) {
+ struct mallinfo info = mallinfo();
+#if IS_CYGWIN
+ snprintf(s, MEM_STR_LEN, " %zu", info.fordblks);
+#else
+ snprintf(s, MEM_STR_LEN, " %d", info.fordblks);
+#endif
+ return;
+ }
+#endif
+
+ // empty string
+ *s = 0;
+}
+
/* The log_puts() serves two somewhat different goals:
*
* - logging
@@ -93,7 +104,7 @@ static void log_puts(enum log_levels level,
const char *function,
const char *string)
{
- char *f;
+ const char *f;
if (!log_output) {
/* log_init() not called yet; print on stderr */
@@ -113,21 +124,16 @@ 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_
- struct mallinfo2 info = mallinfo2();
-#endif
- fprintf(log_output, "%s%d %" PRId64 " %s:%d %s()"
-#ifdef _DEBUG_FREE_SPACE_
- FORDBLKS_FORMAT
-#endif
- ": %s", log_strings[level + 1], count, t, file, line, function,
-#ifdef _DEBUG_FREE_SPACE_
- info.fordblks,
-#endif
- string);
+
+ char free_memory[MEM_STR_LEN];
+ get_free_memory_space(free_memory);
+
+ fprintf(log_output, "%s%u %" PRId64 " %s:%d %s()%s: %s",
+ log_strings[level + 1], count, t, file, line, function,
+ free_memory, string);
} else {
/* if we are using gdb through pipes then we do not want any output
* to the pipe otherwise we get repeated strings */
@@ -152,10 +158,11 @@ void log_printf(enum log_levels level,
char *string;
va_list ap;
- count++;
if (level > debug_level)
return;
+ count++;
+
va_start(ap, format);
string = alloc_vprintf(format, ap);
@@ -172,11 +179,11 @@ void log_vprintf_lf(enum log_levels level, const char *file, unsigned int line,
{
char *tmp;
- count++;
-
if (level > debug_level)
return;
+ count++;
+
tmp = alloc_vprintf(format, args);
if (!tmp)
@@ -207,18 +214,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;
+ if (new_level > LOG_LVL_DEBUG_USB || new_level < LOG_LVL_SILENT) {
+ command_print(CMD, "level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG_USB);
+ 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 +269,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 +361,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);
@@ -361,7 +371,8 @@ char *alloc_vprintf(const char *fmt, va_list ap)
/* allocate and make room for terminating zero. */
/* FIXME: The old version always allocated at least one byte extra and
* other code depend on that. They should be probably be fixed, but for
- * now reserve the extra byte. */
+ * now reserve the extra byte. Apparently the last user of such hack is
+ * log_vprintf_lf() that adds a trailing newline. */
string = malloc(len + 2);
if (!string)
return NULL;
@@ -519,7 +530,7 @@ void log_socket_error(const char *socket_desc)
const char *find_nonprint_char(const char *buf, unsigned int buf_len)
{
for (unsigned int i = 0; i < buf_len; i++) {
- if (!isprint(buf[i]))
+ if (!isprint((unsigned char)buf[i]))
return buf + i;
}
return NULL;
diff --git a/src/helper/log.h b/src/helper/log.h
index ac24f8e833..01917abe23 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
@@ -36,6 +37,13 @@
* LOG_LVL_INFO - state information, etc.
* LOG_LVL_DEBUG - debug statements, execution trace
* LOG_LVL_DEBUG_IO - verbose debug, low-level I/O trace
+ * LOG_LVL_DEBUG_USB - verbose USB trace
+ * In the past this corresponded to build configuration options
+ --enable-verbose and --enable-verbose-usb-comms.
+ * LOG_LVL_DEBUG_MALLOC - log messages will include the amount of free heap space
+ * maintained by malloc in its free list, if mallinfo is available.
+ * In the past this corresponded to build configuration
+ * option --enable-malloc-logging.
*/
enum log_levels {
LOG_LVL_SILENT = -3,
@@ -46,6 +54,10 @@ enum log_levels {
LOG_LVL_INFO = 2,
LOG_LVL_DEBUG = 3,
LOG_LVL_DEBUG_IO = 4,
+ // LOG_LVL_DEBUG_USB and LOG_LVL_DEBUG_MALLOC have the same value at the moment.
+ // In the future, these logging categories will be individually switchable.
+ LOG_LVL_DEBUG_USB = 5,
+ LOG_LVL_DEBUG_MALLOC = 5,
};
void log_printf(enum log_levels level, const char *file, unsigned int line,
@@ -86,9 +98,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);
@@ -99,17 +111,19 @@ extern int debug_level;
#define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO))
+#define LOG_DEBUG_USB(expr, ...) LOG_CUSTOM_LEVEL(LOG_LVL_DEBUG_USB, expr, ##__VA_ARGS__)
+
#define LOG_DEBUG_IO(expr ...) \
do { \
- if (debug_level >= LOG_LVL_DEBUG_IO) \
- log_printf_lf(LOG_LVL_DEBUG, \
+ if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) \
+ log_printf_lf(LOG_LVL_DEBUG_IO, \
__FILE__, __LINE__, __func__, \
expr); \
} while (0)
#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 +132,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..9eb26a4762 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -151,7 +151,7 @@ static char *find_relative_path(const char *from, const char *to)
while (from[0] != '\0') {
if (from[0] != '/')
i++;
- char *next = strchr(from, '/');
+ const char *next = strchr(from, '/');
if (!next)
break;
from = next + 1;
@@ -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..de7ee84ec6 100644
--- a/src/helper/replacements.c
+++ b/src/helper/replacements.c
@@ -19,6 +19,7 @@
#define IN_REPLACEMENTS_C
#include "replacements.h"
+#include
#include
#include
@@ -58,51 +59,6 @@ void *fill_malloc(size_t size)
#include
#endif
-/* replacements for gettimeofday */
-#ifndef HAVE_GETTIMEOFDAY
-
-/* Windows */
-#ifdef _WIN32
-
-#ifndef __GNUC__
-#define EPOCHFILETIME (116444736000000000i64)
-#else
-#define EPOCHFILETIME (116444736000000000LL)
-#endif
-
-int gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- FILETIME ft;
- LARGE_INTEGER li;
- __int64 t;
- static int tzflag;
-
- if (tv) {
- GetSystemTimeAsFileTime(&ft);
- li.LowPart = ft.dwLowDateTime;
- li.HighPart = ft.dwHighDateTime;
- t = li.QuadPart; /* In 100-nanosecond intervals */
- t -= EPOCHFILETIME; /* Offset to the Epoch time */
- t /= 10; /* In microseconds */
- tv->tv_sec = (long)(t / 1000000);
- tv->tv_usec = (long)(t % 1000000);
- }
-
- if (tz) {
- if (!tzflag) {
- _tzset();
- tzflag++;
- }
- tz->tz_minuteswest = _timezone / 60;
- tz->tz_dsttime = _daylight;
- }
-
- return 0;
-}
-#endif /* _WIN32 */
-
-#endif /* HAVE_GETTIMEOFDAY */
-
#ifndef HAVE_STRNLEN
size_t strnlen(const char *s, size_t maxlen)
{
@@ -126,6 +82,12 @@ char *strndup(const char *s, size_t n)
#endif
#ifdef _WIN32
+
+static bool safe_fd_isset(int fd, fd_set *set)
+{
+ return set && OCD_FD_ISSET(fd, set);
+}
+
int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
{
DWORD ms_total, limit;
@@ -138,8 +100,6 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time
struct timeval tvslice;
int retcode;
-#define SAFE_FD_ISSET(fd, set) (set && FD_ISSET(fd, set))
-
/* calculate how long we need to wait in milliseconds */
if (!tv)
ms_total = INFINITE;
@@ -152,19 +112,34 @@ 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)) {
+ if (safe_fd_isset(i, rfds) || safe_fd_isset(i, wfds) || safe_fd_isset(i, efds)) {
intptr_t handle = (intptr_t) _get_osfhandle(i);
handles[n_handles] = (HANDLE)handle;
if (handles[n_handles] == INVALID_HANDLE_VALUE) {
/* socket */
- if (SAFE_FD_ISSET(i, rfds))
- FD_SET(i, &sock_read);
- if (SAFE_FD_ISSET(i, wfds))
- FD_SET(i, &sock_write);
- if (SAFE_FD_ISSET(i, efds))
- FD_SET(i, &sock_except);
+ if (safe_fd_isset(i, rfds))
+ OCD_FD_SET(i, &sock_read);
+ if (safe_fd_isset(i, wfds))
+ OCD_FD_SET(i, &sock_write);
+ if (safe_fd_isset(i, efds))
+ OCD_FD_SET(i, &sock_except);
if (i > sock_max_fd)
sock_max_fd = i;
} else {
@@ -227,7 +202,7 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time
retcode = 0;
for (i = 0; i < n_handles; i++) {
if (WaitForSingleObject(handles[i], 0) == WAIT_OBJECT_0) {
- if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) {
+ if (safe_fd_isset(handle_slot_to_fd[i], rfds)) {
DWORD bytes;
intptr_t handle = (intptr_t) _get_osfhandle(
handle_slot_to_fd[i]);
@@ -236,20 +211,20 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time
NULL, &bytes, NULL)) {
/* check to see if gdb pipe has data available */
if (bytes) {
- FD_SET(handle_slot_to_fd[i], &aread);
+ OCD_FD_SET(handle_slot_to_fd[i], &aread);
retcode++;
}
} else {
- FD_SET(handle_slot_to_fd[i], &aread);
+ OCD_FD_SET(handle_slot_to_fd[i], &aread);
retcode++;
}
}
- if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) {
- FD_SET(handle_slot_to_fd[i], &awrite);
+ if (safe_fd_isset(handle_slot_to_fd[i], wfds)) {
+ OCD_FD_SET(handle_slot_to_fd[i], &awrite);
retcode++;
}
- if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) {
- FD_SET(handle_slot_to_fd[i], &aexcept);
+ if (safe_fd_isset(handle_slot_to_fd[i], efds)) {
+ OCD_FD_SET(handle_slot_to_fd[i], &aexcept);
retcode++;
}
}
diff --git a/src/helper/replacements.h b/src/helper/replacements.h
index ecc0e5e955..c48bc79a87 100644
--- a/src/helper/replacements.h
+++ b/src/helper/replacements.h
@@ -51,21 +51,6 @@ struct timeval {
#endif
-/* gettimeofday() */
-#ifndef HAVE_GETTIMEOFDAY
-
-#ifdef _WIN32
-struct timezone {
- int tz_minuteswest;
- int tz_dsttime;
-};
-#endif
-struct timezone;
-
-int gettimeofday(struct timeval *tv, struct timezone *tz);
-
-#endif
-
void *clear_malloc(size_t size);
void *fill_malloc(size_t size);
@@ -141,6 +126,7 @@ struct sockaddr_un {
#endif
#if IS_MINGW == 1
+#if defined(__x86_64__) || defined(__i386__)
static inline unsigned char inb(unsigned short int port)
{
unsigned char _v;
@@ -152,6 +138,7 @@ static inline void outb(unsigned char value, unsigned short int port)
{
__asm__ __volatile__ ("outb %b0,%w1" : : "a" (value), "Nd" (port));
}
+#endif
/* mingw does not have ffs, so use gcc builtin types */
#define ffs __builtin_ffs
@@ -162,6 +149,18 @@ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct time
#endif /* _WIN32 */
+/* Socket descriptor is unsigned on Windows.
+ * Add a cast to prevent sign mismatch warnings (-Wsign-compare). */
+#ifdef _WIN32
+#define OCD_FD_SET(fd, set) FD_SET((SOCKET)(fd), (set))
+#define OCD_FD_CLR(fd, set) FD_CLR((SOCKET)(fd), (set))
+#define OCD_FD_ISSET(fd, set) FD_ISSET((SOCKET)(fd), (set))
+#else
+#define OCD_FD_SET(fd, set) FD_SET((fd), (set))
+#define OCD_FD_CLR(fd, set) FD_CLR((fd), (set))
+#define OCD_FD_ISSET(fd, set) FD_ISSET((fd), (set))
+#endif
+
/* generic socket functions for Windows and Posix */
static inline int write_socket(int handle, const void *buffer, unsigned int count)
{
@@ -225,6 +224,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..d5926491c0 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,65 @@ 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 either with
+ # - path/to/a/certain/vendor/config_file
+ # or
+ # - 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
+ }
+ regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f
+ regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f
+ if {[catch {_find_internal $f} t]==0} {
+ echo "WARNING: '$filename' is deprecated, use '$f' instead"
+ return $t
+ }
+
+ foreach vendor {gigadevice nordic sifive st ti} {
+ # - path/to/a/certain/config_file
+ # replaced either with
+ # - path/to/a/certain/${vendor}/config_file
+ # or
+ # - 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
+ }
+ regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" f
+ regsub {([/\\])([^/\\_]*)_([^/\\]*$)} $f "\\1\\2-\\3" 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/time_support.c b/src/helper/time_support.c
index dda3cb3e4e..535b0626f1 100644
--- a/src/helper/time_support.c
+++ b/src/helper/time_support.c
@@ -15,79 +15,45 @@
#include "config.h"
#endif
+#include
+
#include "time_support.h"
-/* calculate difference between two struct timeval values */
-int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
+int duration_start(struct duration *duration)
{
- if (x->tv_usec < y->tv_usec) {
- int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
- y->tv_usec -= 1000000 * nsec;
- y->tv_sec += nsec;
- }
- if (x->tv_usec - y->tv_usec > 1000000) {
- int nsec = (x->tv_usec - y->tv_usec) / 1000000;
- y->tv_usec += 1000000 * nsec;
- y->tv_sec -= nsec;
- }
-
- result->tv_sec = x->tv_sec - y->tv_sec;
- result->tv_usec = x->tv_usec - y->tv_usec;
-
- /* Return 1 if result is negative. */
- return x->tv_sec < y->tv_sec;
-}
+ int64_t now = timeval_ms();
-int timeval_add_time(struct timeval *result, long sec, long usec)
-{
- result->tv_sec += sec;
- result->tv_usec += usec;
+ if (now < 0)
+ return ERROR_FAIL;
- while (result->tv_usec > 1000000) {
- result->tv_usec -= 1000000;
- result->tv_sec++;
- }
+ duration->start_ms = now;
- return 0;
+ return ERROR_OK;
}
-/* compare two timevals and return -1/0/+1 accordingly */
-int timeval_compare(const struct timeval *x, const struct timeval *y)
+int duration_measure(struct duration *duration)
{
- if (x->tv_sec < y->tv_sec)
- return -1;
- else if (x->tv_sec > y->tv_sec)
- return 1;
- else if (x->tv_usec < y->tv_usec)
- return -1;
- else if (x->tv_usec > y->tv_usec)
- return 1;
- else
- return 0;
-}
+ int64_t now = timeval_ms();
-int duration_start(struct duration *duration)
-{
- return gettimeofday(&duration->start, NULL);
-}
+ if (now < 0)
+ return ERROR_FAIL;
-int duration_measure(struct duration *duration)
-{
- struct timeval end;
- int retval = gettimeofday(&end, NULL);
- if (retval == 0)
- timeval_subtract(&duration->elapsed, &end, &duration->start);
- return retval;
+ duration->elapsed_ms = now - duration->start_ms;
+
+ return ERROR_OK;
}
float duration_elapsed(const struct duration *duration)
{
- float t = duration->elapsed.tv_sec;
- t += (float)duration->elapsed.tv_usec / 1000000.0;
- return t;
+ return ((float)duration->elapsed_ms) / 1000;
}
float duration_kbps(const struct duration *duration, size_t count)
{
- return count / (1024.0 * duration_elapsed(duration));
+ int64_t elapsed_ms = duration->elapsed_ms;
+
+ if (elapsed_ms == 0)
+ elapsed_ms = 1;
+
+ return 1000 * count / (1024 * (float)elapsed_ms);
}
diff --git a/src/helper/time_support.h b/src/helper/time_support.h
index c984296819..36d08c4431 100644
--- a/src/helper/time_support.h
+++ b/src/helper/time_support.h
@@ -21,16 +21,12 @@
#include
#endif
-int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
-int timeval_add_time(struct timeval *result, long sec, long usec);
-int timeval_compare(const struct timeval *x, const struct timeval *y);
-
/** @returns gettimeofday() timeval as 64-bit in ms */
int64_t timeval_ms(void);
struct duration {
- struct timeval start;
- struct timeval elapsed;
+ int64_t start_ms;
+ int64_t elapsed_ms;
};
/** Update the duration->start field to start the @a duration measurement. */
diff --git a/src/helper/time_support_common.c b/src/helper/time_support_common.c
index 9d17a315bf..6d78c1f42f 100644
--- a/src/helper/time_support_common.c
+++ b/src/helper/time_support_common.c
@@ -9,6 +9,9 @@
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
+ * *
+ * Copyright (C) 2026 by Grant Ramsay *
+ * grant.ramsay@hotmail.com *
***************************************************************************/
#ifdef HAVE_CONFIG_H
@@ -17,14 +20,44 @@
#include "time_support.h"
+#ifdef _WIN32
+#include
+#endif
+
/* simple and low overhead fetching of ms counter. Use only
* the difference between ms counters returned from this fn.
+ * Use QueryPerformanceCounter for Windows, else
+ * clock_gettime with CLOCK_MONOTONIC_RAW if available, else
+ * clock_gettime with CLOCK_MONOTONIC if available, else
+ * fallback to gettimeofday (susceptible to NTP adjustments)
*/
int64_t timeval_ms(void)
{
+#ifdef _WIN32
+ static LARGE_INTEGER frequency;
+ LARGE_INTEGER now;
+ // frequency is static and only read once on the first call
+ if (frequency.QuadPart == 0 && !QueryPerformanceFrequency(&frequency))
+ return -1;
+ if (!QueryPerformanceCounter(&now))
+ return -1;
+ return (now.QuadPart * 1000) / frequency.QuadPart;
+#elif defined(HAVE_CLOCK_GETTIME)
+#ifdef CLOCK_MONOTONIC_RAW
+ clockid_t clk_id = CLOCK_MONOTONIC_RAW;
+#else
+ clockid_t clk_id = CLOCK_MONOTONIC;
+#endif
+ struct timespec now;
+ int retval = clock_gettime(clk_id, &now);
+ if (retval < 0)
+ return retval;
+ return (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
+#else
struct timeval now;
int retval = gettimeofday(&now, NULL);
if (retval < 0)
return retval;
return (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
+#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/helper/util.c b/src/helper/util.c
index 2e9f6155ee..1ced8bd5f4 100644
--- a/src/helper/util.c
+++ b/src/helper/util.c
@@ -40,3 +40,26 @@ int util_init(struct command_context *cmd_ctx)
{
return register_commands(cmd_ctx, NULL, util_command_handlers);
}
+
+bool is_memory_regions_overlap(target_addr_t start1,
+ unsigned int size1,
+ target_addr_t start2,
+ unsigned int size2)
+{
+ /* Two memory regions: [S1,E1] and [S2,E2] where:
+ * E1 = S1 + size1 - 1, E2 = S2 + size2 - 1
+ *
+ * After normalization:
+ * Region 1: [0, size1 - 1]
+ * Region 2: [start2 - start1, (start2 - start1) + size2 - 1]
+ *
+ * Intersection cases:
+ * 1. Normalized region 2 wraps around 0 (unsigned overflow)
+ * 2. Start of normalized region 2 is within region 1
+ */
+ start2 -= start1;
+ target_addr_t end1 = size1 - 1;
+ target_addr_t end2 = start2 + size2 - 1;
+
+ return start2 > end2 || start2 <= end1;
+}
diff --git a/src/helper/util.h b/src/helper/util.h
index 3ccdc4fdfe..c101356784 100644
--- a/src/helper/util.h
+++ b/src/helper/util.h
@@ -10,5 +10,7 @@
struct command_context;
int util_init(struct command_context *cmd_ctx);
+bool is_memory_regions_overlap(target_addr_t start1, unsigned int size1,
+ target_addr_t start2, unsigned int size2);
#endif /* OPENOCD_HELPER_UTIL_H */
diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c
index 6785a74ef1..dcdc047f31 100644
--- a/src/jtag/adapter.c
+++ b/src/jtag/adapter.c
@@ -34,12 +34,18 @@ enum adapter_clk_mode {
#define DEFAULT_CLOCK_SPEED_KHZ 100U
+#define MAX_USB_IDS 16
+
/**
* Adapter configuration
*/
static struct {
bool adapter_initialized;
char *usb_location;
+ // vid = pid = 0 marks the end of the list.
+ uint16_t usb_vids[MAX_USB_IDS + 1];
+ uint16_t usb_pids[MAX_USB_IDS + 1];
+ char *product_name;
char *serial;
enum adapter_clk_mode clock_mode;
int speed_khz;
@@ -53,17 +59,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);
@@ -194,6 +202,7 @@ int adapter_quit(void)
free(adapter_config.serial);
free(adapter_config.usb_location);
+ free(adapter_config.product_name);
struct jtag_tap *t = jtag_all_taps();
while (t) {
@@ -269,15 +278,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;
}
@@ -323,11 +332,26 @@ static void adapter_usb_set_location(const char *location)
}
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
+const uint16_t *adapter_usb_get_vids(void)
+{
+ return adapter_config.usb_vids;
+}
+
+const uint16_t *adapter_usb_get_pids(void)
+{
+ return adapter_config.usb_pids;
+}
+
const char *adapter_usb_get_location(void)
{
return adapter_config.usb_location;
}
+const char *adapter_usb_get_product_name(void)
+{
+ return adapter_config.product_name;
+}
+
bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len)
{
size_t path_step, string_length;
@@ -613,34 +637,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 +874,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 +933,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;
}
@@ -936,8 +979,8 @@ COMMAND_HANDLER(adapter_gpio_config_handler)
int gpio_idx = get_gpio_index(CMD_ARGV[0]);
if (gpio_idx == -1) {
- LOG_ERROR("adapter has no gpio named %s", CMD_ARGV[0]);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ command_print(CMD, "adapter has no gpio named %s", CMD_ARGV[0]);
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
if (CMD_ARGC == 1) {
@@ -949,7 +992,7 @@ COMMAND_HANDLER(adapter_gpio_config_handler)
while (i < CMD_ARGC) {
LOG_DEBUG("Processing %s", CMD_ARGV[i]);
- if (isdigit(*CMD_ARGV[i])) {
+ if (isdigit((unsigned char)*CMD_ARGV[i])) {
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], gpio_config->gpio_num);
++i;
continue;
@@ -1031,9 +1074,34 @@ COMMAND_HANDLER(adapter_gpio_config_handler)
}
}
- LOG_ERROR("illegal option for adapter %s %s: %s",
+ 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;
+ }
+ }
+
+ command_print(CMD, "illegal option for adapter %s %s: %s",
CMD_NAME, gpio_map[gpio_idx].name, CMD_ARGV[i]);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ return ERROR_COMMAND_ARGUMENT_INVALID;
}
/* Force swdio_dir init state to be compatible with swdio init state */
@@ -1058,7 +1126,61 @@ COMMAND_HANDLER(handle_usb_location_command)
}
#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */
+COMMAND_HANDLER(handle_usb_vid_pid_command)
+{
+ if (MAX_USB_IDS * 2 < CMD_ARGC) {
+ LOG_WARNING("ignoring extra IDs in vid_pid "
+ "(maximum is %d pairs)", MAX_USB_IDS);
+ CMD_ARGC = MAX_USB_IDS * 2;
+ }
+
+ if (CMD_ARGC < 2 || (CMD_ARGC & 1)) {
+ LOG_WARNING("incomplete vid_pid configuration directive");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ unsigned int i;
+ for (i = 0; i < CMD_ARGC; i += 2) {
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], adapter_config.usb_vids[i / 2]);
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], adapter_config.usb_pids[i / 2]);
+ }
+
+ /* null termination */
+ adapter_config.usb_vids[i / 2] = 0;
+ adapter_config.usb_pids[i / 2] = 0;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_usb_product_name_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ free(adapter_config.product_name);
+ adapter_config.product_name = NULL;
+
+ if (*CMD_ARGV[0])
+ adapter_config.product_name = strdup(CMD_ARGV[0]);
+
+ return ERROR_OK;
+}
+
static const struct command_registration adapter_usb_command_handlers[] = {
+ {
+ .name = "vid_pid",
+ .handler = &handle_usb_vid_pid_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the USB VID and PID of the USB device",
+ .usage = "(vid pid)*",
+ },
+ {
+ .name = "product_name",
+ .handler = &handle_usb_product_name_command,
+ .mode = COMMAND_CONFIG,
+ .help = "set the USB product name of the USB device",
+ .usage = "name",
+ },
#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS
{
.name = "location",
@@ -1168,7 +1290,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..c22ac53fe1 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;
};
@@ -82,9 +92,17 @@ bool is_adapter_initialized(void);
/** @returns USB location string set with command 'adapter usb location' */
const char *adapter_usb_get_location(void);
+/** @returns USB product name set with command 'adapter usb product_name' */
+const char *adapter_usb_get_product_name(void);
+
/** @returns true if USB location string is "-[.[...]]" */
bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len);
+/** @returns USB VIDs set with command 'adapter usb vid_pid' */
+const uint16_t *adapter_usb_get_vids(void);
+/** @returns USB PIDs set with command 'adapter usb vid_pid' */
+const uint16_t *adapter_usb_get_pids(void);
+
/** @returns The current adapter speed setting. */
int adapter_get_speed(int *speed);
@@ -119,6 +137,8 @@ const char *adapter_gpio_get_name(enum adapter_gpio_config_index idx);
*/
const struct adapter_gpio_config *adapter_gpio_get_config(void);
+extern struct adapter_driver *adapter_driver;
+
#define ADAPTER_GPIO_NOT_SET UINT_MAX
#endif /* OPENOCD_JTAG_ADAPTER_H */
diff --git a/src/jtag/core.c b/src/jtag/core.c
index 06fe2a428f..204c18c6b0 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -115,8 +115,6 @@ struct jtag_event_callback {
/* callbacks to inform high-level handlers about JTAG state changes */
static struct jtag_event_callback *jtag_event_callbacks;
-extern struct adapter_driver *adapter_driver;
-
void jtag_set_flush_queue_sleep(int ms)
{
jtag_flush_queue_sleep = ms;
@@ -148,19 +146,16 @@ static bool jtag_poll_en = true;
bool is_jtag_poll_safe(void)
{
/* Polling can be disabled explicitly with set_enabled(false).
- * It can also be masked with mask().
- * It is also implicitly disabled while TRST is active and
- * while SRST is gating the JTAG clock.
- */
- if (!jtag_poll_en)
+ * It can also be masked with mask(). */
+ if (!jtag_poll_en || !jtag_poll)
return false;
- if (!transport_is_jtag())
- return jtag_poll;
-
- if (!jtag_poll || jtag_trst != 0)
+ /* On JTAG transport it is also implicitly disabled while TRST is active */
+ if (transport_is_jtag() && jtag_trst == 1)
return false;
- return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING);
+
+ /* On any transport while SRST is gating the JTAG clock or other debug HW */
+ return jtag_srst != 1 || (jtag_reset_config & RESET_SRST_NO_GATING);
}
bool jtag_poll_get_enabled(void)
@@ -559,6 +554,10 @@ void jtag_add_pathmove(unsigned int num_states, const enum tap_state *path)
{
enum tap_state cur_state = cmd_queue_cur_state;
+ // quit if there is nothing to do
+ if (num_states == 0)
+ return;
+
/* the last state has to be a stable state */
if (!tap_is_state_stable(path[num_states - 1])) {
LOG_ERROR("BUG: TAP path doesn't finish in a stable state");
@@ -1002,60 +1001,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;
}
@@ -1586,22 +1585,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 f10ed971ea..652ac4eb6e 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -120,8 +120,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
@@ -172,8 +170,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
@@ -181,15 +179,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
@@ -203,6 +203,15 @@ endif
if AM335XGPIO
DRIVERFILES += %D%/am335xgpio.c
endif
+if CH347
+DRIVERFILES += %D%/ch347.c
+endif
+if CKLINK
+DRIVERFILES += %D%/cklink.c
+endif
+if XVC
+DRIVERFILES += %D%/xvc.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..fdaeeae248 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,772 @@ 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;
-
- bytes_remaining = size;
-
- /* 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 */
- 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));
-}
-
-/**
- * Move from the current TAP state to the current TAP end state.
- *
- * @param device pointer to struct angie identifying ANGIE driver instance.
- * @return on success: ERROR_OK
- * @return on failure: ERROR_FAIL
- */
-static int angie_queue_statemove(struct angie *device)
-{
- 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;
- }
-
- 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());
-
- ret = angie_append_clock_tms_cmd(device, tms_count, tms_sequence);
-
- if (ret == ERROR_OK)
- tap_set_state(tap_get_end_state());
-
- return ret;
-}
-
-/**
- * Perform a scan operation on a JTAG register.
- *
- * @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_scan(struct angie *device, struct jtag_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;
-
- /* 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);
-
- /* 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;
- }
-
- /* 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);
- }
-
- /* 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;
- }
+ 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) {
+ free(buffer);
+ return ret;
+ }
+ ret = angie_buffer_append(device, 1, tms, tdi);
+ if (ret != ERROR_OK) {
+ free(buffer);
+ return ret;
+ }
+ }
+ 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) {
- free(tdi_buffer_start);
- free(tdo_buffer_start);
+ free(buffer);
return ret;
}
}
- free(tdi_buffer_start);
+ 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;
+ }
- /* Set current state to the end state requested by the command */
- tap_set_state(cmd->cmd.scan->end_state);
+ 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 the TAP into the Test Logic Reset state.
+ * Return JTAG RUNTEST command size in bytes
*
- * @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: RUNTEST command
+ * @return size of command in the transfer buffer in bytes
*/
-static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd)
+static int angie_jtag_runtest_size(struct angie *device,
+ const struct runtest_command *cmd)
{
- int ret = angie_append_clock_tms_cmd(device, 5, 0xff);
+ int cmd_size = 0;
- if (ret == ERROR_OK)
- tap_set_state(TAP_RESET);
+ 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;
- return ret;
+ return cmd_size;
}
/**
- * Run Test.
+ * Execute JTAG RUNTEST command
*
- * 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: SCAN 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_runtest(struct angie *device,
+ const struct runtest_command *cmd)
{
int ret;
+ enum tap_state saved_end_state = tap_get_end_state();
+
+ LOG_DEBUG_IO("RUNTEST: %d cycles", cmd->num_cycles);
- /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */
+ // only do a state_move when we're not already in IDLE
if (tap_get_state() != TAP_IDLE) {
angie_set_end_state(TAP_IDLE);
- angie_queue_statemove(device);
+ ret = angie_state_move(device, 0);
+ if (ret != ERROR_OK)
+ return ret;
}
- /* Generate the clock cycles */
- ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles);
+ // 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;
- /* 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);
+ // 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;
}
return ERROR_OK;
}
/**
- * Execute a JTAG_RESET command
+ * Execute JTAG TMS command
+ * Clock a bunch of TMS transitions, to change the JTAG
+ * state machine.
*
- * @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: TMS command
+ * @return ERROR_OK on success, negative error code otherwise
*/
-static int angie_reset(int trst, int srst)
+static int angie_jtag_execute_tms(struct angie *device,
+ const struct tms_command *cmd)
{
- struct angie *device = angie_handle;
- uint8_t low = 0, high = 0;
-
- if (trst) {
- tap_set_state(TAP_RESET);
- low |= SIGNAL_TRST;
- } else {
- high |= SIGNAL_TRST;
- }
-
- if (srst)
- low |= SIGNAL_SRST;
- else
- high |= SIGNAL_SRST;
+ unsigned int num_bits = cmd->num_bits;
+ const uint8_t *bits = cmd->bits;
- 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;
+ LOG_DEBUG_IO("TMS: %d bits", num_bits);
- angie_clear_queue(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);
}
/**
- * Move to one TAP state or several states in succession.
+ * Execute JTAG RESET command
+ * Control /TRST and /SYSRST pins.
+ * Perform immediate bitbang transaction.
*
- * @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: RESET 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_reset(struct angie *device,
+ const struct reset_command *cmd)
{
- int ret, state_count;
- enum tap_state *path;
- uint8_t tms_sequence;
+ LOG_DEBUG_IO("RESET: trst %i srst %i", cmd->trst, cmd->srst);
+
+ 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);
- unsigned int num_states = cmd->cmd.pathmove->num_states;
- path = cmd->cmd.pathmove->path;
- state_count = 0;
+ 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
- while (num_states > 0) {
- unsigned int batch_size;
+ 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
- tms_sequence = 0;
+ return angie_buffer_append_simple(device, out_value);
+}
- /* 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--;
- }
+/**
+ * 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: Angie device pointer
+ * @param cmd: STABLECLOCKS command
+ * @return ERROR_OK on success, negative error code otherwise
+ */
+static int angie_jtag_execute_stableclocks(struct angie *device,
+ const struct stableclocks_command *cmd)
+{
+ int tms = (tap_get_state() == TAP_RESET ? 1 : 0);
- /* 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 +1374,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..38c73efc2e 100644
--- a/src/jtag/drivers/arm-jtag-ew.c
+++ b/src/jtag/drivers/arm-jtag-ew.c
@@ -76,9 +76,7 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length);
/* helper functions */
static int armjtagew_get_version_info(void);
-#ifdef _DEBUG_USB_COMMS_
static void armjtagew_debug_buffer(uint8_t *buffer, int length);
-#endif
static struct armjtagew *armjtagew_handle;
@@ -94,69 +92,68 @@ 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);
+ armjtagew_debug_buffer(buffer, (scan_size + 7) / 8);
-#ifdef _DEBUG_USB_COMMS_
- 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;
}
@@ -641,9 +638,7 @@ static int armjtagew_tap_execute(void)
LOG_DEBUG_IO("pending scan result, length = %d", length);
-#ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer(buffer, byte_length);
-#endif
if (jtag_read_buffer(buffer, command) != ERROR_OK) {
armjtagew_tap_init();
@@ -743,9 +738,8 @@ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length)
LOG_DEBUG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result);
-#ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer(usb_out_buffer, out_length);
-#endif
+
if (result != ERROR_OK)
return -1;
return transferred;
@@ -760,29 +754,29 @@ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length)
LOG_DEBUG_IO("armjtagew_usb_read, result = %d", result);
-#ifdef _DEBUG_USB_COMMS_
armjtagew_debug_buffer(usb_in_buffer, result);
-#endif
+
if (result != ERROR_OK)
return -1;
return transferred;
}
-#ifdef _DEBUG_USB_COMMS_
#define BYTES_PER_LINE 16
static void armjtagew_debug_buffer(uint8_t *buffer, int length)
{
+ if (!LOG_LEVEL_IS(LOG_LVL_DEBUG_USB))
+ return;
+
char line[8 + 3 * BYTES_PER_LINE + 1];
for (int i = 0; i < length; i += BYTES_PER_LINE) {
int n = snprintf(line, 9, "%04x", i);
for (int j = i; j < i + BYTES_PER_LINE && j < length; j++)
n += snprintf(line + n, 4, " %02x", buffer[j]);
- LOG_DEBUG("%s", line);
+ LOG_DEBUG_USB("%s", line);
/* Prevent GDB timeout (writing to log might take some time) */
keep_alive();
}
}
-#endif
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index 1a105aac44..eccbe06b8d 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -31,28 +31,22 @@ static off_t bcm2835_peri_base = 0x20000000;
#define BCM2835_GPIO_MODE_OUTPUT 1
/* GPIO setup macros */
-#define MODE_GPIO(_g) ({ \
- typeof(_g) g = (_g); \
- *(pio_base + (g / 10)) >> ((g % 10) * 3) & 7; \
-})
+#define BCM2835_GPIO_REG_READ(offset) \
+ (*(pio_base + (offset)))
-#define INP_GPIO(_g) do { \
- typeof(_g) g1 = (_g); \
- *(pio_base + (g1 / 10)) &= ~(7 << ((g1 % 10) * 3)); \
-} while (0)
+#define BCM2835_GPIO_REG_WRITE(offset, value) \
+ (*(pio_base + (offset)) = (value))
-#define SET_MODE_GPIO(_g, m) do { \
- typeof(_g) g = (_g); \
- /* clear the mode bits first, then set as necessary */ \
- INP_GPIO(g); \
- *(pio_base + (g / 10)) |= ((m) << ((g % 10) * 3)); \
-} while (0)
+#define BCM2835_GPIO_SET_REG_BITS(offset, bit_mask) \
+ (*(pio_base + (offset)) |= (bit_mask))
-#define OUT_GPIO(g) SET_MODE_GPIO(g, BCM2835_GPIO_MODE_OUTPUT)
+#define BCM2835_GPIO_CLEAR_REG_BITS(offset, bit_mask) \
+ (*(pio_base + (offset)) &= ~(bit_mask))
-#define GPIO_SET (*(pio_base + 7)) /* sets bits which are 1, ignores bits which are 0 */
-#define GPIO_CLR (*(pio_base + 10)) /* clears bits which are 1, ignores bits which are 0 */
-#define GPIO_LEV (*(pio_base + 13)) /* current level of the pin */
+#define BCM2835_GPIO_MODE_ADDR(gpio_pin_num) (pio_base + ((gpio_pin_num) / 10))
+#define BCM2835_GPIO_SET_ADDR(gpio_pin_num) (pio_base + 7 + ((gpio_pin_num) / 32))
+#define BCM2835_GPIO_CLR_ADDR(gpio_pin_num) (pio_base + 10 + ((gpio_pin_num) / 32))
+#define BCM2835_GPIO_LEVEL_ADDR(gpio_pin_num) (pio_base + 13 + ((gpio_pin_num) / 32))
static int dev_mem_fd;
static volatile uint32_t *pio_base = MAP_FAILED;
@@ -66,10 +60,75 @@ static unsigned int jtag_delay;
static const struct adapter_gpio_config *adapter_gpio_config;
static struct initial_gpio_state {
unsigned int mode;
- unsigned int output_level;
+ bool output_level;
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
static uint32_t initial_drive_strength_etc;
+static struct {
+ volatile uint32_t *swdio_clr_set_addr[2];
+ uint32_t swdio_mask;
+ volatile uint32_t *swdio_read_level_addr;
+ uint32_t swdio_level_shift_bits;
+ bool swdio_active_low;
+ volatile uint32_t *swdio_mode_addr;
+ uint32_t swdio_mode_input_mask;
+ uint32_t swdio_mode_output_mask;
+ volatile uint32_t *swclk_clr_set_addr[2];
+ uint32_t swclk_mask;
+ volatile uint32_t *tdi_clr_set_addr[2];
+ uint32_t tdi_mask;
+ volatile uint32_t *tms_clr_set_addr[2];
+ uint32_t tms_mask;
+ volatile uint32_t *tck_clr_set_addr[2];
+ uint32_t tck_mask;
+ volatile uint32_t *tdo_read_level_addr;
+ uint32_t tdo_level_shift_bits;
+ bool tdo_active_low;
+} gpio_control;
+
+/* GPFSEL[0,5], read the function select bits of specified GPIO pin number */
+static inline unsigned int bcm2835_get_mode(unsigned int gpio_pin_num)
+{
+ return (BCM2835_GPIO_REG_READ((gpio_pin_num / 10)) >> ((gpio_pin_num % 10) * 3) & 7);
+}
+
+/* GPLEV[13,14], current level of the pin */
+static inline bool bcm2835_get_level(unsigned int gpio_pin_num)
+{
+ return ((BCM2835_GPIO_REG_READ((13 + (gpio_pin_num / 32))) >> (gpio_pin_num % 32)) & 1);
+}
+
+/* set GPIO pin as input */
+static inline void bcm2835_set_input(unsigned int gpio_pin_num)
+{
+ BCM2835_GPIO_CLEAR_REG_BITS((gpio_pin_num / 10), (7 << ((gpio_pin_num % 10) * 3)));
+}
+
+/* clear the mode bits first, then set as necessary */
+static inline void bcm2835_set_mode(unsigned int gpio_pin_num, unsigned char mode)
+{
+ bcm2835_set_input(gpio_pin_num);
+ BCM2835_GPIO_SET_REG_BITS((gpio_pin_num / 10), (mode << ((gpio_pin_num % 10) * 3)));
+}
+
+/* set GPIO pin as output */
+static inline void bcm2835_set_output(unsigned int gpio_pin_num)
+{
+ bcm2835_set_mode(gpio_pin_num, BCM2835_GPIO_MODE_OUTPUT);
+}
+
+/* GPSET[7,8], sets bits which are 1, ignores bits which are 0 */
+static inline void bcm2835_gpio_set(unsigned int gpio_pin_num)
+{
+ BCM2835_GPIO_REG_WRITE((7 + (gpio_pin_num / 32)), (1 << (gpio_pin_num % 32)));
+}
+
+/* GPCLR[10,11], clears bits which are 1, ignores bits which are 0 */
+static inline void bcm2835_gpio_clear(unsigned int gpio_pin_num)
+{
+ BCM2835_GPIO_REG_WRITE((10 + (gpio_pin_num / 32)), (1 << (gpio_pin_num % 32)));
+}
+
static inline const char *bcm2835_get_mem_dev(void)
{
if (bcm2835_peri_mem_dev)
@@ -96,7 +155,7 @@ static inline void bcm2835_delay(void)
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
{
/* Only chip 0 is supported, accept unset value (-1) too */
- return adapter_gpio_config[idx].gpio_num <= 31;
+ return adapter_gpio_config[idx].gpio_num <= 53;
}
static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int value)
@@ -105,27 +164,27 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va
switch (gpio_config->drive) {
case ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL:
if (value)
- GPIO_SET = 1 << gpio_config->gpio_num;
+ bcm2835_gpio_set(gpio_config->gpio_num);
else
- GPIO_CLR = 1 << gpio_config->gpio_num;
+ bcm2835_gpio_clear(gpio_config->gpio_num);
/* For performance reasons assume the GPIO is already set as an output
* and therefore the call can be omitted here.
*/
break;
case ADAPTER_GPIO_DRIVE_MODE_OPEN_DRAIN:
if (value) {
- INP_GPIO(gpio_config->gpio_num);
+ bcm2835_set_input(gpio_config->gpio_num);
} else {
- GPIO_CLR = 1 << gpio_config->gpio_num;
- OUT_GPIO(gpio_config->gpio_num);
+ bcm2835_gpio_clear(gpio_config->gpio_num);
+ bcm2835_set_output(gpio_config->gpio_num);
}
break;
case ADAPTER_GPIO_DRIVE_MODE_OPEN_SOURCE:
if (value) {
- GPIO_SET = 1 << gpio_config->gpio_num;
- OUT_GPIO(gpio_config->gpio_num);
+ bcm2835_gpio_set(gpio_config->gpio_num);
+ bcm2835_set_output(gpio_config->gpio_num);
} else {
- INP_GPIO(gpio_config->gpio_num);
+ bcm2835_set_input(gpio_config->gpio_num);
}
break;
}
@@ -135,12 +194,12 @@ static void set_gpio_value(const struct adapter_gpio_config *gpio_config, int va
static void restore_gpio(enum adapter_gpio_config_index idx)
{
if (is_gpio_config_valid(idx)) {
- SET_MODE_GPIO(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode);
+ bcm2835_set_mode(adapter_gpio_config[idx].gpio_num, initial_gpio_state[idx].mode);
if (initial_gpio_state[idx].mode == BCM2835_GPIO_MODE_OUTPUT) {
if (initial_gpio_state[idx].output_level)
- GPIO_SET = 1 << adapter_gpio_config[idx].gpio_num;
+ bcm2835_gpio_set(adapter_gpio_config[idx].gpio_num);
else
- GPIO_CLR = 1 << adapter_gpio_config[idx].gpio_num;
+ bcm2835_gpio_clear(adapter_gpio_config[idx].gpio_num);
}
}
bcm2835_gpio_synchronize();
@@ -151,9 +210,8 @@ static void initialize_gpio(enum adapter_gpio_config_index idx)
if (!is_gpio_config_valid(idx))
return;
- initial_gpio_state[idx].mode = MODE_GPIO(adapter_gpio_config[idx].gpio_num);
- unsigned int shift = adapter_gpio_config[idx].gpio_num;
- initial_gpio_state[idx].output_level = (GPIO_LEV >> shift) & 1;
+ initial_gpio_state[idx].mode = bcm2835_get_mode(adapter_gpio_config[idx].gpio_num);
+ initial_gpio_state[idx].output_level = bcm2835_get_level(adapter_gpio_config[idx].gpio_num);
LOG_DEBUG("saved GPIO mode for %s (GPIO %d %d): %d",
adapter_gpio_get_name(idx), adapter_gpio_config[idx].chip_num, adapter_gpio_config[idx].gpio_num,
initial_gpio_state[idx].mode);
@@ -171,35 +229,29 @@ static void initialize_gpio(enum adapter_gpio_config_index idx)
set_gpio_value(&adapter_gpio_config[idx], 1);
break;
case ADAPTER_GPIO_INIT_STATE_INPUT:
- INP_GPIO(adapter_gpio_config[idx].gpio_num);
+ bcm2835_set_input(adapter_gpio_config[idx].gpio_num);
break;
}
/* Direction for non push-pull is already set by set_gpio_value() */
if (adapter_gpio_config[idx].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL
&& adapter_gpio_config[idx].init_state != ADAPTER_GPIO_INIT_STATE_INPUT)
- OUT_GPIO(adapter_gpio_config[idx].gpio_num);
+ bcm2835_set_output(adapter_gpio_config[idx].gpio_num);
bcm2835_gpio_synchronize();
}
static enum bb_value bcm2835gpio_read(void)
{
- unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num;
- uint32_t value = (GPIO_LEV >> shift) & 1;
- return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low ? BB_HIGH : BB_LOW);
+ bool value = ((*gpio_control.tdo_read_level_addr >> gpio_control.tdo_level_shift_bits) & 1);
+ return (value ^ gpio_control.tdo_active_low) ? BB_HIGH : BB_LOW;
}
static int bcm2835gpio_write(int tck, int tms, int tdi)
{
- uint32_t set = tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
- tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
- tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
- uint32_t clear = !tck << adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num |
- !tms << adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num |
- !tdi << adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num;
+ *gpio_control.tdi_clr_set_addr[tdi] = gpio_control.tdi_mask;
+ *gpio_control.tms_clr_set_addr[tms] = gpio_control.tms_mask;
+ *gpio_control.tck_clr_set_addr[tck] = gpio_control.tck_mask; /* Write clock last */
- GPIO_SET = set;
- GPIO_CLR = clear;
bcm2835_gpio_synchronize();
bcm2835_delay();
@@ -210,16 +262,9 @@ static int bcm2835gpio_write(int tck, int tms, int tdi)
/* Requires push-pull drive mode for swclk and swdio */
static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
{
- swclk = swclk ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0);
- swdio = swdio ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
+ *gpio_control.swdio_clr_set_addr[swdio] = gpio_control.swdio_mask;
+ *gpio_control.swclk_clr_set_addr[swclk] = gpio_control.swclk_mask; /* Write clock last */
- uint32_t set = swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
- swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
- uint32_t clear = !swclk << adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num |
- !swdio << adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
-
- GPIO_SET = set;
- GPIO_CLR = clear;
bcm2835_gpio_synchronize();
bcm2835_delay();
@@ -266,9 +311,11 @@ static void bcm2835_swdio_drive(bool is_output)
if (is_output) {
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 1);
- OUT_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ /* per bcm2835_set_output, clear mode bits then set the pin to output */
+ *gpio_control.swdio_mode_addr = (gpio_control.swdio_mode_output_mask |
+ (*gpio_control.swdio_mode_addr & gpio_control.swdio_mode_input_mask));
} else {
- INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ *gpio_control.swdio_mode_addr &= gpio_control.swdio_mode_input_mask;
if (is_gpio_config_valid(ADAPTER_GPIO_IDX_SWDIO_DIR))
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO_DIR], 0);
}
@@ -277,9 +324,8 @@ static void bcm2835_swdio_drive(bool is_output)
static int bcm2835_swdio_read(void)
{
- unsigned int shift = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num;
- uint32_t value = (GPIO_LEV >> shift) & 1;
- return value ^ (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0);
+ bool value = ((*gpio_control.swdio_read_level_addr >> gpio_control.swdio_level_shift_bits) & 1);
+ return (int)(value ^ gpio_control.swdio_active_low);
}
static int bcm2835gpio_khz(int khz, int *jtag_speed)
@@ -515,6 +561,26 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
initialize_gpio(ADAPTER_GPIO_IDX_TMS);
initialize_gpio(ADAPTER_GPIO_IDX_TCK);
initialize_gpio(ADAPTER_GPIO_IDX_TRST);
+
+ /* flip the addresses used when pins are active low */
+ unsigned char idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].active_low ? 1 : 0;
+ gpio_control.tms_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num);
+ gpio_control.tms_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num);
+ gpio_control.tms_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TMS].gpio_num % 32));
+
+ idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].active_low ? 1 : 0;
+ gpio_control.tdi_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num);
+ gpio_control.tdi_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num);
+ gpio_control.tdi_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TDI].gpio_num % 32));
+
+ idx = adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].active_low ? 1 : 0;
+ gpio_control.tck_clr_set_addr[idx] = BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num);
+ gpio_control.tck_clr_set_addr[!idx] = BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num);
+ gpio_control.tck_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_TCK].gpio_num % 32));
+
+ gpio_control.tdo_read_level_addr = BCM2835_GPIO_LEVEL_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num);
+ gpio_control.tdo_level_shift_bits = (adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].gpio_num % 32);
+ gpio_control.tdo_active_low = adapter_gpio_config[ADAPTER_GPIO_IDX_TDO].active_low;
}
const struct bitbang_interface *bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_generic;
@@ -538,6 +604,30 @@ LOG_INFO("pads conf set to %08x", pads_base[BCM2835_PADS_GPIO_0_27_OFFSET]);
if (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL &&
adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].drive == ADAPTER_GPIO_DRIVE_MODE_PUSH_PULL) {
+ /* flip the addresses used when pins are active low */
+ unsigned char idx = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low ? 1 : 0;
+ gpio_control.swdio_clr_set_addr[idx] =
+ BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ gpio_control.swdio_clr_set_addr[!idx] =
+ BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ gpio_control.swdio_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 32));
+ gpio_control.swdio_read_level_addr =
+ BCM2835_GPIO_LEVEL_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ gpio_control.swdio_level_shift_bits = (adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 32);
+ gpio_control.swdio_active_low = adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].active_low;
+ gpio_control.swdio_mode_addr = BCM2835_GPIO_MODE_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ gpio_control.swdio_mode_input_mask =
+ ~(7 << ((adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 10) * 3));
+ gpio_control.swdio_mode_output_mask =
+ (1 << ((adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num % 10) * 3));
+
+ idx = adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].active_low ? 1 : 0;
+ gpio_control.swclk_clr_set_addr[idx] =
+ BCM2835_GPIO_CLR_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num);
+ gpio_control.swclk_clr_set_addr[!idx] =
+ BCM2835_GPIO_SET_ADDR(adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num);
+ gpio_control.swclk_mask = (1 << (adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK].gpio_num % 32));
+
LOG_DEBUG("BCM2835 GPIO using fast mode for SWD write");
bcm2835gpio_bitbang = &bcm2835gpio_bitbang_swd_write_fast;
} else {
@@ -570,7 +660,7 @@ static int bcm2835gpio_quit(void)
* current and final states of swdio and swdio_dir do not have to be
* considered to calculate the safe restoration order.
*/
- INP_GPIO(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
+ bcm2835_set_input(adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO].gpio_num);
restore_gpio(ADAPTER_GPIO_IDX_SWDIO_DIR);
restore_gpio(ADAPTER_GPIO_IDX_SWDIO);
restore_gpio(ADAPTER_GPIO_IDX_SWCLK);
diff --git a/src/jtag/drivers/bitbang.c b/src/jtag/drivers/bitbang.c
index c2e763ddb3..501830cc0f 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,66 @@ 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;
+ 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) {
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);
+ 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..7a1a93c1b6 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;
@@ -1157,9 +1157,7 @@ static unsigned char buspirate_jtag_command(int fd,
/* TODO add support for WIN32 and others ! */
static int buspirate_serial_open(char *port)
{
- int fd;
- fd = open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY);
- return fd;
+ return open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY);
}
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
new file mode 100644
index 0000000000..8a7cd7d326
--- /dev/null
+++ b/src/jtag/drivers/ch347.c
@@ -0,0 +1,2399 @@
+// 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 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 = default_ch347_vids;
+ const uint16_t *ch347_pids = default_ch347_pids;
+
+ if (adapter_usb_get_vids()[0] != 0) {
+ ch347_vids = adapter_usb_get_vids();
+ ch347_pids = adapter_usb_get_pids();
+ }
+
+ int retval = jtag_libusb_open(ch347_vids, ch347_pids,
+ adapter_usb_get_product_name(), &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;
+ }
+
+ // Fix for CH347F on ARM64
+ // Force set configuration 1 (required on some ARM64 platforms)
+ retval = libusb_set_configuration(ch347_handle, 1);
+ if (retval != LIBUSB_SUCCESS && retval != LIBUSB_ERROR_BUSY)
+ LOG_WARNING("CH347 set_configuration failed: %s", libusb_error_name(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;
+}
+
+static const struct command_registration ch347_command_handlers[] = {
+ {
+ .name = "ch347",
+ .mode = COMMAND_ANY,
+ .help = "perform ch347 management",
+ .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/cklink.c b/src/jtag/drivers/cklink.c
new file mode 100644
index 0000000000..0e974fe2ee
--- /dev/null
+++ b/src/jtag/drivers/cklink.c
@@ -0,0 +1,747 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * T-Head CK-Link JTAG adapter driver. *
+ * *
+ * Supports the CK-Link Lite V2 wire protocol used by T-Head probes and *
+ * Bouffalo Lab BL616/BL702 CK-Link clones. USB bulk with a framed *
+ * command protocol reverse-engineered from T-Head's DebugServer. *
+ * *
+ * Copyright (C) 2026 by William Markezana *
+ * *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "libusb_helper.h"
+
+// USB identification. Defaults can be overridden via `adapter usb vid_pid`.
+#define CKLINK_VID_BOUFFALO 0x42bf
+#define CKLINK_VID_THEAD 0x32bf
+#define CKLINK_PID_LITE_V2 0xb210
+
+#define CKLINK_USB_INTERFACE 0
+#define CKLINK_EP_OUT 0x02
+#define CKLINK_EP_IN 0x81
+#define CKLINK_USB_TIMEOUT_MS 1000
+#define CKLINK_USB_BUF_SIZE 2048
+
+// Wire-protocol framing bytes
+#define CKLINK_FRAME_START 0x68
+#define CKLINK_FRAME_END 0x16
+
+// Response frame layout: start + status + payload + checksum + end
+#define CKLINK_FRAME_OVERHEAD 4
+#define CKLINK_RESP_PAYLOAD_OFFSET 2
+
+// Opcodes
+#define CKLINK_OP_SELFREG_WRITE 0x06
+#define CKLINK_OP_SELFREG_READ 0x87
+#define CKLINK_OP_JTAG_BATCH 0x88
+
+// Self-register indices
+#define CKLINK_SR_CSR 0 // clock divider + CDI mode
+#define CKLINK_SR_MTCR_WAIT 1 // target-comm wait cycles
+#define CKLINK_SR_JTAG_CONFIG 8 // JTAG config word
+#define CKLINK_SELFREG_BYTES 4
+
+/*
+ * Init values replayed from a captured DebugServer session.
+ * sr0 (CSR): byte 0 = clock divider, byte 3 = CDI mode (0x60=5-wire JTAG,
+ * 0x61=2-wire cJTAG). The 5->2->5 mode toggle at end of init acts as a
+ * TAP reset: the wire driver re-initializes on each switch.
+ * sr1 MTCR_WAIT = 1000 cycles. sr8 JTAG_CONFIG: opaque, known-good.
+ */
+#define CKLINK_SR0_SETUP_CLK_BYTE 0x17 // ~2000 kHz
+#define CKLINK_SR0_RUN_CLK_BYTE 0x12 // ~2526 kHz, DebugServer default
+#define CKLINK_SR0_MODE_JTAG 0x60
+#define CKLINK_SR0_MODE_CJTAG 0x61
+#define CKLINK_SR1_INIT_VALUE 0x000003e8
+#define CKLINK_SR8_INIT_VALUE 0x00622250
+
+// freq_kHz = 48000 / (N + 1); cap at DebugServer-validated 0x12.
+#define CKLINK_CLK_SOURCE_KHZ 48000
+#define CKLINK_CLK_DIV_MIN CKLINK_SR0_RUN_CLK_BYTE
+#define CKLINK_CLK_DIV_MAX 0xff
+
+#define CKLINK_CSR(clk, mode) (((uint32_t)(mode) << 24) | (clk))
+
+// Batch opcode encodes IR/DR bit-counts in single bytes.
+#define CKLINK_MAX_SCAN_BITS 255
+#define CKLINK_MAX_SCAN_BYTES 32 // DIV_ROUND_UP(255, 8)
+
+// Synthesized IR when a DR scan arrives without a cached IR.
+#define CKLINK_PLACEHOLDER_IR_BITS 5
+#define CKLINK_PLACEHOLDER_IR_VALUE 0x01
+
+struct cklink_ctx {
+ struct libusb_device_handle *usb_dev;
+ uint8_t tx_buf[CKLINK_USB_BUF_SIZE];
+ uint8_t rx_buf[CKLINK_USB_BUF_SIZE];
+ uint8_t csr_clk;
+ uint8_t ir_value[CKLINK_MAX_SCAN_BYTES];
+ unsigned int ir_bits;
+ struct jtag_command *pending_ir_cmd;
+ uint8_t *scan_tdi;
+ uint8_t *scan_tdo;
+ size_t scan_buf_size;
+ bool long_scan_warned;
+ bool dropped_ir_warned;
+};
+
+static struct cklink_ctx *cklink_handle;
+
+// Built-in VID/PID list, used when `adapter usb vid_pid` is not set.
+static const uint16_t cklink_default_vids[] = {
+ CKLINK_VID_BOUFFALO,
+ CKLINK_VID_THEAD,
+ 0,
+};
+static const uint16_t cklink_default_pids[] = {
+ CKLINK_PID_LITE_V2,
+ CKLINK_PID_LITE_V2,
+ 0,
+};
+
+// Sum-mod-256.
+static uint8_t cklink_checksum(const uint8_t *buf, unsigned int len)
+{
+ uint8_t sum = 0;
+ for (unsigned int i = 0; i < len; i++)
+ sum += buf[i];
+ return sum;
+}
+
+/* Send a framed command; NULL rxlen means fire-and-forget (selfreg writes
+ * are not acknowledged). @p opcode selects the response-checksum rule. */
+static int cklink_usb_xfer(struct cklink_ctx *ck, uint8_t opcode,
+ unsigned int txlen, unsigned int *rxlen)
+{
+ int actual = 0;
+ int ret = jtag_libusb_bulk_write(ck->usb_dev, CKLINK_EP_OUT,
+ (char *)ck->tx_buf, txlen,
+ CKLINK_USB_TIMEOUT_MS, &actual);
+ if (ret != ERROR_OK || (unsigned int)actual != txlen) {
+ LOG_ERROR("CK-Link bulk write failed (ret=%d, actual=%d/%d)",
+ ret, actual, txlen);
+ return ERROR_FAIL;
+ }
+
+ if (!rxlen)
+ return ERROR_OK;
+
+ ret = jtag_libusb_bulk_read(ck->usb_dev, CKLINK_EP_IN,
+ (char *)ck->rx_buf, CKLINK_USB_BUF_SIZE,
+ CKLINK_USB_TIMEOUT_MS, &actual);
+ if (ret != ERROR_OK || actual < (int)CKLINK_FRAME_OVERHEAD) {
+ LOG_ERROR("CK-Link bulk read failed (ret=%d, actual=%d)",
+ ret, actual);
+ return ERROR_FAIL;
+ }
+ if (ck->rx_buf[0] != CKLINK_FRAME_START) {
+ LOG_ERROR("CK-Link bad response start byte 0x%02x",
+ ck->rx_buf[0]);
+ return ERROR_FAIL;
+ }
+ if (ck->rx_buf[actual - 1] != CKLINK_FRAME_END) {
+ LOG_ERROR("CK-Link bad response end byte 0x%02x",
+ ck->rx_buf[actual - 1]);
+ return ERROR_FAIL;
+ }
+ /*
+ * RX checksum is opcode-specific: selfreg reads sum all payload;
+ * single-entry JTAG batch sums all except the last byte of dr_tdo.
+ */
+ unsigned int csum_end = actual - ((opcode == CKLINK_OP_JTAG_BATCH) ? 3 : 2);
+ uint8_t computed = cklink_checksum(ck->rx_buf, csum_end);
+ if (computed != ck->rx_buf[actual - 2]) {
+ LOG_ERROR("CK-Link response checksum mismatch: op=0x%02x stated=0x%02x computed=0x%02x",
+ opcode, ck->rx_buf[actual - 2], computed);
+ return ERROR_FAIL;
+ }
+ // Status byte semantics undocumented; log non-zero for traces.
+ if (ck->rx_buf[1] != 0) {
+ LOG_DEBUG("CK-Link op=0x%02x returned status=0x%02x",
+ opcode, ck->rx_buf[1]);
+ }
+ *rxlen = (unsigned int)actual;
+ return ERROR_OK;
+}
+
+static unsigned int cklink_frame_start(struct cklink_ctx *ck, uint8_t opcode)
+{
+ ck->tx_buf[0] = CKLINK_FRAME_START;
+ ck->tx_buf[1] = opcode;
+ return 2;
+}
+
+static unsigned int cklink_frame_end(struct cklink_ctx *ck, unsigned int pos)
+{
+ assert(pos + 2 <= CKLINK_USB_BUF_SIZE);
+ ck->tx_buf[pos] = cklink_checksum(ck->tx_buf, pos);
+ ck->tx_buf[pos + 1] = CKLINK_FRAME_END;
+ return pos + 2;
+}
+
+static int cklink_selfreg_write(struct cklink_ctx *ck, uint8_t reg,
+ const uint8_t *value)
+{
+ unsigned int pos = cklink_frame_start(ck, CKLINK_OP_SELFREG_WRITE);
+ ck->tx_buf[pos++] = reg;
+ memcpy(&ck->tx_buf[pos], value, CKLINK_SELFREG_BYTES);
+ pos += CKLINK_SELFREG_BYTES;
+ pos = cklink_frame_end(ck, pos);
+ return cklink_usb_xfer(ck, CKLINK_OP_SELFREG_WRITE, pos, NULL);
+}
+
+static int cklink_selfreg_read(struct cklink_ctx *ck, uint8_t reg, uint8_t *value)
+{
+ unsigned int pos = cklink_frame_start(ck, CKLINK_OP_SELFREG_READ);
+ ck->tx_buf[pos++] = reg;
+ pos = cklink_frame_end(ck, pos);
+
+ unsigned int rxlen = 0;
+ int ret = cklink_usb_xfer(ck, CKLINK_OP_SELFREG_READ, pos, &rxlen);
+ if (ret != ERROR_OK)
+ return ret;
+
+ const unsigned int expected = CKLINK_FRAME_OVERHEAD + CKLINK_SELFREG_BYTES;
+ if (rxlen < expected) {
+ LOG_ERROR("CK-Link selfreg read response too short (%u < %u)",
+ rxlen, expected);
+ return ERROR_FAIL;
+ }
+ memcpy(value, &ck->rx_buf[CKLINK_RESP_PAYLOAD_OFFSET],
+ CKLINK_SELFREG_BYTES);
+ return ERROR_OK;
+}
+
+/* Single-entry batch scan. Scans > 255 bits are clamped with a one-time
+ * warning: chunking across entries breaks Shift-DR continuity, and
+ * erroring out here breaks OpenOCD's chain probe's -expected-id recovery. */
+static int cklink_jtag_scan(struct cklink_ctx *ck,
+ unsigned int ir_bits, const uint8_t *ir_tdi,
+ uint8_t *ir_tdo,
+ unsigned int dr_bits, const uint8_t *dr_tdi,
+ uint8_t *dr_tdo)
+{
+ if ((ir_bits > CKLINK_MAX_SCAN_BITS || dr_bits > CKLINK_MAX_SCAN_BITS)
+ && !ck->long_scan_warned) {
+ LOG_WARNING("CK-Link: scan exceeds %u-bit per-entry limit (ir=%u dr=%u); clamping",
+ CKLINK_MAX_SCAN_BITS, ir_bits, dr_bits);
+ ck->long_scan_warned = true;
+ }
+ if (ir_bits > CKLINK_MAX_SCAN_BITS)
+ ir_bits = CKLINK_MAX_SCAN_BITS;
+ if (dr_bits > CKLINK_MAX_SCAN_BITS)
+ dr_bits = CKLINK_MAX_SCAN_BITS;
+
+ const unsigned int ir_bytes = DIV_ROUND_UP(ir_bits, 8);
+ const unsigned int dr_bytes = DIV_ROUND_UP(dr_bits, 8);
+
+ unsigned int pos = cklink_frame_start(ck, CKLINK_OP_JTAG_BATCH);
+ ck->tx_buf[pos++] = 0; // entry_count - 1
+ ck->tx_buf[pos++] = (uint8_t)ir_bits;
+ if (ir_tdi)
+ memcpy(&ck->tx_buf[pos], ir_tdi, ir_bytes);
+ else
+ memset(&ck->tx_buf[pos], 0, ir_bytes);
+ pos += ir_bytes;
+ ck->tx_buf[pos++] = (uint8_t)dr_bits;
+ if (dr_tdi)
+ memcpy(&ck->tx_buf[pos], dr_tdi, dr_bytes);
+ else
+ memset(&ck->tx_buf[pos], 0, dr_bytes);
+ pos += dr_bytes;
+ pos = cklink_frame_end(ck, pos);
+
+ unsigned int rxlen = 0;
+ int ret = cklink_usb_xfer(ck, CKLINK_OP_JTAG_BATCH, pos, &rxlen);
+ if (ret != ERROR_OK)
+ return ret;
+
+ // Response: start + status + ir_tdo + dr_echo + dr_tdo + csum + end.
+ const unsigned int expected =
+ CKLINK_FRAME_OVERHEAD + ir_bytes + 1 + dr_bytes;
+ if (rxlen < expected) {
+ LOG_ERROR("CK-Link scan response truncated: got %u, need %u (ir=%u dr=%u)",
+ rxlen, expected, ir_bits, dr_bits);
+ return ERROR_FAIL;
+ }
+
+ if (ir_tdo && ir_bytes)
+ memcpy(ir_tdo, &ck->rx_buf[CKLINK_RESP_PAYLOAD_OFFSET], ir_bytes);
+
+ const unsigned int dr_tdo_offset =
+ CKLINK_RESP_PAYLOAD_OFFSET + ir_bytes + 1;
+ if (dr_tdo)
+ memcpy(dr_tdo, &ck->rx_buf[dr_tdo_offset], dr_bytes);
+
+ return ERROR_OK;
+}
+
+// Shift num_bits of idle cycles, chunked to the 255-bit protocol limit.
+static int cklink_idle_cycles(struct cklink_ctx *ck, unsigned int num_bits)
+{
+ static const uint8_t zeros[CKLINK_MAX_SCAN_BYTES] = { 0 };
+
+ while (num_bits > 0) {
+ unsigned int chunk = num_bits > CKLINK_MAX_SCAN_BITS
+ ? CKLINK_MAX_SCAN_BITS : num_bits;
+ int ret = cklink_jtag_scan(ck, 0, NULL, NULL,
+ chunk, zeros, NULL);
+ if (ret != ERROR_OK)
+ return ret;
+ num_bits -= chunk;
+ }
+ return ERROR_OK;
+}
+
+/* Flush a pending IR with a 1-bit dummy DR so its in_value gets populated
+ * with real captured IR TDO. Called at end of execute_queue so Capture-IR
+ * validation sees real hardware data. */
+static int cklink_flush_pending_ir(struct cklink_ctx *ck)
+{
+ if (!ck || !ck->pending_ir_cmd)
+ return ERROR_OK;
+
+ uint8_t ir_tdo[CKLINK_MAX_SCAN_BYTES] = { 0 };
+ uint8_t dummy_dr = 0;
+ int ret = cklink_jtag_scan(ck, ck->ir_bits, ck->ir_value, ir_tdo,
+ 1, &dummy_dr, NULL);
+ if (ret != ERROR_OK)
+ return ret;
+
+ struct scan_command *scan = ck->pending_ir_cmd->cmd.scan;
+ unsigned int off = 0;
+ for (unsigned int i = 0; i < scan->num_fields; i++) {
+ struct scan_field *f = &scan->fields[i];
+ if (f->in_value) {
+ buf_set_buf(ir_tdo, off, f->in_value, 0,
+ f->num_bits);
+ }
+ off += f->num_bits;
+ }
+ ck->pending_ir_cmd = NULL;
+ // ir_bits/ir_value stay valid: hardware IR is still what we cached.
+ return ERROR_OK;
+}
+
+static int cklink_execute_scan(struct cklink_ctx *ck, struct jtag_command *cmd)
+{
+ struct scan_command *scan = cmd->cmd.scan;
+
+ unsigned int total_bits = 0;
+ for (unsigned int i = 0; i < scan->num_fields; i++)
+ total_bits += scan->fields[i].num_bits;
+
+ if (total_bits == 0)
+ return ERROR_OK;
+
+ const unsigned int total_bytes = DIV_ROUND_UP(total_bits, 8);
+ if (total_bytes > ck->scan_buf_size) {
+ uint8_t *ntdi = realloc(ck->scan_tdi, total_bytes);
+ uint8_t *ntdo = realloc(ck->scan_tdo, total_bytes);
+ if (!ntdi || !ntdo) {
+ LOG_ERROR("CK-Link: out of memory for %u-bit scan",
+ total_bits);
+ // Partial success is fine; freed in cklink_quit.
+ if (ntdi)
+ ck->scan_tdi = ntdi;
+ if (ntdo)
+ ck->scan_tdo = ntdo;
+ return ERROR_FAIL;
+ }
+ ck->scan_tdi = ntdi;
+ ck->scan_tdo = ntdo;
+ ck->scan_buf_size = total_bytes;
+ }
+ memset(ck->scan_tdi, 0, total_bytes);
+ memset(ck->scan_tdo, 0, total_bytes);
+
+ unsigned int bit_offset = 0;
+ for (unsigned int i = 0; i < scan->num_fields; i++) {
+ struct scan_field *field = &scan->fields[i];
+ if (field->out_value) {
+ buf_set_buf(field->out_value, 0, ck->scan_tdi,
+ bit_offset, field->num_bits);
+ }
+ bit_offset += field->num_bits;
+ }
+
+ if (scan->ir_scan) {
+ /*
+ * Defer IR until paired with a DR (batch needs both).
+ * Back-to-back IR drops the first: mid-queue flush would
+ * cycle Capture-DR/Update-DR on the previous IR's register
+ * (e.g. DMI), triggering spurious transactions.
+ */
+ if (total_bytes > sizeof(ck->ir_value)) {
+ LOG_ERROR("CK-Link: IR scan of %u bits exceeds cache (%zu bytes)",
+ total_bits, sizeof(ck->ir_value));
+ return ERROR_JTAG_QUEUE_FAILED;
+ }
+ if (ck->pending_ir_cmd) {
+ if (!ck->dropped_ir_warned) {
+ LOG_WARNING("CK-Link: back-to-back IR scan dropped pending IR; multi-TAP chains are not supported");
+ ck->dropped_ir_warned = true;
+ } else {
+ LOG_DEBUG("CK-Link: dropping pending IR (%u bits) before new IR scan",
+ ck->ir_bits);
+ }
+ }
+ memcpy(ck->ir_value, ck->scan_tdi, total_bytes);
+ ck->ir_bits = total_bits;
+ ck->pending_ir_cmd = cmd;
+ return ERROR_OK;
+ }
+
+ // No cached IR yet: inject IDCODE placeholder so chain detection works.
+ const uint8_t placeholder_ir = CKLINK_PLACEHOLDER_IR_VALUE;
+ const unsigned int eff_ir_bits = ck->ir_bits ? ck->ir_bits
+ : CKLINK_PLACEHOLDER_IR_BITS;
+ const uint8_t *eff_ir_value = ck->ir_bits ? ck->ir_value : &placeholder_ir;
+ if (!ck->ir_bits)
+ LOG_DEBUG("CK-Link: DR scan with no cached IR; injecting IDCODE placeholder");
+
+ uint8_t ir_tdo_buf[CKLINK_MAX_SCAN_BYTES] = { 0 };
+ int ret = cklink_jtag_scan(ck, eff_ir_bits, eff_ir_value, ir_tdo_buf,
+ total_bits, ck->scan_tdi, ck->scan_tdo);
+ if (ret != ERROR_OK)
+ return ret;
+
+ // Scatter captured IR TDO back into the deferred IR command's fields.
+ if (ck->pending_ir_cmd) {
+ struct scan_command *ir_scan = ck->pending_ir_cmd->cmd.scan;
+ unsigned int ir_off = 0;
+ for (unsigned int i = 0; i < ir_scan->num_fields; i++) {
+ struct scan_field *f = &ir_scan->fields[i];
+ if (f->in_value) {
+ buf_set_buf(ir_tdo_buf, ir_off,
+ f->in_value, 0, f->num_bits);
+ }
+ ir_off += f->num_bits;
+ }
+ ck->pending_ir_cmd = NULL;
+ }
+
+ /*
+ * For clamped scans, fill un-shifted TDO with caller's TDI (models
+ * "no more TAPs past the limit" - a bare wire). Gives OpenOCD's
+ * bypass chain-length probe the expected end-of-chain marker.
+ */
+ if (total_bits > CKLINK_MAX_SCAN_BITS) {
+ buf_set_buf(ck->scan_tdi, CKLINK_MAX_SCAN_BITS,
+ ck->scan_tdo, CKLINK_MAX_SCAN_BITS,
+ total_bits - CKLINK_MAX_SCAN_BITS);
+ }
+
+ bit_offset = 0;
+ for (unsigned int i = 0; i < scan->num_fields; i++) {
+ struct scan_field *field = &scan->fields[i];
+ if (field->in_value) {
+ buf_set_buf(ck->scan_tdo, bit_offset,
+ field->in_value, 0, field->num_bits);
+ }
+ bit_offset += field->num_bits;
+ }
+
+ return ERROR_OK;
+}
+
+static int cklink_write_csr(struct cklink_ctx *ck, uint8_t clk, uint8_t mode)
+{
+ uint8_t buf[CKLINK_SELFREG_BYTES];
+ h_u32_to_le(buf, CKLINK_CSR(clk, mode));
+ return cklink_selfreg_write(ck, CKLINK_SR_CSR, buf);
+}
+
+// khz -> sr0 byte 0 divider, rounded up so we never exceed the request.
+static uint8_t cklink_khz_to_div(int khz)
+{
+ if (khz <= 0)
+ return CKLINK_CLK_DIV_MAX;
+ int n = ((CKLINK_CLK_SOURCE_KHZ + khz - 1) / khz) - 1;
+ if (n < CKLINK_CLK_DIV_MIN)
+ n = CKLINK_CLK_DIV_MIN;
+ if (n > CKLINK_CLK_DIV_MAX)
+ n = CKLINK_CLK_DIV_MAX;
+ return (uint8_t)n;
+}
+
+static int cklink_execute_tlr_reset(struct cklink_ctx *ck)
+{
+ // Probe-side reset via 5->2->5 mode toggle; target TAP reset not guaranteed.
+ int ret;
+
+ ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_CJTAG);
+ if (ret != ERROR_OK)
+ return ret;
+ ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_CJTAG);
+ if (ret != ERROR_OK)
+ return ret;
+ ret = cklink_write_csr(ck, ck->csr_clk, CKLINK_SR0_MODE_JTAG);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ck->ir_bits = 0;
+ memset(ck->ir_value, 0, sizeof(ck->ir_value));
+ ck->pending_ir_cmd = NULL;
+ tap_set_state(TAP_RESET);
+ return ERROR_OK;
+}
+
+static int cklink_execute_runtest(struct cklink_ctx *ck, struct jtag_command *cmd)
+{
+ return cklink_idle_cycles(ck, cmd->cmd.runtest->num_cycles);
+}
+
+static int cklink_execute_stableclocks(struct cklink_ctx *ck, struct jtag_command *cmd)
+{
+ // TMS=0 shifts only hold state in RTI; other stable states would advance.
+ return cklink_idle_cycles(ck, cmd->cmd.stableclocks->num_cycles);
+}
+
+static int cklink_execute_tms(struct jtag_command *cmd)
+{
+ // No TMS-sequence opcode: honoring JTAG_TMS is impossible.
+ LOG_ERROR("CK-Link: JTAG_TMS (%u bits) is not supported by this probe",
+ cmd->cmd.tms->num_bits);
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+}
+
+static int cklink_execute_reset(struct cklink_ctx *ck, struct jtag_command *cmd)
+{
+ // Only TRST is meaningful here: we have no separate SRST control.
+ if (cmd->cmd.reset->trst)
+ return cklink_execute_tlr_reset(ck);
+ return ERROR_OK;
+}
+
+static int cklink_execute_queue(struct jtag_command *cmd_queue)
+{
+ struct cklink_ctx *ck = cklink_handle;
+ if (!ck)
+ return ERROR_JTAG_INIT_FAILED;
+
+ for (struct jtag_command *cmd = cmd_queue; cmd; cmd = cmd->next) {
+ int ret;
+
+ switch (cmd->type) {
+ case JTAG_SCAN:
+ ret = cklink_execute_scan(ck, cmd);
+ break;
+ case JTAG_TLR_RESET:
+ ret = cklink_execute_tlr_reset(ck);
+ break;
+ case JTAG_RUNTEST:
+ ret = cklink_execute_runtest(ck, cmd);
+ break;
+ case JTAG_RESET:
+ ret = cklink_execute_reset(ck, cmd);
+ break;
+ case JTAG_PATHMOVE:
+ // No TMS-sequence opcode: honoring PATHMOVE is impossible.
+ LOG_ERROR("CK-Link: JTAG_PATHMOVE is not supported by this probe");
+ ret = ERROR_JTAG_NOT_IMPLEMENTED;
+ break;
+ case JTAG_STABLECLOCKS:
+ ret = cklink_execute_stableclocks(ck, cmd);
+ break;
+ case JTAG_TMS:
+ ret = cklink_execute_tms(cmd);
+ break;
+ case JTAG_SLEEP:
+ jtag_sleep(cmd->cmd.sleep->us);
+ ret = ERROR_OK;
+ break;
+ default:
+ LOG_ERROR("CK-Link: unsupported JTAG command %d",
+ cmd->type);
+ return ERROR_JTAG_QUEUE_FAILED;
+ }
+ if (ret != ERROR_OK)
+ return ret;
+ }
+ // Flush so any un-paired IR's in_value is populated before OpenOCD reads.
+ return cklink_flush_pending_ir(ck);
+}
+
+static int cklink_probe_init(struct cklink_ctx *ck)
+{
+ uint8_t sr1[CKLINK_SELFREG_BYTES];
+ uint8_t sr8[CKLINK_SELFREG_BYTES];
+ uint8_t readback[CKLINK_SELFREG_BYTES];
+ int ret;
+
+ h_u32_to_le(sr1, CKLINK_SR1_INIT_VALUE);
+ h_u32_to_le(sr8, CKLINK_SR8_INIT_VALUE);
+
+ // Configure at slow clock for cold-boot signal-integrity margin.
+ ret = cklink_write_csr(ck, CKLINK_SR0_SETUP_CLK_BYTE,
+ CKLINK_SR0_MODE_JTAG);
+ if (ret != ERROR_OK)
+ return ret;
+ ret = cklink_selfreg_write(ck, CKLINK_SR_MTCR_WAIT, sr1);
+ if (ret != ERROR_OK)
+ return ret;
+ ret = cklink_selfreg_write(ck, CKLINK_SR_JTAG_CONFIG, sr8);
+ if (ret != ERROR_OK)
+ return ret;
+ ret = cklink_write_csr(ck, CKLINK_SR0_RUN_CLK_BYTE,
+ CKLINK_SR0_MODE_JTAG);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = cklink_selfreg_read(ck, CKLINK_SR_CSR, readback);
+ if (ret != ERROR_OK)
+ return ret;
+ if (readback[3] != CKLINK_SR0_MODE_JTAG) {
+ LOG_WARNING("CK-Link: sr0 mode byte is 0x%02x, expected 0x%02x (5-wire JTAG)",
+ readback[3], CKLINK_SR0_MODE_JTAG);
+ }
+ ck->csr_clk = CKLINK_SR0_RUN_CLK_BYTE;
+
+ // Pre-load IR = IDCODE; 1-bit DR is the minimum the batch opcode accepts.
+ const uint8_t idcode_ir = CKLINK_PLACEHOLDER_IR_VALUE;
+ const uint8_t dummy_dr = 0;
+ return cklink_jtag_scan(ck, CKLINK_PLACEHOLDER_IR_BITS, &idcode_ir, NULL,
+ 1, &dummy_dr, NULL);
+}
+
+static int cklink_init(void)
+{
+ struct cklink_ctx *ck = calloc(1, sizeof(*ck));
+ if (!ck) {
+ LOG_ERROR("CK-Link: out of memory");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ const uint16_t *vids = adapter_usb_get_vids();
+ const uint16_t *pids = adapter_usb_get_pids();
+ if (!vids[0] || !pids[0]) {
+ vids = cklink_default_vids;
+ pids = cklink_default_pids;
+ }
+
+ const char *serial = adapter_get_required_serial();
+ if (jtag_libusb_open(vids, pids, serial,
+ &ck->usb_dev, NULL) != ERROR_OK) {
+ LOG_ERROR("CK-Link probe not found");
+ free(ck);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ libusb_set_auto_detach_kernel_driver(ck->usb_dev, 1);
+
+ int claim = libusb_claim_interface(ck->usb_dev, CKLINK_USB_INTERFACE);
+ if (claim != 0) {
+ LOG_ERROR("CK-Link: failed to claim interface %d: %s",
+ CKLINK_USB_INTERFACE, libusb_error_name(claim));
+ jtag_libusb_close(ck->usb_dev);
+ free(ck);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ if (cklink_probe_init(ck) != ERROR_OK) {
+ LOG_ERROR("CK-Link: probe initialization failed");
+ libusb_release_interface(ck->usb_dev, CKLINK_USB_INTERFACE);
+ jtag_libusb_close(ck->usb_dev);
+ free(ck);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ cklink_handle = ck;
+ tap_set_state(TAP_RESET);
+ LOG_INFO("CK-Link Lite V2 initialized (5-wire JTAG)");
+ return ERROR_OK;
+}
+
+static int cklink_quit(void)
+{
+ if (!cklink_handle)
+ return ERROR_OK;
+
+ libusb_release_interface(cklink_handle->usb_dev,
+ CKLINK_USB_INTERFACE);
+ jtag_libusb_close(cklink_handle->usb_dev);
+ free(cklink_handle->scan_tdi);
+ free(cklink_handle->scan_tdo);
+ free(cklink_handle);
+ cklink_handle = NULL;
+ return ERROR_OK;
+}
+
+static int cklink_speed(int speed)
+{
+ struct cklink_ctx *ck = cklink_handle;
+ if (!ck)
+ return ERROR_OK; // called before init
+
+ uint8_t div = cklink_khz_to_div(speed);
+ if (div == ck->csr_clk)
+ return ERROR_OK;
+ int ret = cklink_write_csr(ck, div, CKLINK_SR0_MODE_JTAG);
+ if (ret != ERROR_OK)
+ return ret;
+ ck->csr_clk = div;
+ int actual = CKLINK_CLK_SOURCE_KHZ / (div + 1);
+ LOG_DEBUG("CK-Link: adapter speed: requested %d kHz, programmed %d kHz (div=0x%02x)",
+ speed, actual, div);
+ return ERROR_OK;
+}
+
+static int cklink_khz(int khz, int *jtag_speed)
+{
+ if (khz == 0) {
+ LOG_ERROR("CK-Link: adaptive clocking (RTCK) is not supported");
+ return ERROR_JTAG_NOT_IMPLEMENTED;
+ }
+ uint8_t div = cklink_khz_to_div(khz);
+ int achievable = CKLINK_CLK_SOURCE_KHZ / (div + 1);
+ if (achievable != khz) {
+ static int last_clamp_khz;
+ if (khz != last_clamp_khz) {
+ LOG_WARNING("CK-Link: requested %d kHz clamped to %d kHz (div=0x%02x)",
+ khz, achievable, div);
+ last_clamp_khz = khz;
+ }
+ }
+ *jtag_speed = achievable;
+ return ERROR_OK;
+}
+
+static int cklink_speed_div(int speed, int *khz)
+{
+ *khz = speed;
+ return ERROR_OK;
+}
+
+static struct jtag_interface cklink_jtag_interface = {
+ .execute_queue = cklink_execute_queue,
+};
+
+struct adapter_driver cklink_adapter_driver = {
+ .name = "cklink",
+ .transport_ids = TRANSPORT_JTAG,
+ .transport_preferred_id = TRANSPORT_JTAG,
+
+ .init = cklink_init,
+ .quit = cklink_quit,
+ .speed = cklink_speed,
+ .khz = cklink_khz,
+ .speed_div = cklink_speed_div,
+
+ .jtag_ops = &cklink_jtag_interface,
+};
diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c
index 2bfcfcc2b0..759a6738d6 100644
--- a/src/jtag/drivers/cmsis_dap.c
+++ b/src/jtag/drivers/cmsis_dap.c
@@ -37,7 +37,8 @@
#include