- prepare OpenOCD for branching, created ./trunk/
authordrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Fri, 2 Jun 2006 10:36:31 +0000 (10:36 +0000)
committerdrath <drath@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Fri, 2 Jun 2006 10:36:31 +0000 (10:36 +0000)
git-svn-id: svn://svn.berlios.de/openocd/trunk@64 b42882b7-edfa-0310-969c-e2dbd0fdcd60

93 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
bootstrap [new file with mode: 0755]
configure.in [new file with mode: 0644]
doc/configs/arm7_ft2232.cfg [new file with mode: 0644]
doc/configs/arm7_ftd2xx.cfg [new file with mode: 0644]
doc/configs/arm7_wig.cfg [new file with mode: 0644]
doc/configs/arm9_ftd2xx.cfg [new file with mode: 0644]
doc/configs/chameleon.cfg [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/flash/Makefile.am [new file with mode: 0644]
src/flash/at91sam7.c [new file with mode: 0644]
src/flash/at91sam7.h [new file with mode: 0644]
src/flash/cfi.c [new file with mode: 0644]
src/flash/cfi.h [new file with mode: 0644]
src/flash/flash.c [new file with mode: 0644]
src/flash/flash.h [new file with mode: 0644]
src/flash/lpc2000.c [new file with mode: 0644]
src/flash/lpc2000.h [new file with mode: 0644]
src/flash/str7x.c [new file with mode: 0644]
src/flash/str7x.h [new file with mode: 0644]
src/helper/Makefile.am [new file with mode: 0644]
src/helper/binarybuffer.c [new file with mode: 0644]
src/helper/binarybuffer.h [new file with mode: 0644]
src/helper/command.c [new file with mode: 0644]
src/helper/command.h [new file with mode: 0644]
src/helper/configuration.c [new file with mode: 0644]
src/helper/configuration.h [new file with mode: 0644]
src/helper/interpreter.c [new file with mode: 0644]
src/helper/interpreter.h [new file with mode: 0644]
src/helper/log.c [new file with mode: 0644]
src/helper/log.h [new file with mode: 0644]
src/helper/time_support.c [new file with mode: 0644]
src/helper/time_support.h [new file with mode: 0644]
src/helper/types.h [new file with mode: 0644]
src/jtag/Makefile.am [new file with mode: 0644]
src/jtag/amt_jtagaccel.c [new file with mode: 0644]
src/jtag/bitbang.c [new file with mode: 0644]
src/jtag/bitbang.h [new file with mode: 0644]
src/jtag/ep93xx.c [new file with mode: 0644]
src/jtag/ftd2xx.c [new file with mode: 0644]
src/jtag/ftdi2232.c [new file with mode: 0644]
src/jtag/jtag.c [new file with mode: 0644]
src/jtag/jtag.h [new file with mode: 0644]
src/jtag/parport.c [new file with mode: 0644]
src/openocd.c [new file with mode: 0644]
src/server/Makefile.am [new file with mode: 0644]
src/server/gdb_server.c [new file with mode: 0644]
src/server/gdb_server.h [new file with mode: 0644]
src/server/server.c [new file with mode: 0644]
src/server/server.h [new file with mode: 0644]
src/server/telnet_server.c [new file with mode: 0644]
src/server/telnet_server.h [new file with mode: 0644]
src/target/Makefile.am [new file with mode: 0644]
src/target/algorithm.c [new file with mode: 0644]
src/target/algorithm.h [new file with mode: 0644]
src/target/arm720t.c [new file with mode: 0644]
src/target/arm720t.h [new file with mode: 0644]
src/target/arm7_9_common.c [new file with mode: 0644]
src/target/arm7_9_common.h [new file with mode: 0644]
src/target/arm7tdmi.c [new file with mode: 0644]
src/target/arm7tdmi.h [new file with mode: 0644]
src/target/arm920t.c [new file with mode: 0644]
src/target/arm920t.h [new file with mode: 0644]
src/target/arm9tdmi.c [new file with mode: 0644]
src/target/arm9tdmi.h [new file with mode: 0644]
src/target/arm_jtag.c [new file with mode: 0644]
src/target/arm_jtag.h [new file with mode: 0644]
src/target/armv4_5.c [new file with mode: 0644]
src/target/armv4_5.h [new file with mode: 0644]
src/target/armv4_5_cache.c [new file with mode: 0644]
src/target/armv4_5_cache.h [new file with mode: 0644]
src/target/armv4_5_mmu.c [new file with mode: 0644]
src/target/armv4_5_mmu.h [new file with mode: 0644]
src/target/breakpoints.c [new file with mode: 0644]
src/target/breakpoints.h [new file with mode: 0644]
src/target/embeddedice.c [new file with mode: 0644]
src/target/embeddedice.h [new file with mode: 0644]
src/target/etm.c [new file with mode: 0644]
src/target/etm.h [new file with mode: 0644]
src/target/register.c [new file with mode: 0644]
src/target/register.h [new file with mode: 0644]
src/target/target.c [new file with mode: 0644]
src/target/target.h [new file with mode: 0644]
src/xsvf/Makefile.am [new file with mode: 0644]
src/xsvf/xsvf.c [new file with mode: 0644]
src/xsvf/xsvf.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..79755bb
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Dominic Rath <Dominic.Rath@gmx.de>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..5b6e7c6
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+                   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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..66c2887
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,7 @@
+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
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..f200873
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,194 @@
+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.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..02520f2
--- /dev/null
@@ -0,0 +1,5 @@
+# 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
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..30445f1
--- /dev/null
+++ b/README
@@ -0,0 +1,49 @@
+                                    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.
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..335b7c6
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
+- 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.
diff --git a/bootstrap b/bootstrap
new file mode 100755 (executable)
index 0000000..f7c4c0f
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,4 @@
+aclocal \
+&& autoheader \
+&& automake --gnu --add-missing \
+&& autoconf
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..db37806
--- /dev/null
@@ -0,0 +1,112 @@
+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)
diff --git a/doc/configs/arm7_ft2232.cfg b/doc/configs/arm7_ft2232.cfg
new file mode 100644 (file)
index 0000000..369d09b
--- /dev/null
@@ -0,0 +1,26 @@
+#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
diff --git a/doc/configs/arm7_ftd2xx.cfg b/doc/configs/arm7_ftd2xx.cfg
new file mode 100644 (file)
index 0000000..59dad02
--- /dev/null
@@ -0,0 +1,29 @@
+#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
diff --git a/doc/configs/arm7_wig.cfg b/doc/configs/arm7_wig.cfg
new file mode 100644 (file)
index 0000000..c1e6bf9
--- /dev/null
@@ -0,0 +1,28 @@
+#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
diff --git a/doc/configs/arm9_ftd2xx.cfg b/doc/configs/arm9_ftd2xx.cfg
new file mode 100644 (file)
index 0000000..84885dd
--- /dev/null
@@ -0,0 +1,28 @@
+#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
+
diff --git a/doc/configs/chameleon.cfg b/doc/configs/chameleon.cfg
new file mode 100644 (file)
index 0000000..94d581c
--- /dev/null
@@ -0,0 +1,12 @@
+#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
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..e197382
--- /dev/null
@@ -0,0 +1,40 @@
+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) 
diff --git a/src/flash/Makefile.am b/src/flash/Makefile.am
new file mode 100644 (file)
index 0000000..61e363c
--- /dev/null
@@ -0,0 +1,5 @@
+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
diff --git a/src/flash/at91sam7.c b/src/flash/at91sam7.c
new file mode 100644 (file)
index 0000000..8a602a3
--- /dev/null
@@ -0,0 +1,632 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/flash/at91sam7.h b/src/flash/at91sam7.h
new file mode 100644 (file)
index 0000000..8f9e3db
--- /dev/null
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/flash/cfi.c b/src/flash/cfi.c
new file mode 100644 (file)
index 0000000..5e94367
--- /dev/null
@@ -0,0 +1,1194 @@
+/***************************************************************************
+ *   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(&reg_params[0], "r0", 32, PARAM_OUT);
+       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+       init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
+       init_reg_param(&reg_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(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+
+       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(&reg_params[0], "r0", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[0].value, 0, 32, address);
+                       
+                       init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
+                       buf_set_u32(reg_params[1].value, 0, 32, size);
+                       
+                       init_reg_param(&reg_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(&reg_params[0]);
+                       destroy_reg_param(&reg_params[1]);
+                       destroy_reg_param(&reg_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;
+}
diff --git a/src/flash/cfi.h b/src/flash/cfi.h
new file mode 100644 (file)
index 0000000..d9700be
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/flash/flash.c b/src/flash/flash.c
new file mode 100644 (file)
index 0000000..a5067cd
--- /dev/null
@@ -0,0 +1,556 @@
+/***************************************************************************
+ *   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;
+
+}
diff --git a/src/flash/flash.h b/src/flash/flash.h
new file mode 100644 (file)
index 0000000..a8cc186
--- /dev/null
@@ -0,0 +1,76 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/flash/lpc2000.c b/src/flash/lpc2000.c
new file mode 100644 (file)
index 0000000..b6fcb30
--- /dev/null
@@ -0,0 +1,685 @@
+/***************************************************************************
+ *   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(&reg_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(&reg_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(&reg_params[2], "r12", 32, PARAM_OUT);
+       buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
+       
+       /* IAP stack */
+       init_reg_param(&reg_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(&reg_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(&reg_params[0]);
+       destroy_reg_param(&reg_params[1]);
+       destroy_reg_param(&reg_params[2]);
+       destroy_reg_param(&reg_params[3]);
+       destroy_reg_param(&reg_params[4]);
+       
+       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;
+}
diff --git a/src/flash/lpc2000.h b/src/flash/lpc2000.h
new file mode 100644 (file)
index 0000000..dbbe4b6
--- /dev/null
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/flash/str7x.c b/src/flash/str7x.c
new file mode 100644 (file)
index 0000000..2e3a6c8
--- /dev/null
@@ -0,0 +1,469 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/flash/str7x.h b/src/flash/str7x.h
new file mode 100644 (file)
index 0000000..fe63b5e
--- /dev/null
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *   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 */
+
diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am
new file mode 100644 (file)
index 0000000..5fb2241
--- /dev/null
@@ -0,0 +1,6 @@
+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
diff --git a/src/helper/binarybuffer.c b/src/helper/binarybuffer.c
new file mode 100644 (file)
index 0000000..357d05c
--- /dev/null
@@ -0,0 +1,246 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/helper/binarybuffer.h b/src/helper/binarybuffer.h
new file mode 100644 (file)
index 0000000..0a68894
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/command.c b/src/helper/command.c
new file mode 100644 (file)
index 0000000..26eada6
--- /dev/null
@@ -0,0 +1,508 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/helper/command.h b/src/helper/command.h
new file mode 100644 (file)
index 0000000..262786a
--- /dev/null
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/configuration.c b/src/helper/configuration.c
new file mode 100644 (file)
index 0000000..e59ca6d
--- /dev/null
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *   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;
+}
+
diff --git a/src/helper/configuration.h b/src/helper/configuration.h
new file mode 100644 (file)
index 0000000..cd96e2f
--- /dev/null
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/interpreter.c b/src/helper/interpreter.c
new file mode 100644 (file)
index 0000000..7e88263
--- /dev/null
@@ -0,0 +1,237 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/helper/interpreter.h b/src/helper/interpreter.h
new file mode 100644 (file)
index 0000000..93e8d39
--- /dev/null
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/log.c b/src/helper/log.c
new file mode 100644 (file)
index 0000000..60ba80b
--- /dev/null
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/helper/log.h b/src/helper/log.h
new file mode 100644 (file)
index 0000000..c495524
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/time_support.c b/src/helper/time_support.c
new file mode 100644 (file)
index 0000000..5a7869d
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************
+ *   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;
+}
+
diff --git a/src/helper/time_support.h b/src/helper/time_support.h
new file mode 100644 (file)
index 0000000..d8b7fe5
--- /dev/null
@@ -0,0 +1,30 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/helper/types.h b/src/helper/types.h
new file mode 100644 (file)
index 0000000..6d49bbb
--- /dev/null
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *   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 */
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
new file mode 100644 (file)
index 0000000..a3a0660
--- /dev/null
@@ -0,0 +1,50 @@
+
+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
diff --git a/src/jtag/amt_jtagaccel.c b/src/jtag/amt_jtagaccel.c
new file mode 100644 (file)
index 0000000..42f8bc3
--- /dev/null
@@ -0,0 +1,510 @@
+/***************************************************************************
+ *   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;
+}
diff --git a/src/jtag/bitbang.c b/src/jtag/bitbang.c
new file mode 100644 (file)
index 0000000..d6ff289
--- /dev/null
@@ -0,0 +1,219 @@
+/***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath                                 &nb