--- /dev/null
+Dominic Rath <Dominic.Rath@gmx.de>
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+2005-07-03 Dominic Rath <Dominic.Rath@gmx.net>
+
+ * First public release
+
+2005-10-27 Dominic Rath <Dominic.Rath@gmx.net>
+
+ * First release of new codebase
--- /dev/null
+Prerequisites
+=============
+
+When building with support for FTDI FT2232 based devices, you need at least
+one of the following libraries:
+
+- libftdi (http://www.intra2net.com/opensource/ftdi/)
+- libftd2xx (http://www.ftdichip.com/Drivers/D2XX.htm)
+
+Basic Installation
+==================
+
+ OpenOCD is distributed without autotools generated files, i.e. without a
+configure script. Run ./bootstrap in the openocd directory to have all
+necessary files generated.
+
+ You have to explicitly enable desired JTAG interfaces during configure:
+
+./configure --enable-parport --enable-ftdi2232 --enable-ftd2xx \
+ --enable-amtjtagaccel
+
+ Under Windows/Cygwin, only the ftd2xx driver is supported for FT2232 based
+devices. You have to specify the location of the FTDI driver package with the
+--with-ftd2xx=/full/path/name option.
+
+Under Linux you can choose to build the parport driver with support for
+/dev/parportN instead of the default access with direct port I/O using
+--enable-parport_ppdev. This has the advantage of running OpenOCD without root
+privileges at the expense of a slight performance decrease.
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
--- /dev/null
+# not a GNU package. You can remove this line, if
+# have all needed files, that a GNU package needs
+AUTOMAKE_OPTIONS = foreign 1.4
+
+SUBDIRS = src
--- /dev/null
+ openocd
+
+ Free and Open On-Chip Debugging, In-System Programming
+ and Boundary-Scan Testing
+ Copyright (c) 2004, 2005 Dominic Rath
+
+The debugger uses an IEEE 1149-1 compliant JTAG TAP bus master to access on-chip
+debug functionality available on ARM7 and ARM9 based microcontrollers /
+system-on-chip solutions.
+
+User interaction is realized through a telnet command line interface and a gdb
+(The GNU Debugger) remote protocol server.
+
+Initially, support for two JTAG TAP bus master interfaces with public hardware
+schematics will be included, but support of additional hardware is an expressed
+goal.
+
+1. JTAG hardware
+
+Currently, openocd contains support for Wiggler-compatible paralell port
+dongles and a USB interface based on the FTDI FT2232, called USBJTAG-1.
+A new version of the USB interface, USB-JTAG v1.2, is available with complete
+schematics (http://www.fh-augsburg.de/~hhoegl/proj/volksmikro/usb-jtag/050910/).
+
+It was tested using Amontec's (www.amontec.com) Chameleon POD in it's
+Wiggler configuration, but homemade wigglers should work just as well.
+In order to use the reset functionality (warm-reset, debug from reset, reset
+and init), the choosen Wiggler has to connect the nSRST line.
+
+USBJTAG-1 is based on a FTDI DLP2232M module and a few additional parts.
+Schematics are freely available. USB-JTAG v1.2 doesn't use the DLP2232M, but
+has the FTDI chip soldered directly on the PCB. There are two drivers for these
+modules implemented, one using the open source libftdi, the other using FTDI's
+proprietary FTD2XX library.
+
+2. Supported cores
+
+This version of openocd supports the following cores:
+
+- ARM7TDMI
+- ARM9TDMI
+
+Support for cores with MMUs (ARM720t, ARM920t) is currently being merged.
+
+3. Licensing
+
+openocd is licensed under the terms of the GNU General Public License, see the
+file COPYING for details.
+
--- /dev/null
+- Additional cores. ARM9E(J)-S, ARM7TDMI-S, TI925, ...
+- Testing.
+- Additional jtag interfaces. Currently, only Wiggler style interfaces and
+ USBJTAG-1 are supported.
+- Testing.
+- Handle endianess. The configuration variable is there, but that's about it.
+ Currently, only little-endian targets and little-endian hosts are supported.
--- /dev/null
+aclocal \
+&& autoheader \
+&& automake --gnu --add-missing \
+&& autoconf
--- /dev/null
+AC_INIT(configure.in)
+
+AC_SEARCH_LIBS([ioperm], [ioperm])
+
+AC_CANONICAL_HOST
+
+build_bitbang=no
+is_cygwin=no
+
+AC_ARG_ENABLE(parport,
+ AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]),
+ [build_parport=$enableval], [build_parport=no])
+
+AC_ARG_ENABLE(parport_ppdev,
+ AS_HELP_STRING([--enable-parport_ppdev], [Enable use of ppdev (/dev/parportN) for parport]),
+ [parport_use_ppdev=$enableval], [parport_use_ppdev=no])
+
+AC_ARG_ENABLE(ftdi2232,
+ AS_HELP_STRING([--enable-ftdi2232], [Enable building the libftdi ft2232c driver]),
+ [build_ftdi2232=$enableval], [build_ftdi2232=no])
+
+AC_ARG_ENABLE(ftd2xx,
+ AS_HELP_STRING([--enable-ftd2xx], [Enable building the ftd2xx ft2232c driver]),
+ [build_ftd2xx=$enableval], [build_ftd2xx=no])
+
+AC_ARG_ENABLE(amtjtagaccel,
+ AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]),
+ [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
+
+AC_ARG_ENABLE(ep93xx,
+ AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]),
+ [build_ep93xx=$enableval], [build_ep93xx=no])
+
+AC_ARG_WITH(ftd2xx,
+ [AS_HELP_STRING(--with-ftd2xx,
+ [Where libftd2xx can be found <default=search>])],
+ [],
+ with_ftd2xx=search)
+
+if test $build_parport = yes; then
+ build_bitbang=yes
+ AC_DEFINE(BUILD_PARPORT, 1, [1 if you want parport.])
+else
+ AC_DEFINE(BUILD_PARPORT, 0, [0 if you don't want parport.])
+fi
+
+if test $build_ep93xx = yes; then
+ build_bitbang=yes
+ AC_DEFINE(BUILD_EP93XX, 1, [1 if you want ep93xx.])
+else
+ AC_DEFINE(BUILD_EP93XX, 0, [0 if you don't want ep93xx.])
+fi
+
+if test $parport_use_ppdev = yes; then
+ AC_DEFINE(PARPORT_USE_PPDEV, 1, [1 if you want parport to use ppdev.])
+else
+ AC_DEFINE(PARPORT_USE_PPDEV, 0, [0 if you don't want parport to use ppdev.])
+fi
+
+if test $build_bitbang = yes; then
+ AC_DEFINE(BUILD_BITBANG, 1, [1 if you want a bitbang interface.])
+else
+ AC_DEFINE(BUILD_BITBANG, 0, [0 if you don't want a bitbang interface.])
+fi
+
+if test $build_ftdi2232 = yes; then
+ AC_DEFINE(BUILD_FTDI2232, 1, [1 if you want libftdi ft2232.])
+else
+ AC_DEFINE(BUILD_FTDI2232, 0, [0 if you don't want libftdi ft2232.])
+fi
+
+if test $build_ftd2xx = yes; then
+ AC_DEFINE(BUILD_FTD2XX, 1, [1 if you want ftd2xx ft2232.])
+else
+ AC_DEFINE(BUILD_FTD2XX, 0, [0 if you don't want ftd2xx ft2232.])
+fi
+
+if test $build_amtjtagaccel = yes; then
+ AC_DEFINE(BUILD_AMTJTAGACCEL, 1, [1 if you want the Amontec JTAG-Accelerator driver.])
+else
+ AC_DEFINE(BUILD_AMTJTAGACCEL, 0, [0 if you don't want the Amontec JTAG-Accelerator driver.])
+fi
+
+case $host in
+ *-*-cygwin*)
+ is_cygwin=yes
+ AC_DEFINE(IS_CYGWIN, 1, [1 if building for Cygwin.])
+ ;;
+ *)
+ AC_DEFINE(IS_CYGWIN, 0, [0 if not building for Cygwin.])
+ ;;
+esac
+
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(openocd, 0.1)
+
+AM_CONDITIONAL(PARPORT, test $build_parport = yes)
+AM_CONDITIONAL(EP93XX, test $build_ep93xx = yes)
+AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
+AM_CONDITIONAL(FTDI2232, test $build_ftdi2232 = yes)
+AM_CONDITIONAL(FTD2XX, test $build_ftd2xx = yes)
+AM_CONDITIONAL(AMTJTAGACCEL, test $build_amtjtagaccel = yes)
+AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
+AM_CONDITIONAL(FTD2XXDIR, test $with_ftd2xx != search)
+
+AC_LANG_C
+AC_PROG_CC
+AC_PROG_RANLIB
+
+AC_SUBST(WITH_FTD2XX, $with_ftd2xx)
+
+AC_OUTPUT(Makefile src/Makefile src/helper/Makefile src/jtag/Makefile src/xsvf/Makefile src/target/Makefile src/server/Makefile src/flash/Makefile)
--- /dev/null
+#daemon configuration
+telnet_port 4444
+gdb_port 3333
+
+#interface
+interface ftdi2232
+jtag_speed 0
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst srst_pulls_trst
+
+#jtag scan chain
+#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
+jtag_device 4 0x1 0xf 0xe
+
+#target configuration
+daemon_startup reset
+#target <type> <startup mode>
+#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
+target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
+target_script 0 reset h2294_init.script
+run_and_halt_time 0 30
+working_area 0 0x40000000 0x40000 nobackup
+
+#flash configuration
+flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
+flash bank cfi 0x80000000 0x400000 2 2 0
--- /dev/null
+#daemon configuration
+telnet_port 4444
+gdb_port 3333
+
+#interface
+interface ftd2xx
+ftd2xx_device_desc "Amontec JTAGkey A"
+ftd2xx_layout jtagkey
+ftd2xx_vid_pid 0x0403 0xcff8
+jtag_speed 2
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst srst_pulls_trst
+
+#jtag scan chain
+#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
+jtag_device 4 0x1 0xf 0xe
+
+#target configuration
+daemon_startup reset
+#target <type> <startup mode>
+#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
+target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
+target_script 0 reset h2294_init.script
+run_and_halt_time 0 30
+working_area 0 0x40000000 0x40000 nobackup
+
+#flash configuration
+flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
+flash bank cfi 0x80000000 0x400000 2 2 0
--- /dev/null
+#daemon configuration
+telnet_port 4444
+gdb_port 3333
+
+#interface
+interface parport
+parport_port 0x378
+parport_cable wiggler
+jtag_speed 0
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst srst_pulls_trst
+
+#jtag scan chain
+#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
+jtag_device 4 0x1 0xf 0xe
+
+#target configuration
+daemon_startup reset
+#target <type> <startup mode>
+#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
+target arm7tdmi little run_and_halt 0 arm7tdmi-s_r4
+target_script 0 reset h2294_init.script
+run_and_halt_time 0 30
+working_area 0 0x40000000 0x40000 nobackup
+
+#flash configuration
+flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
+flash bank cfi 0x80000000 0x400000 2 2 0
--- /dev/null
+#daemon configuration
+telnet_port 4444
+gdb_port 3333
+
+#interface
+interface ftd2xx
+ftd2xx_device_desc "Amontec JTAGkey A"
+ftd2xx_layout "jtagkey"
+ftd2xx_vid_pid 0x0403 0xcff8
+jtag_speed 1
+#use combined on interfaces or targets that can't set TRST/SRST separately
+reset_config trst_and_srst
+
+#jtag scan chain
+#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
+jtag_device 4 0x1 0xf 0xe
+
+#target configuration
+daemon_startup reset
+#target <type> <endianess> <reset mode>
+target arm9tdmi little reset_halt 0 arm920t
+working_area 0 0x200000 0x4000 backup
+run_and_halt_time 0 5000
+
+#flash configuration
+#flash bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...]
+flash bank cfi 0x10000000 0x800000 2 2 0
+
--- /dev/null
+#daemon configuration
+telnet_port 4444
+gdb_port 3333
+
+#interface
+interface parport
+parport_cable chameleon
+jtag_speed 0
+
+#jtag scan chain
+# format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
+jtag_device 5 0x01 0x1f 0x01
--- /dev/null
+bin_PROGRAMS = openocd
+openocd_SOURCES = openocd.c
+
+# set the include path found by configure
+INCLUDES = -I$(top_srcdir)/src/helper \
+ -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target -I$(top_srcdir)/src/xsvf -I$(top_srcdir)/src/server \
+ -I$(top_srcdir)/src/flash $(all_includes)
+
+# the library search path.
+openocd_LDFLAGS = $(all_libraries)
+SUBDIRS = helper jtag xsvf target server flash
+
+if FTDI2232
+FTDI2232LIB = -lftdi
+else
+FTDI2232LIB =
+endif
+
+if IS_CYGWIN
+if FTD2XXDIR
+FTD2XXLDADD = @WITH_FTD2XX@/FTD2XX.lib
+else
+FTD2XXLDADD = -lftd2xx
+endif
+else
+FTD2XXLDADD = -lftd2xx
+endif
+
+if FTD2XX
+FTD2XXLIB = $(FTD2XXLDADD)
+else
+FTD2XXLIB =
+endif
+
+openocd_LDADD = $(top_builddir)/src/xsvf/libxsvf.a \
+ $(top_builddir)/src/target/libtarget.a $(top_builddir)/src/jtag/libjtag.a \
+ $(top_builddir)/src/helper/libhelper.a \
+ $(top_builddir)/src/server/libserver.a $(top_builddir)/src/helper/libhelper.a \
+ $(top_builddir)/src/flash/libflash.a $(top_builddir)/src/target/libtarget.a \
+ $(FTDI2232LIB) $(FTD2XXLIB)
--- /dev/null
+INCLUDES = -I$(top_srcdir)/src/helper -I$(top_srcdir)/src/jtag -I$(top_srcdir)/src/target $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libflash.a
+libflash_a_SOURCES = flash.c lpc2000.c cfi.c at91sam7.c str7x.c
+noinst_HEADERS = flash.h lpc2000.h cfi.h at91sam7.h str7x.h
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Magnus Lundin *
+ * lundin@mlu.mine.nu *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+/***************************************************************************
+There are some things to notice
+
+* AT91SAM7S64 is tested
+* All AT91SAM7Sxx and AT91SAM7Xxx should work but is not tested
+* All parameters are identified from onchip configuartion registers
+*
+* The flash controller handles erases automatically on a page (128/265 byte) basis
+* Only an EraseAll command is supported by the controller
+* Partial erases can be implemented in software by writing one 0xFFFFFFFF word to
+* some location in every page in the region to be erased
+*
+* Lock regions (sectors) are 32 or 64 pages
+*
+ ***************************************************************************/
+
+#include "at91sam7.h"
+
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "binarybuffer.h"
+#include "types.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int at91sam7_register_commands(struct command_context_s *cmd_ctx);
+int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
+int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
+int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int at91sam7_probe(struct flash_bank_s *bank);
+int at91sam7_erase_check(struct flash_bank_s *bank);
+int at91sam7_protect_check(struct flash_bank_s *bank);
+int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+u32 at91sam7_get_flash_status(flash_bank_t *bank);
+void at91sam7_set_flash_mode(flash_bank_t *bank,int mode);
+u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout);
+int at91sam7_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+flash_driver_t at91sam7_flash =
+{
+ .name = "at91sam7",
+ .register_commands = at91sam7_register_commands,
+ .flash_bank_command = at91sam7_flash_bank_command,
+ .erase = at91sam7_erase,
+ .protect = at91sam7_protect,
+ .write = at91sam7_write,
+ .probe = at91sam7_probe,
+ .erase_check = at91sam7_erase_check,
+ .protect_check = at91sam7_protect_check,
+ .info = at91sam7_info
+};
+
+
+char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
+long NVPSIZ[16] = {
+ 0,
+ 0x2000, /* 8K */
+ 0x4000, /* 16K */
+ 0x8000, /* 32K */
+ -1,
+ 0x10000, /* 64K */
+ -1,
+ 0x20000, /* 128K */
+ -1,
+ 0x40000, /* 256K */
+ 0x80000, /* 512K */
+ -1,
+ 0x100000, /* 1024K */
+ -1,
+ 0x200000, /* 2048K */
+ -1
+};
+
+long SRAMSIZ[16] = {
+ -1,
+ 0x0400, /* 1K */
+ 0x0800, /* 2K */
+ -1,
+ 0x1c000, /* 112K */
+ 0x1000, /* 4K */
+ 0x14000, /* 80K */
+ 0x28000, /* 160K */
+ 0x2000, /* 8K */
+ 0x4000, /* 16K */
+ 0x8000, /* 32K */
+ 0x10000, /* 64K */
+ 0x20000, /* 128K */
+ 0x40000, /* 256K */
+ 0x18000, /* 96K */
+ 0x80000, /* 512K */
+};
+
+u32 at91sam7_get_flash_status(flash_bank_t *bank)
+{
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+ long fsr;
+
+ target->type->read_memory(target, MC_FSR, 4, 1, (u8 *)&fsr);
+
+ return fsr;
+}
+
+/* Setup the timimg registers for nvbits or normal flash */
+void at91sam7_set_flash_mode(flash_bank_t *bank,int mode)
+{
+ u32 fmcn, fmr;
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+
+ if (mode != at91sam7_info->flashmode) {
+ /* mainf contains the number of main clocks in approx 500uS */
+ if (mode==1)
+ /* main clocks in 1uS */
+ fmcn = (at91sam7_info->mainf>>9)+1;
+ else
+ /* main clocks in 1.5uS */
+ fmcn = (at91sam7_info->mainf>>9)+(at91sam7_info->mainf>>10)+1;
+ DEBUG("fmcn: %i", fmcn);
+ fmr = fmcn<<16;
+ target->type->write_memory(target, MC_FSR, 4, 1, (u8 *)&fmr);
+ at91sam7_info->flashmode = mode;
+ }
+}
+
+u8 at91sam7_wait_status_busy(flash_bank_t *bank, int timeout)
+{
+ u32 status;
+
+ while ((!((status = at91sam7_get_flash_status(bank)) & 0x01)) && (timeout-- > 0))
+ {
+ DEBUG("status: 0x%x", status);
+ usleep(1000);
+ }
+
+ DEBUG("status: 0x%x", status);
+
+ if (status&0x0C)
+ {
+ ERROR("status register: 0x%x", status);
+ if (status & 0x4)
+ ERROR("Lock Error Bit Detected, Operation Abort");
+ if (status & 0x8)
+ ERROR("Invalid command and/or bad keyword, Operation Abort");
+ if (status & 0x10)
+ ERROR("Security Bit Set, Operation Abort");
+ }
+
+ return status;
+}
+
+int at91sam7_flash_command(struct flash_bank_s *bank,u8 cmd,u16 pagen)
+{
+ u32 fcr;
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+
+ fcr = (0x5A<<24) | (pagen<<8) | cmd;
+ target->type->write_memory(target, MC_FCR, 4, 1, (u8 *)&fcr);
+ DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
+
+ if (at91sam7_wait_status_busy(bank, 10)&0x0C)
+ {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ return ERROR_OK;
+}
+
+/* Read device id register, main clock frequency register and fill in driver info structure */
+int at91sam7_read_part_info(struct flash_bank_s *bank)
+{
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+ unsigned long cidr, mcfr, status;
+
+ if (at91sam7_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* Read and parse chip identification register */
+ target->type->read_memory(target, DBGU_CIDR, 4, 1, (u8 *)&cidr);
+
+ if (cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ at91sam7_info->cidr = cidr;
+ at91sam7_info->cidr_ext = (cidr>>31)&0x0001;
+ at91sam7_info->cidr_nvptyp = (cidr>>28)&0x0007;
+ at91sam7_info->cidr_arch = (cidr>>20)&0x00FF;
+ at91sam7_info->cidr_sramsiz = (cidr>>16)&0x000F;
+ at91sam7_info->cidr_nvpsiz2 = (cidr>>12)&0x000F;
+ at91sam7_info->cidr_nvpsiz = (cidr>>8)&0x000F;
+ at91sam7_info->cidr_eproc = (cidr>>5)&0x0007;
+ at91sam7_info->cidr_version = cidr&0x001F;
+ bank->size = NVPSIZ[at91sam7_info->cidr_nvpsiz];
+
+ DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch );
+
+ /* Read main clock freqency register */
+ target->type->read_memory(target, CKGR_MCFR, 4, 1, (u8 *)&mcfr);
+ if (mcfr&0x10000)
+ {
+ at91sam7_info->mainrdy = 1;
+ at91sam7_info->mainf = mcfr&0xFFFF;
+ at91sam7_info->usec_clocks = mcfr>>9;
+ }
+ else
+ {
+ at91sam7_info->mainrdy = 0;
+ at91sam7_info->mainf = 0;
+ at91sam7_info->usec_clocks = 0;
+ }
+
+ status = at91sam7_get_flash_status(bank);
+ at91sam7_info->lockbits = status>>16;
+ at91sam7_info->securitybit = (status>>4)&0x01;
+
+ if (at91sam7_info->cidr_arch == 0x70 ) {
+ at91sam7_info->num_nvmbits = 2;
+ at91sam7_info->nvmbits = (status>>8)&0x03;
+ bank->base = 0x100000;
+ bank->bus_width = 4;
+ if (bank->size==0x40000) /* AT91SAM7S256 */
+ {
+ at91sam7_info->num_lockbits = 16;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 16*64;
+ }
+ if (bank->size==0x20000) /* AT91SAM7S128 */
+ {
+ at91sam7_info->num_lockbits = 8;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 8*64;
+ }
+ if (bank->size==0x10000) /* AT91SAM7S64 */
+ {
+ at91sam7_info->num_lockbits = 16;
+ at91sam7_info->pagesize = 128;
+ at91sam7_info->pages_in_lockregion = 32;
+ at91sam7_info->num_pages = 16*32;
+ }
+ if (bank->size==0x08000) /* AT91SAM7S321/32 */
+ {
+ at91sam7_info->num_lockbits = 8;
+ at91sam7_info->pagesize = 128;
+ at91sam7_info->pages_in_lockregion = 32;
+ at91sam7_info->num_pages = 8*32;
+ }
+
+ return ERROR_OK;
+ }
+
+ if (at91sam7_info->cidr_arch == 0x71 ) {
+ at91sam7_info->num_nvmbits = 2;
+ at91sam7_info->nvmbits = (status>>8)&0x03;
+ bank->base = 0x100000;
+ bank->bus_width = 4;
+ if (bank->size==0x40000) /* AT91SAM7XC256 */
+ {
+ at91sam7_info->num_lockbits = 16;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 16*64;
+ }
+ if (bank->size==0x20000) /* AT91SAM7XC128 */
+ {
+ at91sam7_info->num_lockbits = 8;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 8*64;
+ }
+
+ return ERROR_OK;
+ }
+
+ if (at91sam7_info->cidr_arch == 0x75 ) {
+ at91sam7_info->num_nvmbits = 3;
+ at91sam7_info->nvmbits = (status>>8)&0x07;
+ bank->base = 0x100000;
+ bank->bus_width = 4;
+ if (bank->size==0x40000) /* AT91SAM7X256 */
+ {
+ at91sam7_info->num_lockbits = 16;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 16*64;
+ }
+ if (bank->size==0x20000) /* AT91SAM7X128 */
+ {
+ at91sam7_info->num_lockbits = 8;
+ at91sam7_info->pagesize = 256;
+ at91sam7_info->pages_in_lockregion = 64;
+ at91sam7_info->num_pages = 8*64;
+ }
+
+ return ERROR_OK;
+ }
+
+ if (at91sam7_info->cidr_arch != 0x70 )
+ {
+ WARNING("at91sam7 flash only tested for AT91SAM7Sxx series");
+ }
+ return ERROR_OK;
+}
+
+int at91sam7_erase_check(struct flash_bank_s *bank)
+{
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+ int i;
+
+ if (!at91sam7_info->working_area_size)
+ {
+ }
+ else
+ {
+ }
+
+ return ERROR_OK;
+}
+
+int at91sam7_protect_check(struct flash_bank_s *bank)
+{
+ u32 status;
+
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ status = at91sam7_get_flash_status(bank);
+ at91sam7_info->lockbits = status>>16;
+
+ return ERROR_OK;
+}
+
+
+int at91sam7_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
+
+ return ERROR_OK;
+}
+
+int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ at91sam7_flash_bank_t *at91sam7_info;
+
+ if (argc < 6)
+ {
+ WARNING("incomplete flash_bank at91sam7 configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
+ bank->driver_priv = at91sam7_info;
+
+ at91sam7_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
+ if (!at91sam7_info->target)
+ {
+ ERROR("no target '%i' configured", args[5]);
+ exit(-1);
+ }
+
+
+ /* part wasn't probed for info yet */
+ at91sam7_info->cidr = 0;
+
+ return ERROR_OK;
+}
+
+int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
+{
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+
+ if (at91sam7_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
+ {
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if ((first == 0) && (last == (at91sam7_info->num_lockbits-1)))
+ {
+ return at91sam7_flash_command(bank, EA, 0);
+ }
+
+ WARNING("Can only erase the whole flash area, pages are autoerased on write");
+ return ERROR_FLASH_OPERATION_FAILED;
+}
+
+int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ u32 cmd, pagen, status;
+ int lockregion;
+
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+
+ if (at91sam7_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= at91sam7_info->num_lockbits))
+ {
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Configure the flash controller timing */
+ at91sam7_set_flash_mode(bank,1);
+
+ for (lockregion=first;lockregion<=last;lockregion++)
+ {
+ pagen = lockregion*at91sam7_info->pages_in_lockregion;
+ if (set)
+ cmd = SLB;
+ else
+ cmd = CLB;
+ if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK)
+ {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+
+ status = at91sam7_get_flash_status(bank);
+ at91sam7_info->lockbits = status>>16;
+
+ return ERROR_OK;
+}
+
+
+int at91sam7_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+ target_t *target = at91sam7_info->target;
+ u32 dst_min_alignment, wcount, bytes_remaining = count;
+ u32 first_page, last_page, pagen, buffer_pos;
+ u32 fcr;
+
+ if (at91sam7_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ dst_min_alignment = at91sam7_info->pagesize;
+
+ if (offset % dst_min_alignment)
+ {
+ WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (at91sam7_info->cidr_arch == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ first_page = offset/dst_min_alignment;
+ last_page = CEIL(offset + count, dst_min_alignment);
+
+ DEBUG("first_page: %i, last_page: %i, count %i", first_page, last_page, count);
+
+ /* Configure the flash controller timing */
+ at91sam7_set_flash_mode(bank,2);
+
+ for (pagen=first_page; pagen<last_page; pagen++) {
+ if (bytes_remaining<dst_min_alignment)
+ count = bytes_remaining;
+ else
+ count = dst_min_alignment;
+ bytes_remaining -= count;
+
+ /* Write one block to the PageWriteBuffer */
+ buffer_pos = (pagen-first_page)*dst_min_alignment;
+ wcount = CEIL(count,4);
+ target->type->write_memory(target, bank->base, 4, wcount, buffer+buffer_pos);
+
+ /* Send Write Page command to Flash Controller */
+ if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK)
+ {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ DEBUG("Flash command: 0x%x, pagenumber:", fcr, pagen);
+ }
+
+ return ERROR_OK;
+}
+
+
+int at91sam7_probe(struct flash_bank_s *bank)
+{
+ /* we can't probe on an at91sam7
+ * if this is an at91sam7, it has the configured flash
+ */
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ WARNING("Cannot identify target as an AT91SAM");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ return ERROR_OK;
+}
+
+int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ int printed;
+ at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
+
+ if (at91sam7_info->cidr == 0)
+ {
+ at91sam7_read_part_info(bank);
+ }
+
+ if (at91sam7_info->cidr == 0)
+ {
+ printed = snprintf(buf, buf_size, "Cannot identify target as an AT91SAM\n");
+ buf += printed;
+ buf_size -= printed;
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ printed = snprintf(buf, buf_size, "\nat91sam7 information:\n");
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "cidr: 0x%8.8x, arch: 0x%4.4x, eproc: %s, version:0x%3.3x, flashsize: 0x%8.8x\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "main clock(estimated): %ikHz \n", at91sam7_info->mainf*2);
+ buf += printed;
+ buf_size -= printed;
+
+ if (at91sam7_info->num_lockbits>0) {
+ printed = snprintf(buf, buf_size, "pagesize: %i, lockbits: %i 0x%4.4x, pages in lock region: %i \n", at91sam7_info->pagesize, at91sam7_info->num_lockbits, at91sam7_info->lockbits,at91sam7_info->num_pages/at91sam7_info->num_lockbits);
+ buf += printed;
+ buf_size -= printed;
+ }
+
+ printed = snprintf(buf, buf_size, "securitybit: %i, nvmbits: 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->nvmbits);
+ buf += printed;
+ buf_size -= printed;
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Magnus Lundin *
+ * lundinªmlu.mine.nu *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef AT91SAM7_H
+#define AT91SAM7_H
+
+#include "flash.h"
+#include "target.h"
+
+typedef struct at91sam7_flash_bank_s
+{
+ struct target_s *target;
+ u32 working_area;
+ u32 working_area_size;
+
+ /* chip id register */
+ u32 cidr;
+ u16 cidr_ext;
+ u16 cidr_nvptyp;
+ u16 cidr_arch;
+ u16 cidr_sramsiz;
+ u16 cidr_nvpsiz;
+ u16 cidr_nvpsiz2;
+ u16 cidr_eproc;
+ u16 cidr_version;
+
+ /* flash geometry */
+ u16 num_pages;
+ u16 pagesize;
+ u16 pages_in_lockregion;
+ u8 num_erase_regions;
+ u32 *erase_region_info;
+
+ /* nv memory bits */
+ u16 num_lockbits;
+ u16 lockbits;
+ u16 num_nvmbits;
+ u16 nvmbits;
+ u8 securitybit;
+ u8 flashmode; /* 0: not init, 1: fmcn for nvbits (1uS), 2: fmcn for flash (1.5uS) */
+
+ /* main clock status */
+ u8 mainrdy;
+ u16 mainf;
+ u16 usec_clocks;
+
+} at91sam7_flash_bank_t;
+
+/* AT91SAM7 control registers */
+#define DBGU_CIDR 0xFFFFF240
+#define CKGR_MCFR 0xFFFFFC24
+#define MC_FMR 0xFFFFFF60
+#define MC_FCR 0xFFFFFF64
+#define MC_FSR 0xFFFFFF68
+
+/* Flash Controller Commands */
+#define WP 0x01
+#define SLB 0x02
+#define WPL 0x03
+#define CLB 0x04
+#define EA 0x08
+#define SGPB 0x0B
+#define CGPB 0x0D
+#define SSB 0x0F
+
+
+#endif /* AT91SAM7_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "cfi.h"
+
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+#include "types.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int cfi_register_commands(struct command_context_s *cmd_ctx);
+int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int cfi_erase(struct flash_bank_s *bank, int first, int last);
+int cfi_protect(struct flash_bank_s *bank, int set, int first, int last);
+int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int cfi_probe(struct flash_bank_s *bank);
+int cfi_erase_check(struct flash_bank_s *bank);
+int cfi_protect_check(struct flash_bank_s *bank);
+int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+int cfi_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+#define CFI_MAX_BUS_WIDTH 4
+
+flash_driver_t cfi_flash =
+{
+ .name = "cfi",
+ .register_commands = cfi_register_commands,
+ .flash_bank_command = cfi_flash_bank_command,
+ .erase = cfi_erase,
+ .protect = cfi_protect,
+ .write = cfi_write,
+ .probe = cfi_probe,
+ .erase_check = cfi_erase_check,
+ .protect_check = cfi_protect_check,
+ .info = cfi_info
+};
+
+inline u32 flash_address(flash_bank_t *bank, int sector, u32 offset)
+{
+ /* while the sector list isn't built, only accesses to sector 0 work */
+ if (sector == 0)
+ return bank->base + offset * bank->bus_width;
+ else
+ {
+ if (!bank->sectors)
+ {
+ ERROR("BUG: sector list not yet built");
+ exit(-1);
+ }
+ return bank->base + bank->sectors[sector].offset + offset * bank->bus_width;
+ }
+
+}
+
+void cfi_command(flash_bank_t *bank, u8 cmd, u8 *cmd_buf)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ int i;
+
+ if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
+ {
+ for (i = bank->bus_width; i > 0; i--)
+ {
+ *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+ }
+ }
+ else
+ {
+ for (i = 1; i <= bank->bus_width; i++)
+ {
+ *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd;
+ }
+ }
+}
+
+/* read unsigned 8-bit value from the bank
+ * flash banks are expected to be made of similar chips
+ * the query result should be the same for all
+ */
+u8 cfi_query_u8(flash_bank_t *bank, int sector, u32 offset)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 data[CFI_MAX_BUS_WIDTH];
+
+ target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
+
+ if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
+ return data[0];
+ else
+ return data[bank->bus_width - 1];
+}
+
+/* read unsigned 8-bit value from the bank
+ * in case of a bank made of multiple chips,
+ * the individual values are ORed
+ */
+u8 cfi_get_u8(flash_bank_t *bank, int sector, u32 offset)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 data[CFI_MAX_BUS_WIDTH];
+ int i;
+
+ target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data);
+
+ if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
+ {
+ for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ data[0] |= data[i];
+
+ return data[0];
+ }
+ else
+ {
+ u8 value = 0;
+ for (i = 0; i < bank->bus_width / bank->chip_width; i++)
+ value |= data[bank->bus_width - 1 - i];
+
+ return value;
+ }
+}
+
+u16 cfi_query_u16(flash_bank_t *bank, int sector, u32 offset)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 data[CFI_MAX_BUS_WIDTH * 2];
+
+ target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data);
+
+ if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
+ return data[0] | data[bank->bus_width] << 8;
+ else
+ return data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8;
+}
+
+u32 cfi_query_u32(flash_bank_t *bank, int sector, u32 offset)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 data[CFI_MAX_BUS_WIDTH * 4];
+
+ target->type->read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data);
+
+ if (cfi_info->target->endianness == TARGET_LITTLE_ENDIAN)
+ return data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24;
+ else
+ return data[bank->bus_width - 1] | data[(2* bank->bus_width) - 1] << 8 |
+ data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24;
+}
+
+void cfi_intel_clear_status_register(flash_bank_t *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+
+ if (target->state != TARGET_HALTED)
+ {
+ ERROR("BUG: attempted to clear status register while target wasn't halted");
+ exit(-1);
+ }
+
+ cfi_command(bank, 0x50, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+}
+
+u8 cfi_intel_wait_status_busy(flash_bank_t *bank, int timeout)
+{
+ u8 status;
+
+ while ((!((status = cfi_get_u8(bank, 0, 0x0)) & 0x80)) && (timeout-- > 0))
+ {
+ DEBUG("status: 0x%x", status);
+ usleep(1000);
+ }
+
+ DEBUG("status: 0x%x", status);
+
+ if (status != 0x80)
+ {
+ ERROR("status register: 0x%x", status);
+ if (status & 0x2)
+ ERROR("Block Lock-Bit Detected, Operation Abort");
+ if (status & 0x4)
+ ERROR("Program suspended");
+ if (status & 0x8)
+ ERROR("Low Programming Voltage Detected, Operation Aborted");
+ if (status & 0x10)
+ ERROR("Program Error / Error in Setting Lock-Bit");
+ if (status & 0x20)
+ ERROR("Error in Block Erasure or Clear Lock-Bits");
+ if (status & 0x40)
+ ERROR("Block Erase Suspended");
+
+ cfi_intel_clear_status_register(bank);
+ }
+
+ return status;
+}
+int cfi_read_intel_pri_ext(flash_bank_t *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = malloc(sizeof(cfi_intel_pri_ext_t));
+ target_t *target = cfi_info->target;
+ u8 command[8];
+
+ cfi_info->pri_ext = pri_ext;
+
+ pri_ext->pri[0] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0);
+ pri_ext->pri[1] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1);
+ pri_ext->pri[2] = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2);
+
+ if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I'))
+ {
+ cfi_command(bank, 0xf0, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ pri_ext->major_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3);
+ pri_ext->minor_version = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4);
+
+ DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
+
+ pri_ext->feature_support = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5);
+ pri_ext->suspend_cmd_support = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9);
+ pri_ext->blk_status_reg_mask = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa);
+
+ DEBUG("feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
+
+ pri_ext->vcc_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc);
+ pri_ext->vpp_optimal = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd);
+
+ DEBUG("Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x",
+ (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
+ (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
+
+ pri_ext->num_protection_fields = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe);
+ if (pri_ext->num_protection_fields != 1)
+ {
+ WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields);
+ }
+
+ pri_ext->prot_reg_addr = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf);
+ pri_ext->fact_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11);
+ pri_ext->user_prot_reg_size = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12);
+
+ DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
+
+ return ERROR_OK;
+}
+
+int cfi_intel_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ int printed;
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+
+ printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n");
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "feature_support: 0x%x, suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "Vcc opt: %1.1x.%1.1x, Vpp opt: %1.1x.%1.1x\n",
+ (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f,
+ (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size);
+
+ return ERROR_OK;
+}
+
+int cfi_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *cfi_cmd = register_command(cmd_ctx, NULL, "cfi", NULL, COMMAND_ANY, NULL);
+ /*
+ register_command(cmd_ctx, cfi_cmd, "part_id", cfi_handle_part_id_command, COMMAND_EXEC,
+ "print part id of cfi flash bank <num>");
+ */
+ return ERROR_OK;
+}
+
+/* flash_bank cfi <base> <size> <chip_width> <bus_width> <target#>
+ */
+int cfi_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ cfi_flash_bank_t *cfi_info;
+
+ if (argc < 6)
+ {
+ WARNING("incomplete flash_bank cfi configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ cfi_info = malloc(sizeof(cfi_flash_bank_t));
+ bank->driver_priv = cfi_info;
+
+ cfi_info->target = get_target_by_num(strtoul(args[5], NULL, 0));
+ if (!cfi_info->target)
+ {
+ ERROR("no target '%i' configured", args[5]);
+ exit(-1);
+ }
+
+ /* bank wasn't probed yet */
+ cfi_info->qry[0] = -1;
+
+ return ERROR_OK;
+}
+
+int cfi_intel_erase(struct flash_bank_s *bank, int first, int last)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+ int i;
+
+ cfi_intel_clear_status_register(bank);
+
+ for (i = first; i <= last; i++)
+ {
+ cfi_command(bank, 0x20, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+
+ cfi_command(bank, 0xd0, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+
+ if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->block_erase_timeout_typ)) == 0x80)
+ bank->sectors[i].is_erased = 1;
+ else
+ {
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ ERROR("couldn't erase block %i of flash bank at base 0x%x", i, bank->base);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ return ERROR_OK;
+}
+
+int cfi_erase(struct flash_bank_s *bank, int first, int last)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+
+ if (cfi_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+ {
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ return cfi_intel_erase(bank, first, last);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ return ERROR_OK;
+}
+
+int cfi_intel_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+ int i;
+
+ if (!(pri_ext->feature_support & 0x28))
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ cfi_intel_clear_status_register(bank);
+
+ for (i = first; i <= last; i++)
+ {
+ cfi_command(bank, 0x60, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+ if (set)
+ {
+ cfi_command(bank, 0x01, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+ bank->sectors[i].is_protected = 1;
+ }
+ else
+ {
+ cfi_command(bank, 0xd0, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+ bank->sectors[i].is_protected = 0;
+ }
+
+ cfi_intel_wait_status_busy(bank, 100);
+ }
+
+ /* if the device doesn't support individual block lock bits set/clear,
+ * all blocks have been unlocked in parallel, so we set those that should be protected
+ */
+ if ((!set) && (!(pri_ext->feature_support & 0x20)))
+ {
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ cfi_intel_clear_status_register(bank);
+ cfi_command(bank, 0x60, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+ if (bank->sectors[i].is_protected == 1)
+ {
+ cfi_command(bank, 0x01, command);
+ target->type->write_memory(target, flash_address(bank, i, 0x0), bank->bus_width, 1, command);
+ }
+
+ cfi_intel_wait_status_busy(bank, 100);
+ }
+ }
+
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ return ERROR_OK;
+}
+
+int cfi_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+
+ if (cfi_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+ {
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ cfi_intel_protect(bank, set, first, last);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ return ERROR_OK;
+}
+
+void cfi_add_byte(struct flash_bank_s *bank, u8 *word, u8 byte)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+
+ int i;
+
+ if (target->endianness == TARGET_LITTLE_ENDIAN)
+ {
+ /* shift bytes */
+ for (i = 0; i < bank->bus_width - 1; i++)
+ word[i] = word[i + 1];
+ word[bank->bus_width - 1] = byte;
+ }
+ else
+ {
+ /* shift bytes */
+ for (i = bank->bus_width - 1; i > 0; i--)
+ word[i] = word[i - 1];
+ word[0] = byte;
+ }
+}
+
+int cfi_intel_write_block(struct flash_bank_s *bank, u8 *buffer, u32 address, u32 count)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+ target_t *target = cfi_info->target;
+ reg_param_t reg_params[5];
+ armv4_5_algorithm_t armv4_5_info;
+ working_area_t *source;
+ u32 buffer_size = 32768;
+ u8 write_command[CFI_MAX_BUS_WIDTH];
+ int i;
+ int retval;
+
+ u32 word_32_code[] = {
+ 0xe4904004, /* loop: ldr r4, [r0], #4 */
+ 0xe5813000, /* str r3, [r1] */
+ 0xe5814000, /* str r4, [r1] */
+ 0xe5914000, /* busy ldr r4, [r1] */
+ 0xe3140080, /* tst r4, #0x80 */
+ 0x0afffffc, /* beq busy */
+ 0xe314007f, /* tst r4, #0x7f */
+ 0x1a000003, /* bne done */
+ 0xe2522001, /* subs r2, r2, #1 */
+ 0x0a000001, /* beq done */
+ 0xe2811004, /* add r1, r1 #4 */
+ 0xeafffff3, /* b loop */
+ 0xeafffffe, /* done: b -2 */
+ };
+
+ u32 word_16_code[] = {
+ 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */
+ 0xe1c130b0, /* strh r3, [r1] */
+ 0xe1c140b0, /* strh r4, [r1] */
+ 0xe1d140b0, /* busy ldrh r4, [r1] */
+ 0xe3140080, /* tst r4, #0x80 */
+ 0x0afffffc, /* beq busy */
+ 0xe314007f, /* tst r4, #0x7f */
+ 0x1a000003, /* bne done */
+ 0xe2522001, /* subs r2, r2, #1 */
+ 0x0a000001, /* beq done */
+ 0xe2811002, /* add r1, r1 #2 */
+ 0xeafffff3, /* b loop */
+ 0xeafffffe, /* done: b -2 */
+ };
+
+ u32 word_8_code[] = {
+ 0xe4d04001, /* loop: ldrb r4, [r0], #1 */
+ 0xe5c13000, /* strb r3, [r1] */
+ 0xe5c14000, /* strb r4, [r1] */
+ 0xe5d14000, /* busy ldrb r4, [r1] */
+ 0xe3140080, /* tst r4, #0x80 */
+ 0x0afffffc, /* beq busy */
+ 0xe314007f, /* tst r4, #0x7f */
+ 0x1a000003, /* bne done */
+ 0xe2522001, /* subs r2, r2, #1 */
+ 0x0a000001, /* beq done */
+ 0xe2811001, /* add r1, r1 #1 */
+ 0xeafffff3, /* b loop */
+ 0xeafffffe, /* done: b -2 */
+ };
+
+ cfi_intel_clear_status_register(bank);
+
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+ /* flash write code */
+ if (!cfi_info->write_algorithm)
+ {
+ if (target_alloc_working_area(target, 4 * 13, &cfi_info->write_algorithm) != ERROR_OK)
+ {
+ WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ };
+
+ /* write algorithm code to working area */
+ if (bank->bus_width == 1)
+ {
+ target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_8_code);
+ }
+ else if (bank->bus_width == 2)
+ {
+ target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_16_code);
+ }
+ else if (bank->bus_width == 4)
+ {
+ target_write_buffer(target, cfi_info->write_algorithm->address, 13 * 4, (u8*)word_32_code);
+ }
+ else
+ {
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+
+ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
+ {
+ buffer_size /= 2;
+ if (buffer_size <= 256)
+ {
+ /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
+ if (cfi_info->write_algorithm)
+ target_free_working_area(target, cfi_info->write_algorithm);
+
+ WARNING("no large enough working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+ };
+
+ 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_IN);
+
+ while (count > 0)
+ {
+ u32 thisrun_count = (count > buffer_size) ? buffer_size : count;
+
+ target_write_buffer(target, source->address, thisrun_count, buffer);
+
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ buf_set_u32(reg_params[1].value, 0, 32, address);
+ buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width);
+ cfi_command(bank, 0x40, write_command);
+ buf_set_u32(reg_params[3].value, 0, 32, buf_get_u32(write_command, 0, 32));
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 5, reg_params, cfi_info->write_algorithm->address, cfi_info->write_algorithm->address + (12 * 4), 10000, &armv4_5_info)) != ERROR_OK)
+ {
+ cfi_intel_clear_status_register(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (buf_get_u32(reg_params[4].value, 0, 32) != 0x80)
+ {
+ /* read status register (outputs debug inforation) */
+ cfi_intel_wait_status_busy(bank, 100);
+ cfi_intel_clear_status_register(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ buffer += thisrun_count;
+ address += thisrun_count;
+ count -= thisrun_count;
+ }
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+
+ return ERROR_OK;
+}
+
+int cfi_intel_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+
+ cfi_intel_clear_status_register(bank);
+ cfi_command(bank, 0x40, command);
+ target->type->write_memory(target, address, bank->bus_width, 1, command);
+
+ target->type->write_memory(target, address, bank->bus_width, 1, word);
+
+ if (cfi_intel_wait_status_busy(bank, 1000 * (1 << cfi_info->word_write_timeout_max)) != 0x80)
+ {
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ ERROR("couldn't write word at base 0x%x, address %x", bank->base, address);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int cfi_write_word(struct flash_bank_s *bank, u8 *word, u32 address)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ return cfi_intel_write_word(bank, word, address);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ return ERROR_FLASH_OPERATION_FAILED;
+}
+
+int cfi_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u32 address = bank->base + offset; /* address of first byte to be programmed */
+ u32 write_p, copy_p;
+ int align; /* number of unaligned bytes */
+ u8 current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being programmed */
+ int i;
+ int retval;
+
+ if (cfi_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ /* start at the first byte of the first word (bus_width size) */
+ write_p = address & ~(bank->bus_width - 1);
+ if ((align = address - write_p) != 0)
+ {
+ for (i = 0; i < bank->bus_width; i++)
+ current_word[i] = 0;
+ copy_p = write_p;
+
+ /* copy bytes before the first write address */
+ for (i = 0; i < align; ++i, ++copy_p)
+ {
+ u8 byte;
+ target->type->read_memory(target, copy_p, 1, 1, &byte);
+ cfi_add_byte(bank, current_word, byte);
+ }
+
+ /* add bytes from the buffer */
+ for (; (i < bank->bus_width) && (count > 0); i++)
+ {
+ cfi_add_byte(bank, current_word, *buffer++);
+ count--;
+ copy_p++;
+ }
+
+ /* if the buffer is already finished, copy bytes after the last write address */
+ for (; (count == 0) && (i < bank->bus_width); ++i, ++copy_p)
+ {
+ u8 byte;
+ target->type->read_memory(target, copy_p, 1, 1, &byte);
+ cfi_add_byte(bank, current_word, byte);
+ }
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ write_p = copy_p;
+ }
+
+ /* handle blocks of bus_size aligned 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, count);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+ if (retval != ERROR_OK)
+ {
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+ {
+ /* fall back to memory writes */
+ while (count > bank->bus_width)
+ {
+ for (i = 0; i < bank->bus_width; i++)
+ current_word[i] = 0;
+
+ for (i = 0; i < bank->bus_width; i++)
+ {
+ cfi_add_byte(bank, current_word, *buffer++);
+ }
+
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ write_p += bank->bus_width;
+ count -= bank->bus_width;
+ }
+ }
+ else
+ return retval;
+ }
+
+ /* handle unaligned tail bytes */
+ if (count > 0)
+ {
+ copy_p = write_p;
+ for (i = 0; i < bank->bus_width; i++)
+ current_word[i] = 0;
+
+ for (i = 0; (i < bank->bus_width) && (count > 0); ++i, ++copy_p)
+ {
+ cfi_add_byte(bank, current_word, *buffer++);
+ count--;
+ }
+ for (; i < bank->bus_width; ++i, ++copy_p)
+ {
+ u8 byte;
+ target->type->read_memory(target, copy_p, 1, 1, &byte);
+ cfi_add_byte(bank, current_word, byte);
+ }
+ retval = cfi_write_word(bank, current_word, write_p);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* return to read array mode */
+ cfi_command(bank, 0xf0, current_word);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
+ cfi_command(bank, 0xff, current_word);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, current_word);
+
+ return ERROR_OK;
+}
+
+int cfi_probe(struct flash_bank_s *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+
+
+ cfi_command(bank, 0x98, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
+
+ cfi_info->qry[0] = cfi_query_u8(bank, 0, 0x10);
+ cfi_info->qry[1] = cfi_query_u8(bank, 0, 0x11);
+ cfi_info->qry[2] = cfi_query_u8(bank, 0, 0x12);
+
+ if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y'))
+ {
+ cfi_command(bank, 0xf0, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ cfi_info->pri_id = cfi_query_u16(bank, 0, 0x13);
+ cfi_info->pri_addr = cfi_query_u16(bank, 0, 0x15);
+ cfi_info->alt_id = cfi_query_u16(bank, 0, 0x17);
+ cfi_info->alt_addr = cfi_query_u16(bank, 0, 0x19);
+
+ DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+
+ cfi_info->vcc_min = cfi_query_u8(bank, 0, 0x1b);
+ cfi_info->vcc_max = cfi_query_u8(bank, 0, 0x1c);
+ cfi_info->vpp_min = cfi_query_u8(bank, 0, 0x1d);
+ cfi_info->vpp_max = cfi_query_u8(bank, 0, 0x1e);
+ cfi_info->word_write_timeout_typ = cfi_query_u8(bank, 0, 0x1f);
+ cfi_info->buf_write_timeout_typ = cfi_query_u8(bank, 0, 0x20);
+ cfi_info->block_erase_timeout_typ = cfi_query_u8(bank, 0, 0x21);
+ cfi_info->chip_erase_timeout_typ = cfi_query_u8(bank, 0, 0x22);
+ cfi_info->word_write_timeout_max = cfi_query_u8(bank, 0, 0x23);
+ cfi_info->buf_write_timeout_max = cfi_query_u8(bank, 0, 0x24);
+ cfi_info->block_erase_timeout_max = cfi_query_u8(bank, 0, 0x25);
+ cfi_info->chip_erase_timeout_max = cfi_query_u8(bank, 0, 0x26);
+
+ DEBUG("Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x",
+ (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+ (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+ (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+ (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+ DEBUG("typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
+ 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
+ DEBUG("max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+ (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+ (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+ (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+
+ cfi_info->dev_size = cfi_query_u8(bank, 0, 0x27);
+ cfi_info->interface_desc = cfi_query_u16(bank, 0, 0x28);
+ cfi_info->max_buf_write_size = cfi_query_u16(bank, 0, 0x2a);
+ cfi_info->num_erase_regions = cfi_query_u8(bank, 0, 0x2c);
+
+ DEBUG("size: 0x%x, interface desc: %i, max buffer write size: %x", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
+
+ if (1 << cfi_info->dev_size != bank->size)
+ {
+ WARNING("configuration specifies 0x%x size, but a 0x%x size flash was found", bank->size, 1 << cfi_info->dev_size);
+ }
+
+ if (cfi_info->num_erase_regions)
+ {
+ int i;
+ int num_sectors = 0;
+ int sector = 0;
+ u32 offset = 0;
+ cfi_info->erase_region_info = malloc(4 * cfi_info->num_erase_regions);
+
+ for (i = 0; i < cfi_info->num_erase_regions; i++)
+ {
+ cfi_info->erase_region_info[i] = cfi_query_u32(bank, 0, 0x2d + (4 * i));
+ DEBUG("erase region[%i]: %i blocks of size 0x%x", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256);
+
+ num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1;
+ }
+
+ bank->num_sectors = num_sectors;
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+ for (i = 0; i < cfi_info->num_erase_regions; i++)
+ {
+ int j;
+ for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++)
+ {
+ bank->sectors[sector].offset = offset;
+ bank->sectors[sector].size = (cfi_info->erase_region_info[i] >> 16) * 256;
+ offset += bank->sectors[sector].size;
+ bank->sectors[sector].is_erased = -1;
+ bank->sectors[sector].is_protected = -1;
+ sector++;
+ }
+ }
+ }
+ else
+ {
+ cfi_info->erase_region_info = NULL;
+ }
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ cfi_read_intel_pri_ext(bank);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ /* return to read array mode */
+ cfi_command(bank, 0xf0, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ return ERROR_OK;
+}
+
+int cfi_erase_check(struct flash_bank_s *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+ int i;
+ int retval;
+
+ if (!cfi_info->erase_check_algorithm)
+ {
+ u32 erase_check_code[] =
+ {
+ 0xe4d03001,
+ 0xe0022003,
+ 0xe2511001,
+ 0x1afffffb,
+ 0xeafffffe
+ };
+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, 20, &cfi_info->erase_check_algorithm) != ERROR_OK)
+ {
+ WARNING("no working area available, falling back to slow memory reads");
+ }
+ else
+ {
+ /* write algorithm code to working area */
+ target->type->write_memory(target, cfi_info->erase_check_algorithm->address, 4, 5, (u8*)erase_check_code);
+ }
+ }
+
+ if (!cfi_info->erase_check_algorithm)
+ {
+ u32 *buffer = malloc(4096);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
+ u32 check = 0xffffffffU;
+ int erased = 1;
+
+ while (size > 0)
+ {
+ u32 thisrun_size = (size > 4096) ? 4096 : size;
+ int j;
+
+ target->type->read_memory(target, address, 4, thisrun_size / 4, (u8*)buffer);
+
+ for (j = 0; j < thisrun_size / 4; j++)
+ check &= buffer[j];
+
+ if (check != 0xffffffff)
+ {
+ erased = 0;
+ break;
+ }
+
+ size -= thisrun_size;
+ address += thisrun_size;
+ }
+
+ bank->sectors[i].is_erased = erased;
+ }
+
+ free(buffer);
+ }
+ else
+ {
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u32 address = bank->base + bank->sectors[i].offset;
+ u32 size = bank->sectors[i].size;
+
+ reg_param_t reg_params[3];
+ armv4_5_algorithm_t armv4_5_info;
+
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, address);
+
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, size);
+
+ init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0xff);
+
+ if ((retval = target->type->run_algorithm(target, 0, NULL, 3, reg_params, cfi_info->erase_check_algorithm->address, cfi_info->erase_check_algorithm->address + 0x10, 10000, &armv4_5_info)) != ERROR_OK)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ if (buf_get_u32(reg_params[2].value, 0, 32) == 0xff)
+ bank->sectors[i].is_erased = 1;
+ else
+ bank->sectors[i].is_erased = 0;
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int cfi_intel_protect_check(struct flash_bank_s *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ cfi_intel_pri_ext_t *pri_ext = cfi_info->pri_ext;
+ target_t *target = cfi_info->target;
+ u8 command[8];
+ int i;
+
+ /* check if block lock bits are supported on this device */
+ if (!(pri_ext->blk_status_reg_mask & 0x1))
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ cfi_command(bank, 0x90, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x55), bank->bus_width, 1, command);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ u8 block_status = cfi_get_u8(bank, i, 0x2);
+
+ if (block_status & 1)
+ bank->sectors[i].is_protected = 1;
+ else
+ bank->sectors[i].is_protected = 0;
+ }
+
+ cfi_command(bank, 0xff, command);
+ target->type->write_memory(target, flash_address(bank, 0, 0x0), bank->bus_width, 1, command);
+
+ return ERROR_OK;
+}
+
+int cfi_protect_check(struct flash_bank_s *bank)
+{
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+ target_t *target = cfi_info->target;
+
+ if (cfi_info->qry[0] != 'Q')
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ return cfi_intel_protect_check(bank);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ return ERROR_OK;
+}
+
+int cfi_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ int printed;
+ cfi_flash_bank_t *cfi_info = bank->driver_priv;
+
+ if (cfi_info->qry[0] == -1)
+ {
+ printed = snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n");
+ return ERROR_OK;
+ }
+
+ printed = snprintf(buf, buf_size, "\ncfi information:\n");
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "Vcc min: %1.1x.%1.1x, Vcc max: %1.1x.%1.1x, Vpp min: %1.1x.%1.1x, Vpp max: %1.1x.%1.1x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f,
+ (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f,
+ (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f,
+ (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "typ. word write timeout: %u, typ. buf write timeout: %u, typ. block erase timeout: %u, typ. chip erase timeout: %u\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ,
+ 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ);
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "max. word write timeout: %u, max. buf write timeout: %u, max. block erase timeout: %u, max. chip erase timeout: %u\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ),
+ (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ),
+ (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ),
+ (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ));
+ buf += printed;
+ buf_size -= printed;
+
+ printed = snprintf(buf, buf_size, "size: 0x%x, interface desc: %i, max buffer write size: %x\n", 1 << cfi_info->dev_size, cfi_info->interface_desc, cfi_info->max_buf_write_size);
+ buf += printed;
+ buf_size -= printed;
+
+ switch(cfi_info->pri_id)
+ {
+ case 1:
+ case 3:
+ cfi_intel_info(bank, buf, buf_size);
+ break;
+ default:
+ ERROR("cfi primary command set %i unsupported", cfi_info->pri_id);
+ break;
+ }
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef CFI_H
+#define CFI_H
+
+#include "flash.h"
+#include "target.h"
+
+typedef struct cfi_flash_bank_s
+{
+ struct target_s *target;
+ working_area_t *write_algorithm;
+ working_area_t *erase_check_algorithm;
+
+ char qry[3];
+
+ /* identification string */
+ u16 pri_id;
+ u16 pri_addr;
+ u16 alt_id;
+ u16 alt_addr;
+
+ /* device-system interface */
+ u8 vcc_min;
+ u8 vcc_max;
+ u8 vpp_min;
+ u8 vpp_max;
+ u8 word_write_timeout_typ;
+ u8 buf_write_timeout_typ;
+ u8 block_erase_timeout_typ;
+ u8 chip_erase_timeout_typ;
+ u8 word_write_timeout_max;
+ u8 buf_write_timeout_max;
+ u8 block_erase_timeout_max;
+ u8 chip_erase_timeout_max;
+
+ /* flash geometry */
+ u8 dev_size;
+ u16 interface_desc;
+ u16 max_buf_write_size;
+ u8 num_erase_regions;
+ u32 *erase_region_info;
+
+ void *pri_ext;
+ void *alt_ext;
+} cfi_flash_bank_t;
+
+/* Intel primary extended query table
+ * as defined for the Advanced+ Boot Block Flash Memory (C3)
+ * and used by the linux kernel cfi driver (as of 2.6.14)
+ */
+typedef struct cfi_intel_pri_ext_s
+{
+ char pri[3];
+ u8 major_version;
+ u8 minor_version;
+ u32 feature_support;
+ u8 suspend_cmd_support;
+ u16 blk_status_reg_mask;
+ u8 vcc_optimal;
+ u8 vpp_optimal;
+ u8 num_protection_fields;
+ u16 prot_reg_addr;
+ u8 fact_prot_reg_size;
+ u8 user_prot_reg_size;
+ u8 extra[0];
+} cfi_intel_pri_ext_t;
+
+#endif /* CFI_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "flash.h"
+#include "command.h"
+#include "log.h"
+#include "target.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/* command handlers */
+int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* flash drivers
+ */
+extern flash_driver_t lpc2000_flash;
+extern flash_driver_t cfi_flash;
+extern flash_driver_t at91sam7_flash;
+extern flash_driver_t str7x_flash;
+
+flash_driver_t *flash_drivers[] =
+{
+ &lpc2000_flash,
+ &cfi_flash,
+ &at91sam7_flash,
+ &str7x_flash,
+ NULL,
+};
+
+flash_bank_t *flash_banks;
+static command_t *flash_cmd;
+
+int flash_register_commands(struct command_context_s *cmd_ctx)
+{
+ flash_cmd = register_command(cmd_ctx, NULL, "flash", NULL, COMMAND_ANY, NULL);
+
+ register_command(cmd_ctx, flash_cmd, "bank", handle_flash_bank_command, COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+int flash_init(struct command_context_s *cmd_ctx)
+{
+ if (flash_banks)
+ {
+ register_command(cmd_ctx, flash_cmd, "banks", handle_flash_banks_command, COMMAND_EXEC,
+ "list configured flash banks ");
+ register_command(cmd_ctx, flash_cmd, "info", handle_flash_info_command, COMMAND_EXEC,
+ "print info about flash bank <num>");
+ register_command(cmd_ctx, flash_cmd, "probe", handle_flash_probe_command, COMMAND_EXEC,
+ "identify flash bank <num>");
+ register_command(cmd_ctx, flash_cmd, "erase_check", handle_flash_erase_check_command, COMMAND_EXEC,
+ "check erase state of sectors in flash bank <num>");
+ register_command(cmd_ctx, flash_cmd, "protect_check", handle_flash_protect_check_command, COMMAND_EXEC,
+ "check protection state of sectors in flash bank <num>");
+ register_command(cmd_ctx, flash_cmd, "erase", handle_flash_erase_command, COMMAND_EXEC,
+ "erase sectors at <bank> <first> <last>");
+ register_command(cmd_ctx, flash_cmd, "write", handle_flash_write_command, COMMAND_EXEC,
+ "write binary <bank> <file> <offset>");
+ register_command(cmd_ctx, flash_cmd, "protect", handle_flash_protect_command, COMMAND_EXEC,
+ "set protection of sectors at <bank> <first> <last> <on|off>");
+ }
+
+ return ERROR_OK;
+}
+
+flash_bank_t *get_flash_bank_by_num(int num)
+{
+ flash_bank_t *p;
+ int i = 0;
+
+ for (p = flash_banks; p; p = p->next)
+ {
+ if (i++ == num)
+ {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+/* flash_bank <driver> <base> <size> <chip_width> <bus_width> [driver_options ...]
+ */
+int handle_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ int i;
+ int found = 0;
+
+ if (argc < 5)
+ {
+ WARNING("incomplete flash_bank configuration");
+ return ERROR_OK;
+ }
+
+ for (i = 0; flash_drivers[i]; i++)
+ {
+ if (strcmp(args[0], flash_drivers[i]->name) == 0)
+ {
+ flash_bank_t *p, *c;
+
+ /* register flash specific commands */
+ if (flash_drivers[i]->register_commands(cmd_ctx) != ERROR_OK)
+ {
+ ERROR("couldn't register '%s' commands", args[0]);
+ exit(-1);
+ }
+
+ c = malloc(sizeof(flash_bank_t));
+ c->driver = flash_drivers[i];
+ c->driver_priv = NULL;
+ c->base = strtoul(args[1], NULL, 0);
+ c->size = strtoul(args[2], NULL, 0);
+ c->chip_width = strtoul(args[3], NULL, 0);
+ c->bus_width = strtoul(args[4], NULL, 0);
+ c->next = NULL;
+
+ if (flash_drivers[i]->flash_bank_command(cmd_ctx, cmd, args, argc, c) != ERROR_OK)
+ {
+ ERROR("'%s' driver rejected flash bank at 0x%8.8x", args[0], c->base);
+ free(c);
+ return ERROR_OK;
+ }
+
+ /* put flash bank in linked list */
+ if (flash_banks)
+ {
+ /* find last flash bank */
+ for (p = flash_banks; p && p->next; p = p->next);
+ if (p)
+ p->next = c;
+ }
+ else
+ {
+ flash_banks = c;
+ }
+
+ found = 1;
+ }
+ }
+
+ /* no matching flash driver found */
+ if (!found)
+ {
+ ERROR("flash driver '%s' not found", args[0]);
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_banks_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *p;
+ int i = 0;
+
+ if (!flash_banks)
+ {
+ command_print(cmd_ctx, "no flash banks configured");
+ return ERROR_OK;
+ }
+
+ for (p = flash_banks; p; p = p->next)
+ {
+ command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
+ i++, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_info_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *p;
+ int i = 0;
+ int j = 0;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: flash info <num>");
+ return ERROR_OK;
+ }
+
+ for (p = flash_banks; p; p = p->next)
+ {
+ if (i++ == strtoul(args[0], NULL, 0))
+ {
+ char buf[1024];
+
+ command_print(cmd_ctx, "#%i: %s at 0x%8.8x, size 0x%8.8x, buswidth %i, chipwidth %i",
+ i, p->driver->name, p->base, p->size, p->bus_width, p->chip_width);
+ for (j = 0; j < p->num_sectors; j++)
+ {
+ char *erase_state, *protect_state;
+
+ if (p->sectors[j].is_erased == 0)
+ erase_state = "not erased";
+ else if (p->sectors[j].is_erased == 1)
+ erase_state = "erased";
+ else
+ erase_state = "erase state unknown";
+
+ if (p->sectors[j].is_protected == 0)
+ protect_state = "not protected";
+ else if (p->sectors[j].is_protected == 1)
+ protect_state = "protected";
+ else
+ protect_state = "protection state unknown";
+
+ command_print(cmd_ctx, "\t#%i: 0x%8.8x (0x%xkB) %s, %s",
+ j, p->sectors[j].offset, p->sectors[j].size,
+ erase_state, protect_state);
+ }
+
+ p->driver->info(p, buf, 1024);
+ command_print(cmd_ctx, "%s", buf);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_probe_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *p;
+ int retval;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: flash probe <num>");
+ return ERROR_OK;
+ }
+
+ p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (p)
+ {
+ if ((retval = p->driver->probe(p)) == ERROR_OK)
+ {
+ command_print(cmd_ctx, "flash '%s' found at 0x%8.8x", p->driver->name, p->base);
+ }
+ else if (retval == ERROR_FLASH_BANK_INVALID)
+ {
+ command_print(cmd_ctx, "probing failed for flash bank '#%s' at 0x%8.8x",
+ args[0], p->base);
+ }
+ else
+ {
+ command_print(cmd_ctx, "unknown error when probing flash bank '#%s' at 0x%8.8x",
+ args[0], p->base);
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_erase_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *p;
+ int retval;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: flash erase_check <num>");
+ return ERROR_OK;
+ }
+
+ p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (p)
+ {
+ if ((retval = p->driver->erase_check(p)) == ERROR_OK)
+ {
+ command_print(cmd_ctx, "successfully checked erase state", p->driver->name, p->base);
+ }
+ else
+ {
+ command_print(cmd_ctx, "unknown error when checking erase state of flash bank #%s at 0x%8.8x",
+ args[0], p->base);
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_protect_check_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *p;
+ int retval;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: flash protect_check <num>");
+ return ERROR_OK;
+ }
+
+ p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (p)
+ {
+ if ((retval = p->driver->protect_check(p)) == ERROR_OK)
+ {
+ command_print(cmd_ctx, "successfully checked protect state");
+ }
+ else if (retval == ERROR_FLASH_OPERATION_FAILED)
+ {
+ command_print(cmd_ctx, "checking protection state failed (possibly unsupported) by flash #%s at 0x%8.8x", args[0], p->base);
+ }
+ else
+ {
+ command_print(cmd_ctx, "unknown error when checking protection state of flash bank '#%s' at 0x%8.8x", args[0], p->base);
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc > 2)
+ {
+ int first = strtoul(args[1], NULL, 0);
+ int last = strtoul(args[2], NULL, 0);
+ int retval;
+ flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (!p)
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ return ERROR_OK;
+ }
+
+ if ((retval = p->driver->erase(p, first, last)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "can't work with this flash while target is running");
+ break;
+ case ERROR_INVALID_ARGUMENTS:
+ command_print(cmd_ctx, "usage: flash_erase <bank> <first> <last>");
+ break;
+ case ERROR_FLASH_BANK_INVALID:
+ command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
+ break;
+ case ERROR_FLASH_OPERATION_FAILED:
+ command_print(cmd_ctx, "flash erase error");
+ break;
+ case ERROR_FLASH_SECTOR_INVALID:
+ command_print(cmd_ctx, "sector number(s) invalid");
+ break;
+ case ERROR_OK:
+ command_print(cmd_ctx, "erased flash sectors %i to %i", first, last);
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error");
+ }
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: flash erase <bank> <first> <last>");
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_protect_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc > 3)
+ {
+ int first = strtoul(args[1], NULL, 0);
+ int last = strtoul(args[2], NULL, 0);
+ int set;
+ int retval;
+ flash_bank_t *p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (!p)
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ return ERROR_OK;
+ }
+
+ if (strcmp(args[3], "on") == 0)
+ set = 1;
+ else if (strcmp(args[3], "off") == 0)
+ set = 0;
+ else
+ {
+ command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
+ return ERROR_OK;
+ }
+
+ if ((retval = p->driver->protect(p, set, first, last)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "can't work with this flash while target is running");
+ break;
+ case ERROR_INVALID_ARGUMENTS:
+ command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
+ break;
+ case ERROR_FLASH_BANK_INVALID:
+ command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
+ break;
+ case ERROR_FLASH_OPERATION_FAILED:
+ command_print(cmd_ctx, "flash program error");
+ break;
+ case ERROR_FLASH_SECTOR_INVALID:
+ command_print(cmd_ctx, "sector number(s) invalid");
+ break;
+ case ERROR_OK:
+ command_print(cmd_ctx, "protection of flash sectors %i to %i turned %s", first, last, args[3]);
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error");
+ }
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "usage: flash protect <bank> <first> <last> <on|off>");
+ }
+
+ return ERROR_OK;
+}
+
+int handle_flash_write_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ FILE *binary;
+ u32 offset;
+ struct stat binary_stat;
+ u32 binary_size;
+ u8 *buffer;
+ u32 buf_cnt;
+ int retval;
+ flash_bank_t *p;
+
+ if (argc < 3)
+ {
+ command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
+ return ERROR_OK;
+ }
+
+ offset = strtoul(args[2], NULL, 0);
+ p = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (!p)
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ return ERROR_OK;
+ }
+
+ if (stat(args[1], &binary_stat) == -1)
+ {
+ ERROR("couldn't stat() %s: %s", args[1], strerror(errno));
+ return ERROR_OK;
+ }
+
+ if (S_ISDIR(binary_stat.st_mode))
+ {
+ ERROR("%s is a directory", args[1]);
+ command_print(cmd_ctx,"%s is a directory", args[1]);
+ return ERROR_OK;
+ }
+
+ if (binary_stat.st_size == 0){
+ ERROR("Empty file %s", args[1]);
+ command_print(cmd_ctx,"Empty file %s", args[1]);
+ return ERROR_OK;
+ }
+
+ if (!(binary = fopen(args[1], "r")))
+ {
+ ERROR("couldn't open %s: %s", args[1], strerror(errno));
+ command_print(cmd_ctx, "couldn't open %s", args[1]);
+ return ERROR_OK;
+ }
+
+ binary_size = binary_stat.st_size;
+ buffer = malloc(binary_size);
+ buf_cnt = fread(buffer, 1, binary_size, binary);
+
+ if ((retval = p->driver->write(p, buffer, offset, buf_cnt)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_TARGET_NOT_HALTED:
+ command_print(cmd_ctx, "can't work with this flash while target is running");
+ break;
+ case ERROR_INVALID_ARGUMENTS:
+ command_print(cmd_ctx, "usage: flash write <bank> <file> <offset>");
+ break;
+ case ERROR_FLASH_BANK_INVALID:
+ command_print(cmd_ctx, "no '%s' flash found at 0x%8.8x", p->driver->name, p->base);
+ break;
+ case ERROR_FLASH_OPERATION_FAILED:
+ command_print(cmd_ctx, "flash program error");
+ break;
+ case ERROR_FLASH_DST_BREAKS_ALIGNMENT:
+ command_print(cmd_ctx, "offset breaks required alignment");
+ break;
+ case ERROR_FLASH_DST_OUT_OF_BANK:
+ command_print(cmd_ctx, "destination is out of flash bank (offset and/or file too large)");
+ break;
+ case ERROR_FLASH_SECTOR_NOT_ERASED:
+ command_print(cmd_ctx, "destination sector(s) not erased");
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error");
+ }
+ }
+ free(buffer);
+ fclose(binary);
+
+ command_print(cmd_ctx, "wrote file %s to flash bank %i at offset 0x%8.8x", args[1], strtoul(args[0], NULL, 0), strtoul(args[2], NULL, 0));
+
+ return ERROR_OK;
+
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef FLASH_H
+#define FLASH_H
+
+#include "target.h"
+
+typedef struct flash_sector_s
+{
+ u32 offset;
+ u32 size;
+ int is_erased;
+ int is_protected;
+} flash_sector_t;
+
+struct flash_bank_s;
+
+typedef struct flash_driver_s
+{
+ char *name;
+ int (*register_commands)(struct command_context_s *cmd_ctx);
+ int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+ int (*erase)(struct flash_bank_s *bank, int first, int last);
+ int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
+ int (*write)(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+ int (*probe)(struct flash_bank_s *bank);
+ int (*erase_check)(struct flash_bank_s *bank);
+ int (*protect_check)(struct flash_bank_s *bank);
+ int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
+} flash_driver_t;
+
+typedef struct flash_bank_s
+{
+ flash_driver_t *driver;
+ void *driver_priv;
+ u32 base;
+ u32 size;
+ int chip_width;
+ int bus_width;
+ int num_sectors;
+ flash_sector_t *sectors;
+ struct flash_bank_s *next;
+} flash_bank_t;
+
+extern int flash_register_commands(struct command_context_s *cmd_ctx);
+extern int flash_init(struct command_context_s *cmd_ctx);
+
+extern flash_bank_t *get_flash_bank_by_num(int num);
+
+#define ERROR_FLASH_BANK_INVALID (-900)
+#define ERROR_FLASH_SECTOR_INVALID (-901)
+#define ERROR_FLASH_OPERATION_FAILED (-902)
+#define ERROR_FLASH_DST_OUT_OF_BANK (-903)
+#define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904)
+#define ERROR_FLASH_BUSY (-905)
+#define ERROR_FLASH_SECTOR_NOT_ERASED (-906)
+#define ERROR_FLASH_BANK_NOT_PROBED (-907)
+
+#endif /* FLASH_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "lpc2000.h"
+
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* flash programming support for Philips LPC2xxx devices
+ * currently supported devices:
+ * variant 1 (lpc2000_v1):
+ * - 2104|5|6
+ * - 2114|9
+ * - 2124|9
+ * - 2194
+ * - 2212|4
+ * - 2292|4
+ *
+ * variant 2 (lpc2000_v2):
+ * - 213x
+ * - 214x
+ */
+
+int lpc2000_register_commands(struct command_context_s *cmd_ctx);
+int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
+int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
+int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int lpc2000_probe(struct flash_bank_s *bank);
+int lpc2000_erase_check(struct flash_bank_s *bank);
+int lpc2000_protect_check(struct flash_bank_s *bank);
+int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+flash_driver_t lpc2000_flash =
+{
+ .name = "lpc2000",
+ .register_commands = lpc2000_register_commands,
+ .flash_bank_command = lpc2000_flash_bank_command,
+ .erase = lpc2000_erase,
+ .protect = lpc2000_protect,
+ .write = lpc2000_write,
+ .probe = lpc2000_probe,
+ .erase_check = lpc2000_erase_check,
+ .protect_check = lpc2000_protect_check,
+ .info = lpc2000_info
+};
+
+int lpc2000_register_commands(struct command_context_s *cmd_ctx)
+{
+ command_t *lpc2000_cmd = register_command(cmd_ctx, NULL, "lpc2000", NULL, COMMAND_ANY, NULL);
+
+ register_command(cmd_ctx, lpc2000_cmd, "part_id", lpc2000_handle_part_id_command, COMMAND_EXEC,
+ "print part id of lpc2000 flash bank <num>");
+
+ return ERROR_OK;
+}
+
+int lpc2000_build_sector_list(struct flash_bank_s *bank)
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+
+ if (lpc2000_info->variant == 1)
+ {
+ int i = 0;
+ u32 offset = 0;
+
+ /* variant 1 has different layout for 128kb and 256kb flashes */
+ if (bank->size == 128 * 1024)
+ {
+ bank->num_sectors = 16;
+ bank->sectors = malloc(sizeof(flash_sector_t) * 16);
+ for (i = 0; i < 16; i++)
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 8 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ }
+ else if (bank->size == 256 * 1024)
+ {
+ bank->num_sectors = 18;
+ bank->sectors = malloc(sizeof(flash_sector_t) * 18);
+
+ for (i = 0; i < 8; i++)
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 8 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ for (i = 8; i < 10; i++)
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 64 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ for (i = 10; i < 18; i++)
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 8 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ }
+ else
+ {
+ ERROR("BUG: unknown bank->size encountered");
+ exit(-1);
+ }
+ }
+ else if (lpc2000_info->variant == 2)
+ {
+ int num_sectors;
+ int i;
+ u32 offset = 0;
+
+ /* variant 2 has a uniform layout, only number of sectors differs */
+ switch (bank->size)
+ {
+ case 32 * 1024:
+ num_sectors = 8;
+ break;
+ case 64 * 1024:
+ num_sectors = 9;
+ break;
+ case 128 * 1024:
+ num_sectors = 11;
+ break;
+ case 256 * 1024:
+ num_sectors = 15;
+ break;
+ case 500 * 1024:
+ num_sectors = 27;
+ break;
+ default:
+ ERROR("BUG: unknown bank->size encountered");
+ exit(-1);
+ break;
+ }
+
+ bank->num_sectors = num_sectors;
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+
+ for (i = 0; i < num_sectors; i++)
+ {
+ if ((i >= 0) && (i < 8))
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 4 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ if ((i >= 8) && (i < 22))
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 32 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ if ((i >= 22) && (i < 27))
+ {
+ bank->sectors[i].offset = offset;
+ bank->sectors[i].size = 4 * 1024;
+ offset += bank->sectors[i].size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+ }
+ }
+ else
+ {
+ ERROR("BUG: unknown lpc2000_info->variant encountered");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+/* call LPC2000 IAP function
+ * uses 172 bytes working area
+ * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
+ * 0x8 to 0x1f: command parameter table
+ * 0x20 to 0x2b: command result table
+ * 0x2c to 0xac: stack (only 128b needed)
+ */
+int lpc2000_iap_call(flash_bank_t *bank, int code, u32 param_table[5], u32 result_table[2])
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+ target_t *target = lpc2000_info->target;
+ mem_param_t mem_params[2];
+ reg_param_t reg_params[5];
+ armv4_5_algorithm_t armv4_5_info;
+ u32 status_code;
+
+ /* regrab previously allocated working_area, or allocate a new one */
+ if (!lpc2000_info->iap_working_area)
+ {
+ u8 jump_gate[8];
+
+ /* make sure we have a working area */
+ if (target_alloc_working_area(target, 172, &lpc2000_info->iap_working_area) != ERROR_OK)
+ {
+ ERROR("no working area specified, can't write LPC2000 internal flash");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* write IAP code to working area */
+ buf_set_u32(jump_gate, 0, 32, ARMV4_5_BX(12));
+ buf_set_u32(jump_gate, 32, 32, 0xeafffffe);
+ target->type->write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, (u8*)jump_gate);
+ }
+
+ armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
+ armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
+ armv4_5_info.core_state = ARMV4_5_STATE_ARM;
+
+ /* command parameter table */
+ init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 4 * 6, PARAM_OUT);
+ buf_set_u32(mem_params[0].value, 0, 32, code);
+ buf_set_u32(mem_params[0].value, 32, 32, param_table[0]);
+ buf_set_u32(mem_params[0].value, 64, 32, param_table[1]);
+ buf_set_u32(mem_params[0].value, 96, 32, param_table[2]);
+ buf_set_u32(mem_params[0].value, 128, 32, param_table[3]);
+ buf_set_u32(mem_params[0].value, 160, 32, param_table[4]);
+
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);
+
+ /* command result table */
+ init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);
+
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
+
+ /* IAP entry point */
+ init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
+
+ /* IAP stack */
+ init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
+ buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);
+
+ /* return address */
+ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
+ buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);
+
+ target->type->run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
+
+ status_code = buf_get_u32(mem_params[1].value, 0, 32);
+ result_table[0] = buf_get_u32(mem_params[1].value, 32, 32);
+ result_table[1] = buf_get_u32(mem_params[1].value, 64, 32);
+
+ destroy_mem_param(&mem_params[0]);
+ destroy_mem_param(&mem_params[1]);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+
+ return status_code;
+}
+
+int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+ u32 param_table[5];
+ u32 result_table[2];
+ int status_code;
+ int i;
+
+ if ((first < 0) || (last > bank->num_sectors))
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ for (i = first; i <= last; i++)
+ {
+ /* check single sector */
+ param_table[0] = param_table[1] = i;
+ status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
+
+ switch (status_code)
+ {
+ case ERROR_FLASH_OPERATION_FAILED:
+ return ERROR_FLASH_OPERATION_FAILED;
+ 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:
+ return ERROR_FLASH_BUSY;
+ break;
+ default:
+ ERROR("BUG: unknown LPC2000 status code");
+ exit(-1);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+/* flash_bank lpc2000 <base> <size> 0 0 <lpc_variant> <target#> <cclk> [calc_checksum]
+ */
+int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ lpc2000_flash_bank_t *lpc2000_info;
+
+ if (argc < 8)
+ {
+ WARNING("incomplete flash_bank lpc2000 configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
+ bank->driver_priv = lpc2000_info;
+
+ if (strcmp(args[5], "lpc2000_v1") == 0)
+ {
+ lpc2000_info->variant = 1;
+ lpc2000_info->cmd51_dst_boundary = 512;
+ lpc2000_info->cmd51_can_256b = 0;
+ lpc2000_info->cmd51_can_8192b = 1;
+ }
+ else if (strcmp(args[5], "lpc2000_v2") == 0)
+ {
+ lpc2000_info->variant = 2;
+ lpc2000_info->cmd51_dst_boundary = 256;
+ lpc2000_info->cmd51_can_256b = 1;
+ lpc2000_info->cmd51_can_8192b = 0;
+ }
+ else
+ {
+ ERROR("unknown LPC2000 variant");
+ free(lpc2000_info);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ lpc2000_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
+ if (!lpc2000_info->target)
+ {
+ ERROR("no target '%s' configured", args[6]);
+ exit(-1);
+ }
+ lpc2000_info->iap_working_area = NULL;
+ lpc2000_info->cclk = strtoul(args[7], NULL, 0);
+ lpc2000_info->calc_checksum = 0;
+ lpc2000_build_sector_list(bank);
+
+
+ if (argc >= 9)
+ {
+ if (strcmp(args[8], "calc_checksum") == 0)
+ lpc2000_info->calc_checksum = 1;
+ }
+
+ return ERROR_OK;
+}
+
+int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+ u32 param_table[5];
+ u32 result_table[2];
+ int status_code;
+
+ if (lpc2000_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+ {
+ return ERROR_FLASH_SECTOR_INVALID;
+ }
+
+ param_table[0] = first;
+ param_table[1] = last;
+ param_table[2] = lpc2000_info->cclk;
+
+ /* Prepare sectors */
+ status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
+ switch (status_code)
+ {
+ case ERROR_FLASH_OPERATION_FAILED:
+ return ERROR_FLASH_OPERATION_FAILED;
+ case LPC2000_CMD_SUCCESS:
+ break;
+ case LPC2000_INVALID_SECTOR:
+ return ERROR_FLASH_SECTOR_INVALID;
+ break;
+ default:
+ WARNING("lpc2000 prepare sectors returned %i", status_code);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Erase sectors */
+ status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
+ switch (status_code)
+ {
+ case ERROR_FLASH_OPERATION_FAILED:
+ return ERROR_FLASH_OPERATION_FAILED;
+ case LPC2000_CMD_SUCCESS:
+ break;
+ case LPC2000_INVALID_SECTOR:
+ return ERROR_FLASH_SECTOR_INVALID;
+ break;
+ default:
+ WARNING("lpc2000 erase sectors returned %i", status_code);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ /* can't protect/unprotect on the lpc2000 */
+ return ERROR_OK;
+}
+
+int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+ target_t *target = lpc2000_info->target;
+ u32 dst_min_alignment;
+ u32 bytes_remaining = count;
+ u32 bytes_written = 0;
+ int first_sector = 0;
+ int last_sector = 0;
+ u32 param_table[5];
+ u32 result_table[2];
+ int status_code;
+ int i;
+ working_area_t *download_area;
+
+ if (lpc2000_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* allocate a working area */
+ if (target_alloc_working_area(target, 4096, &download_area) != ERROR_OK)
+ {
+ ERROR("no working area specified, can't write LPC2000 internal flash");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ if (lpc2000_info->cmd51_can_256b)
+ dst_min_alignment = 256;
+ else
+ dst_min_alignment = 512;
+
+ if (offset % dst_min_alignment)
+ {
+ WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ if (offset >= bank->sectors[i].offset)
+ first_sector = i;
+ if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
+ last_sector = i;
+ }
+
+ DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
+
+ /* check if exception vectors should be flashed */
+ if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
+ {
+ u32 checksum = 0;
+ int i = 0;
+ for (i = 0; i < 8; i++)
+ {
+ DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
+ if (i != 5)
+ checksum += buf_get_u32(buffer + (i * 4), 0, 32);
+ }
+ checksum = 0 - checksum;
+ DEBUG("checksum: 0x%8.8x", checksum);
+ buf_set_u32(buffer + 0x14, 0, 32, checksum);
+ }
+
+ while (bytes_remaining > 0)
+ {
+ u32 thisrun_bytes;
+ if (bytes_remaining >= 4096)
+ thisrun_bytes = 4096;
+ else if (bytes_remaining >= 1024)
+ thisrun_bytes = 1024;
+ else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
+ thisrun_bytes = 512;
+ else
+ thisrun_bytes = 256;
+
+ /* Prepare sectors */
+ param_table[0] = first_sector;
+ param_table[1] = last_sector;
+ status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
+ switch (status_code)
+ {
+ case ERROR_FLASH_OPERATION_FAILED:
+ return ERROR_FLASH_OPERATION_FAILED;
+ case LPC2000_CMD_SUCCESS:
+ break;
+ case LPC2000_INVALID_SECTOR:
+ return ERROR_FLASH_SECTOR_INVALID;
+ break;
+ default:
+ WARNING("lpc2000 prepare sectors returned %i", status_code);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (bytes_remaining >= thisrun_bytes)
+ {
+ if (target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)
+ {
+ target_free_working_area(target, download_area);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+ else
+ {
+ u8 *last_buffer = malloc(thisrun_bytes);
+ int i;
+ memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
+ for (i = bytes_remaining; i < thisrun_bytes; i++)
+ last_buffer[i] = 0xff;
+ target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, last_buffer);
+ free(last_buffer);
+ }
+
+ DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);
+
+ /* Write data */
+ param_table[0] = bank->base + offset + bytes_written;
+ param_table[1] = download_area->address;
+ param_table[2] = thisrun_bytes;
+ param_table[3] = lpc2000_info->cclk;
+ status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
+ switch (status_code)
+ {
+ case ERROR_FLASH_OPERATION_FAILED:
+ return ERROR_FLASH_OPERATION_FAILED;
+ case LPC2000_CMD_SUCCESS:
+ break;
+ case LPC2000_INVALID_SECTOR:
+ return ERROR_FLASH_SECTOR_INVALID;
+ break;
+ default:
+ WARNING("lpc2000 returned %i", status_code);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (bytes_remaining > thisrun_bytes)
+ bytes_remaining -= thisrun_bytes;
+ else
+ bytes_remaining = 0;
+ bytes_written += thisrun_bytes;
+ }
+
+ target_free_working_area(target, download_area);
+
+ return ERROR_OK;
+}
+
+int lpc2000_probe(struct flash_bank_s *bank)
+{
+ /* we can't probe on an lpc2000
+ * if this is an lpc2xxx, it has the configured flash
+ */
+ return ERROR_OK;
+}
+
+int lpc2000_erase_check(struct flash_bank_s *bank)
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+
+ if (lpc2000_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+int lpc2000_protect_check(struct flash_bank_s *bank)
+{
+ /* sectors are always protected */
+ return ERROR_OK;
+}
+
+int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
+
+ snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
+
+ return ERROR_OK;
+}
+
+int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ flash_bank_t *bank;
+ u32 param_table[5];
+ u32 result_table[2];
+ int status_code;
+ lpc2000_flash_bank_t *lpc2000_info;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "usage: lpc2000 part_id <num>");
+ return ERROR_OK;
+ }
+
+ bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
+ if (!bank)
+ {
+ command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
+ return ERROR_OK;
+ }
+
+ lpc2000_info = bank->driver_priv;
+ if (lpc2000_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
+ {
+ if (status_code == ERROR_FLASH_OPERATION_FAILED)
+ {
+ command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
+ return ERROR_OK;
+ }
+ command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
+ }
+ else
+ {
+ command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);
+ }
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef LPC2000_H
+#define LPC2000_H
+
+#include "flash.h"
+#include "target.h"
+
+typedef struct lpc2000_flash_bank_s
+{
+ int variant;
+ struct target_s *target;
+ struct working_area_s *iap_working_area;
+ u32 cclk;
+ int cmd51_dst_boundary;
+ int cmd51_can_256b;
+ int cmd51_can_8192b;
+ int calc_checksum;
+} lpc2000_flash_bank_t;
+
+enum lpc2000_status_codes
+{
+ LPC2000_CMD_SUCCESS = 0,
+ LPC2000_INVALID_COMMAND = 1,
+ LPC2000_SRC_ADDR_ERROR = 2,
+ LPC2000_DST_ADDR_ERROR = 3,
+ LPC2000_SRC_ADDR_NOT_MAPPED = 4,
+ LPC2000_DST_ADDR_NOT_MAPPED = 5,
+ LPC2000_COUNT_ERROR = 6,
+ LPC2000_INVALID_SECTOR = 7,
+ LPC2000_SECTOR_NOT_BLANK = 8,
+ LPC2000_SECTOR_NOT_PREPARED = 9,
+ LPC2000_COMPARE_ERROR = 10,
+ LPC2000_BUSY = 11
+};
+
+#endif /* LPC2000_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "str7x.h"
+#include "flash.h"
+#include "target.h"
+#include "log.h"
+#include "armv4_5.h"
+#include "algorithm.h"
+#include "binarybuffer.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+str7x_mem_layout_t mem_layout[] = {
+ {0x00000000, 0x02000, 0x01},
+ {0x00002000, 0x02000, 0x01},
+ {0x00004000, 0x02000, 0x01},
+ {0x00006000, 0x02000, 0x01},
+ {0x00008000, 0x08000, 0x01},
+ {0x00010000, 0x10000, 0x01},
+ {0x00020000, 0x10000, 0x01},
+ {0x00030000, 0x10000, 0x01},
+ {0x000C0000, 0x02000, 0x10},
+ {0x000C2000, 0x02000, 0x10},
+ {0,0},
+};
+
+int str7x_register_commands(struct command_context_s *cmd_ctx);
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
+int str7x_erase(struct flash_bank_s *bank, int first, int last);
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last);
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count);
+int str7x_probe(struct flash_bank_s *bank);
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int str7x_protect_check(struct flash_bank_s *bank);
+int str7x_erase_check(struct flash_bank_s *bank);
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size);
+
+flash_driver_t str7x_flash =
+{
+ .name = "str7x",
+ .register_commands = str7x_register_commands,
+ .flash_bank_command = str7x_flash_bank_command,
+ .erase = str7x_erase,
+ .protect = str7x_protect,
+ .write = str7x_write,
+ .probe = str7x_probe,
+ .erase_check = str7x_erase_check,
+ .protect_check = str7x_protect_check,
+ .info = str7x_info
+};
+
+int str7x_register_commands(struct command_context_s *cmd_ctx)
+{
+
+ return ERROR_OK;
+}
+
+int str7x_get_flash_adr(struct flash_bank_s *bank, u32 reg)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ return (str7x_info->flash_base|reg);
+}
+
+int str7x_build_block_list(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+
+ int i;
+ int num_sectors;
+
+ switch (bank->size)
+ {
+ case 16 * 1024:
+ num_sectors = 2;
+ break;
+ case 64 * 1024:
+ num_sectors = 5;
+ break;
+ case 128 * 1024:
+ num_sectors = 6;
+ break;
+ case 256 * 1024:
+ num_sectors = 8;
+ break;
+ default:
+ ERROR("BUG: unknown bank->size encountered");
+ exit(-1);
+ }
+
+ if( str7x_info->bank1 == 1 )
+ {
+ num_sectors += 2;
+ }
+
+ bank->num_sectors = num_sectors;
+ bank->sectors = malloc(sizeof(flash_sector_t) * num_sectors);
+
+ for (i = 0; i < num_sectors; i++)
+ {
+ bank->sectors[i].offset = mem_layout[i].sector_start;
+ bank->sectors[i].size = mem_layout[i].sector_size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+
+ return ERROR_OK;
+}
+
+/* flash bank str7x <base> <size> 0 0 <str71_variant> <target#>
+ */
+int str7x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info;
+
+ if (argc < 7)
+ {
+ WARNING("incomplete flash_bank str7x configuration");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str7x_info = malloc(sizeof(str7x_flash_bank_t));
+ bank->driver_priv = str7x_info;
+
+ if (strcmp(args[5], "STR71x") == 0)
+ {
+ str7x_info->bank1 = 1;
+ str7x_info->flash_base = 0x40000000;
+ }
+ else if (strcmp(args[5], "STR73x") == 0)
+ {
+ str7x_info->bank1 = 0;
+ str7x_info->flash_base = 0x80000000;
+ }
+ else
+ {
+ ERROR("unknown STR7x variant");
+ free(str7x_info);
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ str7x_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
+ if (!str7x_info->target)
+ {
+ ERROR("no target '%i' configured", args[6]);
+ exit(-1);
+ }
+
+ str7x_build_block_list(bank);
+
+ return ERROR_OK;
+}
+
+u32 str7x_status(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 retval;
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&retval);
+
+ return retval;
+}
+
+u32 str7x_result(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 retval;
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_ER), 4, 1, (u8*)&retval);
+
+ return retval;
+}
+
+int str7x_blank_check(struct flash_bank_s *bank, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u8 *buffer;
+ int i;
+ int nBytes;
+
+ if ((first < 0) || (last > bank->num_sectors))
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ buffer = malloc(256);
+
+ for (i = first; i <= last; i++)
+ {
+ bank->sectors[i].is_erased = 1;
+
+ target->type->read_memory(target, bank->base + bank->sectors[i].offset, 4, 256/4, buffer);
+
+ for (nBytes = 0; nBytes < 256; nBytes++)
+ {
+ if (buffer[nBytes] != 0xFF)
+ {
+ bank->sectors[i].is_erased = 0;
+ break;
+ }
+ }
+ }
+
+ free(buffer);
+
+ return ERROR_OK;
+}
+
+int str7x_protect_check(struct flash_bank_s *bank)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+
+ int i;
+ int retval;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ target->type->read_memory(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), 4, 1, (u8*)&retval);
+
+ for (i = 0; i < bank->num_sectors; i++)
+ {
+ if (retval & (mem_layout[i].reg_offset << i))
+ bank->sectors[i].is_protected = 0;
+ else
+ bank->sectors[i].is_protected = 1;
+ }
+
+ return ERROR_OK;
+}
+
+int str7x_erase(struct flash_bank_s *bank, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+
+ int i;
+ u32 cmd;
+ u32 retval;
+ u32 erase_blocks;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ erase_blocks = 0;
+
+ for (i = first; i <= last; i++)
+ erase_blocks |= (mem_layout[i].reg_offset << i);
+
+ cmd = FLASH_SER;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ cmd = erase_blocks;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR1), 4, 1, (u8*)&cmd);
+
+ cmd = FLASH_SER|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_ERER)
+ return ERROR_FLASH_SECTOR_NOT_ERASED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ for (i = first; i <= last; i++)
+ bank->sectors[i].is_erased = 1;
+
+ return ERROR_OK;
+}
+
+int str7x_protect(struct flash_bank_s *bank, int set, int first, int last)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ int i;
+ u32 cmd;
+ u32 retval;
+ u32 protect_blocks;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ protect_blocks = 0xFFFFFFFF;
+
+ if( set )
+ {
+ for (i = first; i <= last; i++)
+ protect_blocks &= ~(mem_layout[i].reg_offset << i);
+ }
+
+ cmd = FLASH_SPR;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR);
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ cmd = protect_blocks;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+
+ cmd = FLASH_SPR|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_ERER)
+ return ERROR_FLASH_SECTOR_NOT_ERASED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ return ERROR_OK;
+}
+
+int str7x_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
+{
+ str7x_flash_bank_t *str7x_info = bank->driver_priv;
+ target_t *target = str7x_info->target;
+ u32 dwords_remaining = (count / 8);
+ u32 bytes_remaining = (count & 0x00000007);
+ u32 address = bank->base + offset;
+ u32 *wordbuffer = (u32*)buffer;
+ u32 bytes_written = 0;
+ u32 cmd;
+ u32 retval;
+
+ if (str7x_info->target->state != TARGET_HALTED)
+ {
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ while (dwords_remaining > 0)
+ {
+ // command
+ cmd = FLASH_DWPG;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ // address
+ cmd = address;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ // data byte 1
+ cmd = wordbuffer[bytes_written/4];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+ bytes_written += 4;
+
+ // data byte 2
+ cmd = wordbuffer[bytes_written/4];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, (u8*)&cmd);
+ bytes_written += 4;
+
+ /* start programming cycle */
+ cmd = FLASH_DWPG|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_PGER)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ dwords_remaining--;
+ address += 8;
+ }
+
+ while( bytes_remaining > 0 )
+ {
+ // command
+ cmd = FLASH_WPG;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ // address
+ cmd = address;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_AR), 4, 1, (u8*)&cmd);
+
+ // data byte
+ cmd = buffer[bytes_written];
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, (u8*)&cmd);
+
+ /* start programming cycle */
+ cmd = FLASH_WPG|FLASH_WMS;
+ target->type->write_memory(target, str7x_get_flash_adr(bank, FLASH_CR0), 4, 1, (u8*)&cmd);
+
+ while (((retval = str7x_status(bank)) & (FLASH_BSYA1|FLASH_BSYA2))){
+ usleep(1000);
+ }
+
+ retval = str7x_result(bank);
+
+ if (retval & FLASH_PGER)
+ return ERROR_FLASH_OPERATION_FAILED;
+ else if (retval & FLASH_WPF)
+ return ERROR_FLASH_OPERATION_FAILED;
+
+ address++;
+ bytes_remaining--;
+ bytes_written++;
+ }
+
+ return ERROR_OK;
+}
+
+int str7x_probe(struct flash_bank_s *bank)
+{
+ return ERROR_OK;
+}
+
+int str7x_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ return ERROR_OK;
+}
+
+int str7x_erase_check(struct flash_bank_s *bank)
+{
+ return str7x_blank_check(bank, 0, bank->num_sectors - 1);
+}
+
+int str7x_info(struct flash_bank_s *bank, char *buf, int buf_size)
+{
+ snprintf(buf, buf_size, "str7x flash driver info" );
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef STR7X_H
+#define STR7X_H
+
+#include "flash.h"
+#include "target.h"
+
+typedef struct str7x_flash_bank_s
+{
+ int bank1;
+ struct target_s *target;
+ u32 flash_base;
+} str7x_flash_bank_t;
+
+enum str7x_status_codes
+{
+ STR7X_CMD_SUCCESS = 0,
+ STR7X_INVALID_COMMAND = 1,
+ STR7X_SRC_ADDR_ERROR = 2,
+ STR7X_DST_ADDR_ERROR = 3,
+ STR7X_SRC_ADDR_NOT_MAPPED = 4,
+ STR7X_DST_ADDR_NOT_MAPPED = 5,
+ STR7X_COUNT_ERROR = 6,
+ STR7X_INVALID_SECTOR = 7,
+ STR7X_SECTOR_NOT_BLANK = 8,
+ STR7X_SECTOR_NOT_PREPARED = 9,
+ STR7X_COMPARE_ERROR = 10,
+ STR7X_BUSY = 11
+};
+
+/* Flash registers */
+
+#define FLASH_CR0 0x00100000
+#define FLASH_CR1 0x00100004
+#define FLASH_DR0 0x00100008
+#define FLASH_DR1 0x0010000C
+#define FLASH_AR 0x00100010
+#define FLASH_ER 0x00100014
+#define FLASH_NVWPAR 0x0010DFB0
+#define FLASH_NVAPR0 0x0010DFB8
+#define FLASH_NVAPR1 0x0010DFBC
+
+/* FLASH_CR0 register bits */
+
+#define FLASH_WMS 0x80000000
+#define FLASH_SUSP 0x40000000
+#define FLASH_WPG 0x20000000
+#define FLASH_DWPG 0x10000000
+#define FLASH_SER 0x08000000
+#define FLASH_SPR 0x01000000
+#define FLASH_BER 0x04000000
+#define FLASH_MER 0x02000000
+#define FLASH_BSYA1 0x00000002
+#define FLASH_BSYA2 0x00000004
+
+/* FLASH_CR1 regsiter bits */
+
+#define FLASH_B1S 0x02000000
+#define FLASH_B0S 0x01000000
+#define FLASH_B1F1 0x00020000
+#define FLASH_B1F0 0x00010000
+#define FLASH_B0F7 0x00000080
+#define FLASH_B0F6 0x00000040
+#define FLASH_B0F5 0x00000020
+#define FLASH_B0F4 0x00000010
+#define FLASH_B0F3 0x00000008
+#define FLASH_B0F2 0x00000004
+#define FLASH_B0F1 0x00000002
+#define FLASH_B0F0 0x00000001
+
+/* FLASH_ER register bits */
+
+#define FLASH_WPF 0x00000100
+#define FLASH_RESER 0x00000080
+#define FLASH_SEQER 0x00000040
+#define FLASH_10ER 0x00000008
+#define FLASH_PGER 0x00000004
+#define FLASH_ERER 0x00000002
+#define FLASH_ERR 0x00000001
+
+typedef struct str7x_mem_layout_s {
+ u32 sector_start;
+ u32 sector_size;
+ u32 reg_offset;
+} str7x_mem_layout_t;
+
+#endif /* STR7X_H */
+
--- /dev/null
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libhelper.a
+libhelper_a_SOURCES = binarybuffer.c configuration.c log.c interpreter.c command.c time_support.c
+noinst_HEADERS = binarybuffer.h configuration.h types.h log.h command.h \
+ interpreter.h time_support.h
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2004, 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "log.h"
+
+#include "binarybuffer.h"
+
+int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value);
+u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num);
+u32 flip_u32(u32 value, unsigned int num);
+
+const unsigned char bit_reverse_table256[] =
+{
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value)
+{
+ unsigned int i;
+
+ if (!buffer)
+ return ERROR_INVALID_ARGUMENTS;
+
+ for (i=first; i<first+num; i++)
+ {
+ if (((value >> (i-first))&1) == 1)
+ buffer[i/8] |= 1 << (i%8);
+ else
+ buffer[i/8] &= ~(1 << (i%8));
+ }
+
+ return ERROR_OK;
+}
+
+u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num)
+{
+ u32 result = 0;
+ unsigned int i;
+
+ if (!buffer)
+ {
+ ERROR("buffer not initialized");
+ return 0;
+ }
+
+ for (i=first; i<first+num; i++)
+ {
+ if (((buffer[i/8]>>(i%8))&1) == 1)
+ result |= 1 << (i-first);
+ }
+
+ return result;
+}
+
+u8* buf_cpy(u8 *from, u8 *to, int size)
+{
+ int num_bytes = CEIL(size, 8);
+ unsigned int i;
+
+ if (from == NULL)
+ return NULL;
+
+ for (i = 0; i < num_bytes; i++)
+ to[i] = from[i];
+
+ return to;
+}
+
+int buf_cmp(u8 *buf1, u8 *buf2, int size)
+{
+ int num_bytes = CEIL(size, 8);
+ int i;
+
+ if (!buf1 || !buf2)
+ return 1;
+
+ for (i = 0; i < num_bytes; i++)
+ {
+ if (buf1[i] != buf2[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+int buf_cmp_mask(u8 *buf1, u8 *buf2, u8 *mask, int size)
+{
+ int num_bytes = CEIL(size, 8);
+ int i;
+
+ for (i = 0; i < num_bytes; i++)
+ {
+ if ((buf1[i] & mask[i]) != (buf2[i] & mask[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+u8* buf_set_ones(u8 *buf, int count)
+{
+ int num_bytes = CEIL(count, 8);
+ int i;
+
+ for (i = 0; i < num_bytes; i++)
+ {
+ if (count >= 8)
+ buf[i] = 0xff;
+ else
+ buf[i] = (1 << count) - 1;
+
+ count -= 8;
+ }
+
+ return buf;
+}
+
+u8* buf_set_buf(u8 *src, int src_start, u8 *dst, int dst_start, int len)
+{
+ int src_idx = src_start, dst_idx = dst_start;
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (((src[src_idx/8] >> (src_idx % 8)) & 1) == 1)
+ dst[dst_idx/8] |= 1 << (dst_idx%8);
+ else
+ dst[dst_idx/8] &= ~(1 << (dst_idx%8));
+ dst_idx++;
+ src_idx++;
+ }
+
+ return dst;
+}
+
+u32 flip_u32(u32 value, unsigned int num)
+{
+ u32 c;
+
+ c = (bit_reverse_table256[value & 0xff] << 24) |
+ (bit_reverse_table256[(value >> 8) & 0xff] << 16) |
+ (bit_reverse_table256[(value >> 16) & 0xff] << 8) |
+ (bit_reverse_table256[(value >> 24) & 0xff]);
+
+ if (num < 32)
+ c = c >> (32 - num);
+
+ return c;
+}
+
+char* buf_to_char(u8 *buf, int size)
+{
+ int char_len = CEIL(size, 8) * 2;
+ char *char_buf = malloc(char_len + 1);
+ int i;
+ int bits_left = size;
+
+ char_buf[char_len] = 0;
+
+ for (i = 0; i < CEIL(size, 8); i++)
+ {
+ if (bits_left < 8)
+ {
+ buf[i] &= ((1 << bits_left) - 1);
+ }
+
+ if (((buf[i] & 0x0f) >= 0) && ((buf[i] & 0x0f) <= 9))
+ char_buf[char_len - 2*i - 1] = '0' + (buf[i] & 0xf);
+ else
+ char_buf[char_len - 2*i - 1] = 'a' + (buf[i] & 0xf) - 10;
+
+ if (((buf[i] & 0xf0) >> 4 >= 0) && ((buf[i] & 0xf0) >> 4 <= 9))
+ char_buf[char_len - 2*i - 2] = '0' + ((buf[i] & 0xf0) >> 4);
+ else
+ char_buf[char_len - 2*i - 2] = 'a' + ((buf[i] & 0xf0) >> 4) - 10;
+
+ }
+
+ return char_buf;
+}
+
+int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size)
+{
+ int bin_len = CEIL(len, 2);
+ int i;
+
+ if (buf_size < CEIL(bin_len, 8))
+ return 0;
+
+ if (len % 2)
+ return 0;
+
+ for (i = 0; i < strlen(buf); i++)
+ {
+ u32 tmp;
+ sscanf(buf + 2*i, "%2x", &tmp);
+ bin_buf[i] = tmp & 0xff;
+ }
+
+ return bin_len * 8;
+}
+
+int buf_to_u32_handler(u8 *in_buf, void *priv)
+{
+ u32 *dest = priv;
+
+ *dest = buf_get_u32(in_buf, 0, 32);
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2004, 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef BINARYBUFFER_H
+#define BINARYBUFFER_H
+
+#include "types.h"
+
+/* support functions to access arbitrary bits in a byte array
+ * flip_u32 inverses the bit order inside a 32-bit word (31..0 -> 0..31)
+ */
+
+extern int buf_set_u32(u8* buffer, unsigned int first, unsigned int num, u32 value);
+extern u32 buf_get_u32(u8* buffer, unsigned int first, unsigned int num);
+
+extern u32 flip_u32(u32 value, unsigned int num);
+
+extern int buf_cmp(u8 *buf1, u8 *buf2, int size);
+extern int buf_cmp_mask(u8 *buf1, u8 *buf2, u8 *mask, int size);
+extern u8* buf_cpy(u8 *from, u8 *to, int size);
+
+extern u8* buf_set_ones(u8 *buf, int count);
+extern u8* buf_set_buf(u8 *src, int src_start, u8 *dst, int dst_start, int len);
+
+extern char* buf_to_char(u8 *buf, int size);
+extern int char_to_buf(char *buf, int len, u8 *bin_buf, int buf_size);
+
+extern int buf_to_u32_handler(u8 *in_buf, void *priv);
+
+#define CEIL(m, n) ((m + n - 1) / n)
+
+#endif /* BINARYBUFFER_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * part of this file is taken from libcli (libcli.sourceforge.net) *
+ * Copyright (C) David Parrish (david@dparrish.com) *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "command.h"
+
+#include "log.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int build_unique_lenghts(command_context_t *context, command_t *commands)
+{
+ command_t *c, *p;
+
+ /* iterate through all commands */
+ for (c = commands; c; c = c->next)
+ {
+ /* find out how many characters are required to uniquely identify a command */
+ for (c->unique_len = 1; c->unique_len <= strlen(c->name); c->unique_len++)
+ {
+ int foundmatch = 0;
+
+ /* for every command, see if the current length is enough */
+ for (p = commands; p; p = p->next)
+ {
+ /* ignore the command itself */
+ if (c == p)
+ continue;
+
+ /* compare commands up to the current length */
+ if (strncmp(p->name, c->name, c->unique_len) == 0)
+ foundmatch++;
+ }
+
+ /* when none of the commands matched, we've found the minimum length required */
+ if (!foundmatch)
+ break;
+ }
+
+ /* if the current command has children, build the unique lengths for them */
+ if (c->children)
+ build_unique_lenghts(context, c->children);
+ }
+
+ return ERROR_OK;
+}
+
+command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help)
+{
+ command_t *c, *p;
+
+ if (!context || !name)
+ return NULL;
+
+ c = malloc(sizeof(command_t));
+
+ c->name = strdup(name);
+ c->parent = parent;
+ c->children = NULL;
+ c->handler = handler;
+ c->mode = mode;
+ if (help)
+ c->help = strdup(help);
+ else
+ c->help = NULL;
+ c->unique_len = 0;
+ c->next = NULL;
+
+ /* place command in tree */
+ if (parent)
+ {
+ if (parent->children)
+ {
+ /* find last child */
+ for (p = parent->children; p && p->next; p = p->next);
+ if (p)
+ p->next = c;
+ }
+ else
+ {
+ parent->children = c;
+ }
+ }
+ else
+ {
+ if (context->commands)
+ {
+ /* find last command */
+ for (p = context->commands; p && p->next; p = p->next);
+ if (p)
+ p->next = c;
+ }
+ else
+ {
+ context->commands = c;
+ }
+ }
+
+ /* update unique lengths */
+ build_unique_lenghts(context, (parent) ? parent : context->commands);
+
+ return c;
+}
+
+int unregister_command(command_context_t *context, char *name)
+{
+ command_t *c, *p = NULL, *c2;
+
+ if ((!context) || (!name))
+ return ERROR_INVALID_ARGUMENTS;
+
+ /* find command */
+ for (c = context->commands; c; c = c->next)
+ {
+ if (strcmp(name, c->name) == 0)
+ {
+ /* unlink command */
+ if (p)
+ {
+ p->next = c->next;
+ }
+ else
+ {
+ context->commands = c->next;
+ }
+
+ /* unregister children */
+ if (c->children)
+ {
+ for (c2 = c->children; c2; c2 = c2->next)
+ {
+ free(c2->name);
+ if (c2->help)
+ free(c2->help);
+ free(c2);
+ }
+ }
+
+ /* delete command */
+ free(c->name);
+ if (c->help)
+ free(c->help);
+ free(c);
+ }
+
+ /* remember the last command for unlinking */
+ p = c;
+ }
+
+ return ERROR_OK;
+}
+
+int parse_line(char *line, char *words[], int max_words)
+{
+ int nwords = 0;
+ char *p = line;
+ char *word_start = line;
+ int inquote = 0;
+
+ while (nwords < max_words - 1)
+ {
+ /* check if we reached
+ * a terminating NUL
+ * a matching closing quote character " or '
+ * we're inside a word but not a quote, and the current character is whitespace
+ */
+ if (!*p || *p == inquote || (word_start && !inquote && isspace(*p)))
+ {
+ /* we're inside a word or quote, and reached its end*/
+ if (word_start)
+ {
+ int len = p - word_start;
+
+ /* copy the word */
+ memcpy(words[nwords] = malloc(len + 1), word_start, len);
+ /* add terminating NUL */
+ words[nwords++][len] = 0;
+ }
+
+ /* we're done parsing the line */
+ if (!*p)
+ break;
+
+ /* skip over trailing quote or whitespace*/
+ if (inquote || isspace(*p))
+ p++;
+
+ inquote = 0;
+ word_start = 0;
+ }
+ else if (*p == '"' || *p == '\'')
+ {
+ /* we've reached the beginning of a quote */
+ inquote = *p++;
+ word_start = p;
+ }
+ else
+ {
+ /* we've reached the beginning of a new word */
+ if (!word_start)
+ word_start = p;
+
+ /* normal character, skip */
+ p++;
+ }
+ }
+
+ return nwords;
+}
+
+void command_print(command_context_t *context, char *format, ...)
+{
+ va_list ap;
+ char *buffer = NULL;
+ int n, size = 0;
+ char *p;
+
+ va_start(ap, format);
+
+ /* process format string */
+ /* TODO: possible bug. va_list is undefined after the first call to vsnprintf */
+ while (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
+ {
+ /* increase buffer until it fits the whole string */
+ if (!(p = realloc(buffer, size += 4096)))
+ return;
+
+ buffer = p;
+ }
+
+ /* vsnprintf failed */
+ if (n < 0)
+ return;
+
+ p = buffer;
+
+ /* process lines in buffer */
+ do {
+ char *next = strchr(p, '\n');
+
+ if (next)
+ *next++ = 0;
+
+ if (context->output_handler)
+ context->output_handler(context, p);
+
+ p = next;
+ } while (p);
+
+ if (buffer)
+ free(buffer);
+
+ va_end(ap);
+}
+
+int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
+{
+ command_t *c;
+
+ for (c = commands; c; c = c->next)
+ {
+ if (strncasecmp(c->name, words[start_word], c->unique_len))
+ continue;
+
+ if (strncasecmp(c->name, words[start_word], strlen(words[start_word])))
+ continue;
+
+ if ((c->mode == context->mode) || (c->mode == COMMAND_ANY))
+ {
+ if (!c->children)
+ {
+ if (!c->handler)
+ {
+ command_print(context, "No handler for command");
+ break;
+ }
+ else
+ {
+ return c->handler(context, c->name, words + start_word + 1, num_words - start_word - 1);
+ }
+ }
+ else
+ {
+ if (start_word == num_words - 1)
+ {
+ command_print(context, "Incomplete command");
+ break;
+ }
+ return find_and_run_command(context, c->children, words, num_words, start_word + 1);
+ }
+ }
+ }
+
+ command_print(context, "Command %s not found", words[start_word]);
+ return ERROR_OK;
+}
+
+int command_run_line(command_context_t *context, char *line)
+{
+ int nwords;
+ char *words[128] = {0};
+ int retval;
+ int i;
+
+ if ((!context) || (!line))
+ return ERROR_INVALID_ARGUMENTS;
+
+ /* skip preceding whitespace */
+ while (isspace(*line))
+ line++;
+
+ /* empty line, ignore */
+ if (!*line)
+ return ERROR_OK;
+
+ if (context->echo)
+ {
+ command_print(context, "%s", line);
+ }
+
+ nwords = parse_line(line, words, sizeof(words) / sizeof(words[0]));
+
+ if (nwords > 0)
+ retval = find_and_run_command(context, context->commands, words, nwords, 0);
+ else
+ return ERROR_INVALID_ARGUMENTS;
+
+ for (i = 0; i < nwords; i++)
+ free(words[i]);
+
+ return retval;
+}
+
+int command_run_file(command_context_t *context, FILE *file, enum command_mode mode)
+{
+ int retval;
+ int old_command_mode;
+ char buffer[4096];
+
+ old_command_mode = context->mode;
+ context->mode = mode;
+
+ while (fgets(buffer, 4096, file))
+ {
+ char *p;
+ char *cmd, *end;
+
+ /* stop processing line after a comment (#, !) or a LF, CR were encountered */
+ if ((p = strpbrk(buffer, "#!\r\n")))
+ *p = 0;
+
+ /* skip over leading whitespace */
+ cmd = buffer;
+ while (isspace(*cmd))
+ cmd++;
+
+ /* empty (all whitespace) line? */
+ if (!*cmd)
+ continue;
+
+ /* search the end of the current line, ignore trailing whitespace */
+ for (p = end = cmd; *p; p++)
+ if (!isspace(*p))
+ end = p;
+
+ /* terminate end */
+ *++end = 0;
+ if (strcasecmp(cmd, "quit") == 0)
+ break;
+
+ /* run line */
+ if (command_run_line(context, cmd) == ERROR_COMMAND_CLOSE_CONNECTION)
+ break;
+ }
+
+ context->mode = old_command_mode;
+
+ return retval;
+}
+
+void command_print_help_line(command_context_t* context, struct command_s *command, int indent)
+{
+ command_t *c;
+ char indents[32] = {0};
+ char *help = "no help available";
+ char name_buf[64];
+ int i;
+
+ for (i = 0; i < indent; i+=2)
+ {
+ indents[i*2] = ' ';
+ indents[i*2+1] = '-';
+ }
+ indents[i*2] = 0;
+
+ if ((command->mode == COMMAND_EXEC) || (command->mode == COMMAND_ANY))
+ {
+ if (command->help)
+ help = command->help;
+
+ snprintf(name_buf, 64, command->name);
+ strncat(name_buf, indents, 64);
+ command_print(context, "%20s\t%s", name_buf, help);
+ }
+
+ if (command->children)
+ {
+ for (c = command->children; c; c = c->next)
+ {
+ command_print_help_line(context, c, indent + 1);
+ }
+ }
+}
+
+int command_print_help(command_context_t* context, char* name, char** args, int argc)
+{
+ command_t *c;
+
+ for (c = context->commands; c; c = c->next)
+ {
+ command_print_help_line(context, c, 0);
+ }
+
+ return ERROR_OK;
+}
+
+void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv)
+{
+ context->output_handler = output_handler;
+ context->output_handler_priv = priv;
+}
+
+command_context_t* copy_command_context(command_context_t* context)
+{
+ command_context_t* copy_context = malloc(sizeof(command_context_t));
+
+ *copy_context = *context;
+
+ return copy_context;
+}
+
+int command_done(command_context_t *context)
+{
+ free(context);
+
+ return ERROR_OK;
+}
+
+command_context_t* command_init()
+{
+ command_context_t* context = malloc(sizeof(command_context_t));
+
+ context->mode = COMMAND_EXEC;
+ context->commands = NULL;
+ context->current_target = 0;
+ context->echo = 0;
+ context->output_handler = NULL;
+ context->output_handler_priv = NULL;
+
+ register_command(context, NULL, "help", command_print_help,
+ COMMAND_EXEC, "display this help");
+
+ register_command(context, NULL, "sleep", handle_sleep_command,
+ COMMAND_ANY, "sleep for <n> milliseconds");
+
+ return context;
+}
+
+/* sleep command sleeps for <n> miliseconds
+ * this is useful in target startup scripts
+ */
+int handle_sleep_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ unsigned long duration = 0;
+
+ if (argc == 1)
+ {
+ duration = strtoul(args[0], NULL, 0);
+ usleep(duration * 1000);
+ }
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#include <stdio.h>
+
+enum command_mode
+{
+ COMMAND_EXEC,
+ COMMAND_CONFIG,
+ COMMAND_ANY,
+};
+
+typedef struct command_context_s
+{
+ enum command_mode mode;
+ struct command_s *commands;
+ int current_target;
+ int echo;
+ int (*output_handler)(struct command_context_s *context, char* line);
+ void *output_handler_priv;
+} command_context_t;
+
+typedef struct command_s
+{
+ char *name;
+ struct command_s *parent;
+ struct command_s *children;
+ int (*handler)(struct command_context_s *context, char* name, char** args, int argc);
+ enum command_mode mode;
+ char *help;
+ int unique_len;
+ struct command_s *next;
+} command_t;
+
+extern command_t* register_command(command_context_t *context, command_t *parent, char *name, int (*handler)(struct command_context_s *context, char* name, char** args, int argc), enum command_mode mode, char *help);
+extern int unregister_command(command_context_t *context, char *name);
+extern void command_set_output_handler(command_context_t* context, int (*output_handler)(struct command_context_s *context, char* line), void *priv);
+extern command_context_t* copy_command_context(command_context_t* context);
+extern command_context_t* command_init();
+extern int command_done(command_context_t *context);
+extern void command_print(command_context_t *context, char *format, ...);
+extern int command_run_line(command_context_t *context, char *line);
+extern int command_run_file(command_context_t *context, FILE *file, enum command_mode mode);
+
+
+#define ERROR_COMMAND_CLOSE_CONNECTION (-600)
+
+#endif /* COMMAND_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2004, 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "types.h"
+#include "command.h"
+#include "configuration.h"
+#include "log.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+char* config_file_name;
+
+static int help_flag;
+
+static struct option long_options[] =
+{
+ {"help", no_argument, &help_flag, 1},
+
+ {"debug", optional_argument, 0, 'd'},
+ {"file", required_argument, 0, 'f'},
+ {"log_output", required_argument, 0, 'l'},
+
+ {0, 0, 0, 0}
+};
+
+int configuration_output_handler(struct command_context_s *context, char* line)
+{
+ INFO(line);
+
+ return ERROR_OK;
+}
+
+int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[])
+{
+ int c;
+ char command_buffer[128];
+
+ while (1)
+ {
+ /* getopt_long stores the option index here. */
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hd::l:f:", long_options, &option_index);
+
+ /* Detect the end of the options. */
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ break;
+ case 'h': /* --help | -h */
+ help_flag = 1;
+ break;
+ case 'f': /* --file | -f */
+ config_file_name = optarg;
+ break;
+ case 'd': /* --debug | -d */
+ if (optarg)
+ snprintf(command_buffer, 128, "debug_level %s", optarg);
+ else
+ snprintf(command_buffer, 128, "debug_level 3");
+ command_run_line(cmd_ctx, command_buffer);
+ break;
+ case 'l': /* --log_output | -l */
+ if (optarg)
+ {
+ snprintf(command_buffer, 128, "log_output %s", optarg);
+ command_run_line(cmd_ctx, command_buffer);
+ }
+ break;
+ }
+ }
+
+ if (help_flag)
+ {
+ printf("Open On-Chip Debugger\n(c) 2005 by Dominic Rath\n\n");
+ printf("--help | -h\tdisplay this help\n");
+ printf("--file | -f\tuse configuration file <name>\n");
+ printf("--debug | -d\tset debug level <0-3>\n");
+ printf("--log_output | -l\tredirect log output to file <name>\n");
+ exit(-1);
+ }
+
+ return ERROR_OK;
+}
+
+int parse_config_file(struct command_context_s *cmd_ctx)
+{
+ FILE *config_file;
+
+ if (!config_file_name)
+ config_file_name = "openocd.cfg";
+
+ config_file = fopen(config_file_name, "r");
+ if (!config_file)
+ {
+ ERROR("couldn't open config file");
+ return ERROR_NO_CONFIG_FILE;
+ }
+
+ command_run_file(cmd_ctx, config_file, COMMAND_CONFIG);
+
+ fclose(config_file);
+
+ return ERROR_OK;
+}
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2004, 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include "command.h"
+#include "types.h"
+
+extern int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[]);
+extern int parse_config_file(struct command_context_s *cmd_ctx);
+extern int configuration_output_handler(struct command_context_s *context, char* line);
+
+extern char* config_file_name;
+#endif /* CONFIGURATION_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "interpreter.h"
+
+#include "binarybuffer.h"
+#include <stdlib.h>
+#include <string.h>
+
+var_t *variables = NULL;
+
+int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+int interpreter_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "var", handle_var_command,
+ COMMAND_ANY, "allocate, display or delete variable <name> [num_fields|'del'] [size1] ...");
+ register_command(cmd_ctx, NULL, "field", handle_field_command,
+ COMMAND_ANY, "display/modify variable field <var> <field> [value|'flip']");
+ register_command(cmd_ctx, NULL, "script", handle_script_command,
+ COMMAND_ANY, "execute commands from <file>");
+
+ return ERROR_OK;
+}
+
+var_t* get_var_by_num(int num)
+{
+ int count = 0;
+ var_t *var = variables;
+
+ if (var)
+ {
+ if (num == count)
+ return var;
+ while (var->next)
+ {
+ var = var->next;
+ count++;
+ if (num == count)
+ return var;
+ }
+ }
+ return NULL;
+}
+
+var_t* get_var_by_name(char *name)
+{
+ var_t *var = variables;
+
+ if (var)
+ {
+ if (strcmp(var->name, name) == 0)
+ return var;
+ while (var->next)
+ {
+ var = var->next;
+ if (strcmp(var->name, name) == 0)
+ return var;
+ }
+ }
+ return NULL;
+}
+
+var_t* get_var_by_namenum(char *namenum)
+{
+ if ((namenum[0] >= '0') && (namenum[0] <= '9'))
+ return get_var_by_num(strtol(namenum, NULL, 0));
+ else
+ return get_var_by_name(namenum);
+
+}
+
+int field_le_to_host(u8 *buffer, void *priv)
+{
+ var_field_t *field = priv;
+ field->value = buf_get_u32(buffer, 0, field->num_bits);
+
+ return ERROR_OK;
+}
+
+int handle_var_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ var_t **last_var_p = &variables;
+ int i;
+
+ if (argc >= 2)
+ {
+ while (*last_var_p)
+ {
+ if (strcmp((*last_var_p)->name, args[0]) == 0)
+ {
+ if (strcmp(args[1], "del") == 0)
+ {
+ var_t *next = (*last_var_p)->next;
+ free ((*last_var_p)->fields);
+ free (*last_var_p);
+ *last_var_p = next;
+ command_print(cmd_ctx, "variable %s deleted", args[0]);
+ }
+ else
+ command_print(cmd_ctx, "variable of that name already exists");
+ return ERROR_OK;
+ }
+ last_var_p = &((*last_var_p)->next);
+ }
+
+ if ((args[0][0] >= 0) && (args[0][0] <= 9))
+ {
+ command_print(cmd_ctx, "invalid name specified (first character may not be a number)");
+ return ERROR_OK;
+ }
+
+ *last_var_p = malloc(sizeof(var_t));
+ (*last_var_p)->name = strdup(args[0]);
+ (*last_var_p)->num_fields = argc - 1;
+ (*last_var_p)->next = NULL;
+
+ (*last_var_p)->fields = malloc(sizeof(var_field_t) * (*last_var_p)->num_fields);
+ for (i = 0; i < (*last_var_p)->num_fields; i++)
+ {
+ (*last_var_p)->fields[i].num_bits = strtol(args[1+i], NULL, 0);
+ (*last_var_p)->fields[i].value = 0x0;
+ }
+ return ERROR_OK;
+ }
+
+ if (argc == 1)
+ {
+ var_t *var = get_var_by_namenum(args[0]);
+ if (var)
+ {
+ int i;
+ command_print(cmd_ctx, "%s (%i fields):", var->name, var->num_fields);
+ for (i = 0; i < (var->num_fields); i++)
+ {
+ command_print(cmd_ctx, "0x%x (/%i)", var->fields[i].value, var->fields[i].num_bits);
+ }
+ }
+ else
+ {
+ command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
+ }
+ }
+
+ if (argc == 0)
+ {
+ var_t *var = variables;
+ int count = 0;
+ while (var)
+ {
+ command_print(cmd_ctx, "%i: %s (%i fields)", count, var->name, var->num_fields);
+ var = var->next;
+ count++;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_field_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+
+ if (argc < 2)
+ command_print(cmd_ctx, "usage: field <var> <field> [value|'flip']");
+
+ if (argc >= 2)
+ {
+ var_t *var = get_var_by_namenum(args[0]);
+ int field_num = strtol(args[1], NULL, 0);
+ if (!var)
+ {
+ command_print(cmd_ctx, "variable %s doesn't exist", args[0]);
+ return ERROR_OK;
+ }
+ if (field_num >= var->num_fields)
+ command_print(cmd_ctx, "variable field %i is out of bounds (max. %i)", field_num, var->num_fields - 1);
+ if ((var) && (field_num < var->num_fields))
+ {
+ if (argc > 2)
+ {
+ if (strcmp(args[2], "flip") == 0)
+ var->fields[field_num].value = flip_u32(var->fields[field_num].value, var->fields[field_num].num_bits);
+ else
+ var->fields[field_num].value = strtoul(args[2], NULL, 0);
+ }
+
+ command_print(cmd_ctx, "%s(%i): 0x%x (/%i)", var->name, field_num, var->fields[field_num].value, var->fields[field_num].num_bits);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int handle_script_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ FILE *script_file;
+ int echo;
+
+ if (argc != 1)
+ command_print(cmd_ctx, "usage: script <file>");
+
+ script_file = fopen(args[0], "r");
+ if (!script_file)
+ {
+ command_print(cmd_ctx, "couldn't open script file %s", args[0]);
+ return ERROR_OK;
+ }
+
+ echo = cmd_ctx->echo;
+ cmd_ctx->echo = 1;
+
+ command_run_file(cmd_ctx, script_file, COMMAND_EXEC);
+
+ cmd_ctx->echo = echo;
+
+ fclose(script_file);
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef INTERPRETER_H
+#define INTERPRETER_H
+
+#include "types.h"
+#include "command.h"
+#include "log.h"
+
+typedef struct var_field_s
+{
+ int num_bits;
+ u32 value;
+} var_field_t;
+
+typedef struct var_s
+{
+ char *name;
+ int num_fields;
+ var_field_t *fields;
+ struct var_s *next;
+} var_t;
+
+extern var_t *variables;
+
+extern int field_le_to_host(u8 *buffer, void *priv);
+
+extern var_t* get_var_by_namenum(char *namenum);
+extern int interpreter_register_commands(struct command_context_s *cmd_ctx);
+
+#endif /* INTERPRETER_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "log.h"
+#include "configuration.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+int debug_level = -1;
+
+static FILE* log_output;
+
+static char *log_strings[4] =
+{
+ "Error: ",
+ "Warning:",
+ "Info: ",
+ "Debug: ",
+};
+
+void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
+{
+ va_list args;
+ char buffer[512];
+
+ if (level > debug_level)
+ return;
+
+ va_start(args, format);
+ vsnprintf(buffer, 512, format, args);
+
+ fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level], file, line, function, buffer);
+ fflush(log_output);
+
+ va_end(args);
+}
+
+void short_log_printf(enum log_levels level, const char *format, ...)
+{
+ va_list args;
+ char buffer[512];
+
+ if (level > debug_level)
+ return;
+
+ va_start(args, format);
+ vsnprintf(buffer, 512, format, args);
+
+ fprintf(log_output, "%s %s\n", log_strings[level], buffer);
+ fflush(log_output);
+
+ va_end(args);
+}
+
+/* change the current debug level on the fly
+ * 0: only ERRORS
+ * 1: + WARNINGS
+ * 2: + INFORMATIONAL MSGS
+ * 3: + DEBUG MSGS
+ */
+int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ command_print(cmd_ctx, "debug_level: %i", debug_level);
+
+ if (argc > 0)
+ debug_level = strtoul(args[0], NULL, 0);
+
+ if (debug_level < 0)
+ debug_level = 0;
+
+ if (debug_level > 3)
+ debug_level = 3;
+
+ return ERROR_OK;
+}
+
+int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 1)
+ {
+ FILE* file = fopen(args[0], "w");
+
+ if (file)
+ {
+ log_output = file;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int log_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
+ COMMAND_ANY, "redirect logging to <file> (default: stderr)");
+ register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
+ COMMAND_ANY, "adjust debug level <0-3>");
+
+ return ERROR_OK;
+}
+
+int log_init(struct command_context_s *cmd_ctx)
+{
+ /* set defaults for daemon configuration, if not set by cmdline or cfgfile */
+ if (debug_level == -1)
+ debug_level = LOG_INFO;
+
+ if (log_output == NULL)
+ {
+ log_output = stderr;
+ }
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef ERROR_H
+#define ERROR_H
+
+#include "command.h"
+
+#include <stdarg.h>
+
+/* logging priorities
+ * LOG_ERROR - fatal errors, that are likely to cause program abort
+ * LOG_WARNING - non-fatal errors, that may be resolved later
+ * LOG_INFO - state information, etc.
+ * LOG_DEBUG - debug statements, execution trace
+ */
+enum log_levels
+{
+ LOG_ERROR = 0,
+ LOG_WARNING = 1,
+ LOG_INFO = 2,
+ LOG_DEBUG = 3
+};
+
+extern void log_printf(enum log_levels level, const char *file, int line,
+ const char *function, const char *format, ...);
+extern int log_register_commands(struct command_context_s *cmd_ctx);
+extern int log_init(struct command_context_s *cmd_ctx);
+
+extern int debug_level;
+
+#define DEBUG(expr ...) \
+ do { \
+ log_printf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define INFO(expr ...) \
+ do { \
+ log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define WARNING(expr ...) \
+ do { \
+ log_printf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define ERROR(expr ...) \
+ do { \
+ log_printf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
+ } while(0)
+
+#define SDEBUG(expr ...) \
+ do { \
+ short_log_printf (LOG_DEBUG, expr); \
+ } while(0)
+
+#define SINFO(expr ...) \
+ do { \
+ short_log_printf (LOG_INFO, expr); \
+ } while(0)
+
+#define SWARNING(expr ...) \
+ do { \
+ short_log_printf (LOG_WARNING, expr); \
+ } while(0)
+
+#define SERROR(expr ...) \
+ do { \
+ short_log_printf (LOG_ERROR, expr); \
+ } while(0)
+
+/* general failures
+ * error codes < 100
+ */
+#define ERROR_OK (0)
+#define ERROR_INVALID_ARGUMENTS (-1)
+#define ERROR_NO_CONFIG_FILE (-2)
+#define ERROR_BUF_TOO_SMALL (-3)
+
+#endif /* ERROR_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+
+#include "time_support.h"
+
+#include <sys/time.h>
+#include <time.h>
+
+int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
+int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y);
+int timeval_add_time(struct timeval *result, int sec, int usec);
+
+/* calculate difference between two struct timeval values */
+int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ 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;
+}
+
+/* add two struct timeval values */
+int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ result->tv_sec = x->tv_sec + y->tv_sec;
+
+ result->tv_usec = x->tv_usec + y->tv_usec;
+
+ while (result->tv_usec > 1000000)
+ {
+ result->tv_usec -= 1000000;
+ result->tv_sec++;
+ }
+
+ return 0;
+}
+
+int timeval_add_time(struct timeval *result, int sec, int usec)
+{
+ result->tv_sec += sec;
+ result->tv_usec += usec;
+
+ while (result->tv_usec > 1000000)
+ {
+ result->tv_usec -= 1000000;
+ result->tv_sec++;
+ }
+
+ return 0;
+}
+
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2006 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef TIME_SUPPORT_H
+#define TIME_SUPPORT_H
+
+#include <sys/time.h>
+#include <time.h>
+
+extern int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
+extern int timeval_add(struct timeval *result, struct timeval *x, struct timeval *y);
+extern int timeval_add_time(struct timeval *result, int sec, int usec);
+
+#endif /* TIME_SUPPORT_H */
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2004, 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef TYPES_H
+#define TYPES_H
+
+#ifndef u8
+typedef unsigned char u8;
+#endif
+
+#ifndef u16
+typedef unsigned short u16;
+#endif
+
+#ifndef u32
+typedef unsigned int u32;
+#endif
+
+#endif /* TYPES_H */
--- /dev/null
+
+if FTD2XXDIR
+FTD2XXINC = -I@WITH_FTD2XX@/
+else
+FTD2XXINC =
+endif
+
+INCLUDES = -I$(top_srcdir)/src/helper $(FTD2XXINC) $(all_includes)
+METASOURCES = AUTO
+noinst_LIBRARIES = libjtag.a
+
+if BITBANG
+BITBANGFILES = bitbang.c
+else
+BITBANGFILES =
+endif
+
+if PARPORT
+PARPORTFILES = parport.c
+else
+PARPORTFILES =
+endif
+
+if FTDI2232
+FTDI2232FILES = ftdi2232.c
+else
+FTDI2232FILES =
+endif
+
+if FTD2XX
+FTD2XXFILES = ftd2xx.c
+else
+FTD2XXFILES =
+endif
+
+if AMTJTAGACCEL
+AMTJTAGACCELFILES = amt_jtagaccel.c
+else
+AMTJTAGACCELFILES =
+endif
+
+if EP93XX
+EP93XXFILES = ep93xx.c
+else
+EP93XXFILES =
+endif
+
+libjtag_a_SOURCES = jtag.c $(BITBANGFILES) $(PARPORTFILES) $(FTDI2232FILES) $(FTD2XXFILES) $(AMTJTAGACCELFILES) $(EP93XXFILES)
+
+noinst_HEADERS = bitbang.h jtag.h
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath *
+ * Dominic.Rath@gmx.de *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "config.h"
+#include "log.h"
+#include "jtag.h"
+
+/* system includes */
+#include <sys/io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/time.h>
+#include <time.h>
+
+#if PARPORT_USE_PPDEV == 1
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#endif
+
+/* configuration */
+unsigned long amt_jtagaccel_port;
+
+/* interface variables
+ */
+static u8 aw_control_rst = 0x00;
+static u8 aw_control_fsm = 0x10;
+static u8 aw_control_baudrate = 0x20;
+
+static int rtck_enabled = 0;
+
+#if PARPORT_USE_PPDEV == 1
+static int device_handle;
+int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR ;
+int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA ;
+#define AMT_AW(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); write(device_handle, &val, 1); } while (0)
+#define AMT_AR(val) do { ioctl(device_handle, PPSETMODE, &addr_mode); read(device_handle, &val, 1); } while (0)
+#define AMT_DW(val) do { ioctl(device_handle, PPSETMODE, &data_mode); write(device_handle, &val, 1); } while (0)
+#define AMT_DR(val) do { ioctl(device_handle, PPSETMODE, &data_mode); read(device_handle, &val, 1); } while (0)
+#else
+#define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0)
+#define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0)
+#define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0)
+#define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0)
+#endif
+
+int amt_jtagaccel_execute_queue(void);
+int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx);
+int amt_jtagaccel_speed(int speed);
+int amt_jtagaccel_init(void);
+int amt_jtagaccel_quit(void);
+
+int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+
+/* tap_move[i][j]: tap movement command to go from state i to state j
+ * 0: Test-Logic-Reset
+ * 1: Run-Test/Idle
+ * 2: Shift-DR
+ * 3: Pause-DR
+ * 4: Shift-IR
+ * 5: Pause-IR
+ */
+u8 amt_jtagaccel_tap_move[6][6][2] =
+{
+ /* TLR RTI SD PD SI PI */
+ {{0x1f, 0x00}, {0x0f, 0x00}, {0x8a, 0x04}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00}}, /* TLR */
+ {{0x1f, 0x00}, {0x00, 0x00}, {0x85, 0x08}, {0x05, 0x00}, {0x8b, 0x08}, {0x0b, 0x00}}, /* RTI */
+ {{0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* SD */
+ {{0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01}}, /* PD */
+ {{0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00}}, /* SI */
+ {{0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00}}, /* PI */
+};
+
+jtag_interface_t amt_jtagaccel_interface =
+{
+ .name = "amt_jtagaccel",
+
+ .execute_queue = amt_jtagaccel_execute_queue,
+
+ .support_statemove = 0,
+
+ .speed = amt_jtagaccel_speed,
+ .register_commands = amt_jtagaccel_register_commands,
+ .init = amt_jtagaccel_init,
+ .quit = amt_jtagaccel_quit,
+};
+
+int amt_jtagaccel_register_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "parport_port", amt_jtagaccel_handle_parport_port_command,
+ COMMAND_CONFIG, NULL);
+ register_command(cmd_ctx, NULL, "rtck", amt_jtagaccel_handle_rtck_command,
+ COMMAND_CONFIG, NULL);
+
+ return ERROR_OK;
+}
+
+void amt_jtagaccel_reset(int trst, int srst)
+{
+ if (trst == 1)
+ aw_control_rst |= 0x4;
+ else if (trst == 0)
+ aw_control_rst &= ~0x4;
+
+ if (srst == 1)
+ aw_control_rst |= 0x1;
+ else if (srst == 0)
+ aw_control_rst &= ~0x1;
+
+ AMT_AW(aw_control_rst);
+}
+
+int amt_jtagaccel_speed(int speed)
+{
+ aw_control_baudrate &= 0xf0;
+ aw_control_baudrate |= speed & 0x0f;
+ AMT_AW(aw_control_baudrate);
+
+ return ERROR_OK;
+}
+
+void amt_jtagaccel_end_state(state)
+{
+ if (tap_move_map[state] != -1)
+ end_state = state;
+ else
+ {
+ ERROR("BUG: %i is not a valid end state", state);
+ exit(-1);
+ }
+}
+
+void amt_wait_scan_busy()
+{
+ int timeout = 4096;
+ u8 ar_status;
+
+ AMT_AR(ar_status);
+ while (((ar_status) & 0x80) && (timeout-- > 0))
+ AMT_AR(ar_status);
+
+ if (ar_status & 0x80)
+ {
+ ERROR("amt_jtagaccel timed out while waiting for end of scan, rtck was %s", (rtck_enabled) ? "enabled" : "disabled");
+ exit(-1);
+ }
+}
+
+void amt_jtagaccel_state_move(void)
+{
+ u8 aw_scan_tms_5;
+ u8 tms_scan[2];
+
+ tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
+ tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
+
+ aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f);
+ AMT_AW(aw_scan_tms_5);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if (tms_scan[0] & 0x80)
+ {
+ aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f);
+ AMT_AW(aw_scan_tms_5);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+ }
+
+ cur_state = end_state;
+}
+
+void amt_jtagaccel_runtest(int num_cycles)
+{
+ int i = 0;
+ u8 aw_scan_tms_5;
+ u8 aw_scan_tms_1to4;
+
+ enum tap_state saved_end_state = end_state;
+
+ /* only do a state_move when we're not already in RTI */
+ if (cur_state != TAP_RTI)
+ {
+ amt_jtagaccel_end_state(TAP_RTI);
+ amt_jtagaccel_state_move();
+ }
+
+ while (num_cycles - i >= 5)
+ {
+ aw_scan_tms_5 = 0x40;
+ AMT_AW(aw_scan_tms_5);
+ i += 5;
+ }
+
+ if (num_cycles - i > 0)
+ {
+ aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4;
+ AMT_AW(aw_scan_tms_1to4);
+ }
+
+ amt_jtagaccel_end_state(saved_end_state);
+ if (cur_state != end_state)
+ amt_jtagaccel_state_move();
+}
+
+void amt_jtagaccel_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
+{
+ int bits_left = scan_size;
+ int bit_count = 0;
+ enum tap_state saved_end_state = end_state;
+ u8 aw_tdi_option;
+ u8 dw_tdi_scan;
+ u8 dr_tdo;
+ u8 aw_tms_scan;
+ u8 tms_scan[2];
+
+ if (ir_scan)
+ amt_jtagaccel_end_state(TAP_SI);
+ else
+ amt_jtagaccel_end_state(TAP_SD);
+
+ amt_jtagaccel_state_move();
+ amt_jtagaccel_end_state(saved_end_state);
+
+ /* handle unaligned bits at the beginning */
+ if ((scan_size - 1) % 8)
+ {
+ aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1);
+ AMT_AW(aw_tdi_option);
+
+ dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff;
+ AMT_DW(dw_tdi_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8));
+ buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo);
+ }
+
+ bit_count += (scan_size - 1) % 8;
+ bits_left -= (scan_size - 1) % 8;
+ }
+
+ while (bits_left - 1 >= 8)
+ {
+ dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff;
+ AMT_DW(dw_tdi_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ buf_set_u32(buffer, bit_count, 8, dr_tdo);
+ }
+
+ bit_count += 8;
+ bits_left -= 8;
+ }
+
+ tms_scan[0] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][0];
+ tms_scan[1] = amt_jtagaccel_tap_move[tap_move_map[cur_state]][tap_move_map[end_state]][1];
+ aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5);
+ AMT_AW(aw_tms_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+
+ if ((type == SCAN_IN) || (type == SCAN_IO))
+ {
+ AMT_DR(dr_tdo);
+ dr_tdo = dr_tdo >> 7;
+ buf_set_u32(buffer, bit_count, 1, dr_tdo);
+ }
+
+ if (tms_scan[0] & 0x80)
+ {
+ aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f);
+ AMT_AW(aw_tms_scan);
+ if (jtag_speed > 3 || rtck_enabled)
+ amt_wait_scan_busy();
+ }
+ cur_state = end_state;
+}
+
+int amt_jtagaccel_execute_queue(void)
+{
+ jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
+ int scan_size;
+ enum scan_type type;
+ u8 *buffer;
+
+ while (cmd)
+ {
+ switch (cmd->type)
+ {
+ case JTAG_END_STATE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("end_state: %i", cmd->cmd.end_state->end_state);
+#endif
+ if (cmd->cmd.end_state->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.end_state->end_state);
+ break;
+ case JTAG_RESET:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+#endif
+ if (cmd->cmd.reset->trst == 1)
+ {
+ cur_state = TAP_TLR;
+ }
+ amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
+ break;
+ case JTAG_RUNTEST:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state);
+#endif
+ if (cmd->cmd.runtest->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.runtest->end_state);
+ amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles);
+ break;
+ case JTAG_STATEMOVE:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("statemove end in %i", cmd->cmd.statemove->end_state);
+#endif
+ if (cmd->cmd.statemove->end_state != -1)
+ amt_jtagaccel_end_state(cmd->cmd.statemove->end_state);
+ amt_jtagaccel_state_move();
+ break;
+ case JTAG_SCAN:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("scan end in %i", cmd->cmd.scan->end_state);
+#endif
+ if (cmd->cmd.scan->end_state != -1)
+ 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)
+ return ERROR_JTAG_QUEUE_FAILED;
+ if (buffer)
+ free(buffer);
+ break;
+ case JTAG_SLEEP:
+#ifdef _DEBUG_JTAG_IO_
+ DEBUG("sleep", cmd->cmd.sleep->us);
+#endif
+ jtag_sleep(cmd->cmd.sleep->us);
+ break;
+ default:
+ ERROR("BUG: unknown JTAG command type encountered");
+ exit(-1);
+ }
+ cmd = cmd->next;
+ }
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_init(void)
+{
+#if PARPORT_USE_PPDEV == 1
+ char buffer[256];
+ int i = 0;
+ u8 control_port;
+#else
+ u8 status_port;
+#endif
+
+#if PARPORT_USE_PPDEV == 1
+ if (device_handle > 0)
+ {
+ ERROR("device is already opened");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port);
+ device_handle = open(buffer, O_RDWR);
+
+ if (device_handle < 0)
+ {
+ ERROR("cannot open device. check it exists and that user read and write rights are set");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = ioctl(device_handle, PPCLAIM);
+ if (i < 0)
+ {
+ ERROR("cannot claim device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ i = IEEE1284_MODE_EPP;
+ i = ioctl(device_handle, PPSETMODE, & i);
+ if (i < 0)
+ {
+ ERROR(" cannot set compatible mode to device");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ control_port = 0x00;
+ i = ioctl(device_handle, PPWCONTROL, &control_port);
+
+ control_port = 0x04;
+ i = ioctl(device_handle, PPWCONTROL, &control_port);
+
+#else
+ if (amt_jtagaccel_port == 0)
+ {
+ amt_jtagaccel_port = 0x378;
+ WARNING("No parport port specified, using default '0x378' (LPT1)");
+ }
+
+ if (ioperm(amt_jtagaccel_port, 5, 1) != 0) {
+ ERROR("missing privileges for direct i/o");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* prepare epp port */
+ /* clear timeout */
+ status_port = inb(amt_jtagaccel_port + 1);
+ outb(status_port | 0x1, amt_jtagaccel_port + 1);
+
+ /* reset epp port */
+ outb(0x00, amt_jtagaccel_port + 2);
+ outb(0x04, amt_jtagaccel_port + 2);
+#endif
+
+ /* enable JTAG port */
+ aw_control_fsm |= 0x04;
+ AMT_AW(aw_control_fsm);
+
+ amt_jtagaccel_speed(jtag_speed);
+
+ if (jtag_reset_config & RESET_TRST_OPEN_DRAIN)
+ aw_control_rst &= ~0x8;
+ else
+ aw_control_rst |= 0x8;
+
+ if (jtag_reset_config & RESET_SRST_PUSH_PULL)
+ aw_control_rst &= ~0x2;
+ else
+ aw_control_rst |= 0x2;
+
+ amt_jtagaccel_reset(0, 0);
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_quit(void)
+{
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ return ERROR_OK;
+
+ /* only if the port wasn't overwritten by cmdline */
+ if (amt_jtagaccel_port == 0)
+ amt_jtagaccel_port = strtoul(args[0], NULL, 0);
+
+ return ERROR_OK;
+}
+
+int amt_jtagaccel_handle_rtck_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc == 0)
+ {
+ command_print(cmd_ctx, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled");
+ return ERROR_OK;
+ }
+ else
+ {
+ if (strcmp(args[0], "enabled") == 0)
+ {
+ rtck_enabled = 1;
+
+ /* set RTCK enable bit */
+ aw_control_fsm |= 0x02;
+ AMT_AW(aw_control_fsm);
+ }
+ }
+
+ return ERROR_OK;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005 by Dominic Rath &nb