- prepare OpenOCD for branching, created ./trunk/
git-svn-id: svn://svn.berlios.de/openocd/trunk@64 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
commit
8b4e882a16
|
@ -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.
|
||||
|
||||
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.)
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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.
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -0,0 +1,4 @@
|
|||
aclocal \
|
||||
&& autoheader \
|
||||
&& automake --gnu --add-missing \
|
||||
&& autoconf
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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 */
|
|
@ -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(®_params[0], "r0", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x8);
|
||||
|
||||
/* command result table */
|
||||
init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 4 * 3, PARAM_IN);
|
||||
|
||||
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);
|
||||
|
||||
/* IAP entry point */
|
||||
init_reg_param(®_params[2], "r12", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 0x7ffffff1);
|
||||
|
||||
/* IAP stack */
|
||||
init_reg_param(®_params[3], "r13_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xac);
|
||||
|
||||
/* return address */
|
||||
init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT);
|
||||
buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x4);
|
||||
|
||||
target->type->run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv4_5_info);
|
||||
|
||||
status_code = buf_get_u32(mem_params[1].value, 0, 32);
|
||||
result_table[0] = buf_get_u32(mem_params[1].value, 32, 32);
|
||||
result_table[1] = buf_get_u32(mem_params[1].value, 64, 32);
|
||||
|
||||
destroy_mem_param(&mem_params[0]);
|
||||
destroy_mem_param(&mem_params[1]);
|
||||
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
destroy_reg_param(®_params[3]);
|
||||
destroy_reg_param(®_params[4]);
|
||||
|
||||
return status_code;
|
||||
}
|
||||
|
||||
int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
int status_code;
|
||||
int i;
|
||||
|
||||
if ((first < 0) || (last > bank->num_sectors))
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
|
||||
for (i = first; i <= last; i++)
|
||||
{
|
||||
/* check single sector */
|
||||
param_table[0] = param_table[1] = i;
|
||||
status_code = lpc2000_iap_call(bank, 53, param_table, result_table);
|
||||
|
||||
switch (status_code)
|
||||
{
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
bank->sectors[i].is_erased = 1;
|
||||
break;
|
||||
case LPC2000_SECTOR_NOT_BLANK:
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
case LPC2000_INVALID_SECTOR:
|
||||
bank->sectors[i].is_erased = 0;
|
||||
break;
|
||||
case LPC2000_BUSY:
|
||||
return ERROR_FLASH_BUSY;
|
||||
break;
|
||||
default:
|
||||
ERROR("BUG: unknown LPC2000 status code");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/* flash_bank lpc2000 <base> <size> 0 0 <lpc_variant> <target#> <cclk> [calc_checksum]
|
||||
*/
|
||||
int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info;
|
||||
|
||||
if (argc < 8)
|
||||
{
|
||||
WARNING("incomplete flash_bank lpc2000 configuration");
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
|
||||
bank->driver_priv = lpc2000_info;
|
||||
|
||||
if (strcmp(args[5], "lpc2000_v1") == 0)
|
||||
{
|
||||
lpc2000_info->variant = 1;
|
||||
lpc2000_info->cmd51_dst_boundary = 512;
|
||||
lpc2000_info->cmd51_can_256b = 0;
|
||||
lpc2000_info->cmd51_can_8192b = 1;
|
||||
}
|
||||
else if (strcmp(args[5], "lpc2000_v2") == 0)
|
||||
{
|
||||
lpc2000_info->variant = 2;
|
||||
lpc2000_info->cmd51_dst_boundary = 256;
|
||||
lpc2000_info->cmd51_can_256b = 1;
|
||||
lpc2000_info->cmd51_can_8192b = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("unknown LPC2000 variant");
|
||||
free(lpc2000_info);
|
||||
return ERROR_FLASH_BANK_INVALID;
|
||||
}
|
||||
|
||||
lpc2000_info->target = get_target_by_num(strtoul(args[6], NULL, 0));
|
||||
if (!lpc2000_info->target)
|
||||
{
|
||||
ERROR("no target '%s' configured", args[6]);
|
||||
exit(-1);
|
||||
}
|
||||
lpc2000_info->iap_working_area = NULL;
|
||||
lpc2000_info->cclk = strtoul(args[7], NULL, 0);
|
||||
lpc2000_info->calc_checksum = 0;
|
||||
lpc2000_build_sector_list(bank);
|
||||
|
||||
|
||||
if (argc >= 9)
|
||||
{
|
||||
if (strcmp(args[8], "calc_checksum") == 0)
|
||||
lpc2000_info->calc_checksum = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
int status_code;
|
||||
|
||||
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||
{
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((first < 0) || (last < first) || (last >= bank->num_sectors))
|
||||
{
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
}
|
||||
|
||||
param_table[0] = first;
|
||||
param_table[1] = last;
|
||||
param_table[2] = lpc2000_info->cclk;
|
||||
|
||||
/* Prepare sectors */
|
||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
break;
|
||||
case LPC2000_INVALID_SECTOR:
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
break;
|
||||
default:
|
||||
WARNING("lpc2000 prepare sectors returned %i", status_code);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
/* Erase sectors */
|
||||
status_code = lpc2000_iap_call(bank, 52, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
break;
|
||||
case LPC2000_INVALID_SECTOR:
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
break;
|
||||
default:
|
||||
WARNING("lpc2000 erase sectors returned %i", status_code);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
|
||||
{
|
||||
/* can't protect/unprotect on the lpc2000 */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_write(struct flash_bank_s *bank, u8 *buffer, u32 offset, u32 count)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
target_t *target = lpc2000_info->target;
|
||||
u32 dst_min_alignment;
|
||||
u32 bytes_remaining = count;
|
||||
u32 bytes_written = 0;
|
||||
int first_sector = 0;
|
||||
int last_sector = 0;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
int status_code;
|
||||
int i;
|
||||
working_area_t *download_area;
|
||||
|
||||
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||
{
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* allocate a working area */
|
||||
if (target_alloc_working_area(target, 4096, &download_area) != ERROR_OK)
|
||||
{
|
||||
ERROR("no working area specified, can't write LPC2000 internal flash");
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (offset + count > bank->size)
|
||||
return ERROR_FLASH_DST_OUT_OF_BANK;
|
||||
|
||||
if (lpc2000_info->cmd51_can_256b)
|
||||
dst_min_alignment = 256;
|
||||
else
|
||||
dst_min_alignment = 512;
|
||||
|
||||
if (offset % dst_min_alignment)
|
||||
{
|
||||
WARNING("offset 0x%x breaks required alignment 0x%x", offset, dst_min_alignment);
|
||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||
}
|
||||
|
||||
for (i = 0; i < bank->num_sectors; i++)
|
||||
{
|
||||
if (offset >= bank->sectors[i].offset)
|
||||
first_sector = i;
|
||||
if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
|
||||
last_sector = i;
|
||||
}
|
||||
|
||||
DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector);
|
||||
|
||||
/* check if exception vectors should be flashed */
|
||||
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
|
||||
{
|
||||
u32 checksum = 0;
|
||||
int i = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
DEBUG("0x%2.2x: 0x%8.8x", i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
|
||||
if (i != 5)
|
||||
checksum += buf_get_u32(buffer + (i * 4), 0, 32);
|
||||
}
|
||||
checksum = 0 - checksum;
|
||||
DEBUG("checksum: 0x%8.8x", checksum);
|
||||
buf_set_u32(buffer + 0x14, 0, 32, checksum);
|
||||
}
|
||||
|
||||
while (bytes_remaining > 0)
|
||||
{
|
||||
u32 thisrun_bytes;
|
||||
if (bytes_remaining >= 4096)
|
||||
thisrun_bytes = 4096;
|
||||
else if (bytes_remaining >= 1024)
|
||||
thisrun_bytes = 1024;
|
||||
else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b))
|
||||
thisrun_bytes = 512;
|
||||
else
|
||||
thisrun_bytes = 256;
|
||||
|
||||
/* Prepare sectors */
|
||||
param_table[0] = first_sector;
|
||||
param_table[1] = last_sector;
|
||||
status_code = lpc2000_iap_call(bank, 50, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
break;
|
||||
case LPC2000_INVALID_SECTOR:
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
break;
|
||||
default:
|
||||
WARNING("lpc2000 prepare sectors returned %i", status_code);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (bytes_remaining >= thisrun_bytes)
|
||||
{
|
||||
if (target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, buffer + bytes_written) != ERROR_OK)
|
||||
{
|
||||
target_free_working_area(target, download_area);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 *last_buffer = malloc(thisrun_bytes);
|
||||
int i;
|
||||
memcpy(last_buffer, buffer + bytes_written, bytes_remaining);
|
||||
for (i = bytes_remaining; i < thisrun_bytes; i++)
|
||||
last_buffer[i] = 0xff;
|
||||
target_write_buffer(lpc2000_info->target, download_area->address, thisrun_bytes, last_buffer);
|
||||
free(last_buffer);
|
||||
}
|
||||
|
||||
DEBUG("writing 0x%x bytes to address 0x%x", thisrun_bytes, bank->base + offset + bytes_written);
|
||||
|
||||
/* Write data */
|
||||
param_table[0] = bank->base + offset + bytes_written;
|
||||
param_table[1] = download_area->address;
|
||||
param_table[2] = thisrun_bytes;
|
||||
param_table[3] = lpc2000_info->cclk;
|
||||
status_code = lpc2000_iap_call(bank, 51, param_table, result_table);
|
||||
switch (status_code)
|
||||
{
|
||||
case ERROR_FLASH_OPERATION_FAILED:
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
case LPC2000_CMD_SUCCESS:
|
||||
break;
|
||||
case LPC2000_INVALID_SECTOR:
|
||||
return ERROR_FLASH_SECTOR_INVALID;
|
||||
break;
|
||||
default:
|
||||
WARNING("lpc2000 returned %i", status_code);
|
||||
return ERROR_FLASH_OPERATION_FAILED;
|
||||
}
|
||||
|
||||
if (bytes_remaining > thisrun_bytes)
|
||||
bytes_remaining -= thisrun_bytes;
|
||||
else
|
||||
bytes_remaining = 0;
|
||||
bytes_written += thisrun_bytes;
|
||||
}
|
||||
|
||||
target_free_working_area(target, download_area);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_probe(struct flash_bank_s *bank)
|
||||
{
|
||||
/* we can't probe on an lpc2000
|
||||
* if this is an lpc2xxx, it has the configured flash
|
||||
*/
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_erase_check(struct flash_bank_s *bank)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
|
||||
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||
{
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
|
||||
}
|
||||
|
||||
int lpc2000_protect_check(struct flash_bank_s *bank)
|
||||
{
|
||||
/* sectors are always protected */
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
|
||||
{
|
||||
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
|
||||
|
||||
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %i", lpc2000_info->variant, lpc2000_info->cclk);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
flash_bank_t *bank;
|
||||
u32 param_table[5];
|
||||
u32 result_table[2];
|
||||
int status_code;
|
||||
lpc2000_flash_bank_t *lpc2000_info;
|
||||
|
||||
if (argc < 1)
|
||||
{
|
||||
command_print(cmd_ctx, "usage: lpc2000 part_id <num>");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
bank = get_flash_bank_by_num(strtoul(args[0], NULL, 0));
|
||||
if (!bank)
|
||||
{
|
||||
command_print(cmd_ctx, "flash bank '#%s' is out of bounds", args[0]);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
lpc2000_info = bank->driver_priv;
|
||||
if (lpc2000_info->target->state != TARGET_HALTED)
|
||||
{
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
if ((status_code = lpc2000_iap_call(bank, 54, param_table, result_table)) != 0x0)
|
||||
{
|
||||
if (status_code == ERROR_FLASH_OPERATION_FAILED)
|
||||
{
|
||||
command_print(cmd_ctx, "no sufficient working area specified, can't access LPC2000 IAP interface");
|
||||
return ERROR_OK;
|
||||
}
|
||||
command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_print(cmd_ctx, "lpc2000 part id: 0x%8.8x", result_table[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
/***************************************************************************
|
||||
* 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 "bitbang.h"
|
||||
|
||||
/* project specific includes */
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "jtag.h"
|
||||
#include "configuration.h"
|
||||
|
||||
/* system includes */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
bitbang_interface_t *bitbang_interface;
|
||||
|
||||
int bitbang_execute_queue(void);
|
||||
|
||||
void bitbang_end_state(enum tap_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 bitbang_state_move(void) {
|
||||
|
||||
int i=0, tms=0;
|
||||
u8 tms_scan = TAP_MOVE(cur_state, end_state);
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
tms = (tms_scan >> i) & 1;
|
||||
bitbang_interface->write(0, tms, 0);
|
||||
bitbang_interface->write(1, tms, 0);
|
||||
}
|
||||
bitbang_interface->write(0, tms, 0);
|
||||
|
||||
cur_state = end_state;
|
||||
}
|
||||
|
||||
void bitbang_runtest(int num_cycles)
|
||||
{
|
||||
int i;
|
||||
|
||||
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)
|
||||
{
|
||||
bitbang_end_state(TAP_RTI);
|
||||
bitbang_state_move();
|
||||
}
|
||||
|
||||
/* execute num_cycles */
|
||||
bitbang_interface->write(0, 0, 0);
|
||||
for (i = 0; i < num_cycles; i++)
|
||||
{
|
||||
bitbang_interface->write(1, 0, 0);
|
||||
bitbang_interface->write(0, 0, 0);
|
||||
}
|
||||
|
||||
/* finish in end_state */
|
||||
bitbang_end_state(saved_end_state);
|
||||
if (cur_state != end_state)
|
||||
bitbang_state_move();
|
||||
}
|
||||
|
||||
void bitbang_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
|
||||
{
|
||||
enum tap_state saved_end_state = end_state;
|
||||
int bit_cnt;
|
||||
|
||||
if (ir_scan)
|
||||
bitbang_end_state(TAP_SI);
|
||||
else
|
||||
bitbang_end_state(TAP_SD);
|
||||
|
||||
bitbang_state_move();
|
||||
bitbang_end_state(saved_end_state);
|
||||
|
||||
for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++)
|
||||
{
|
||||
if ((buffer[bit_cnt/8] >> (bit_cnt % 8)) & 0x1) {
|
||||
bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 1);
|
||||
bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 1);
|
||||
} else {
|
||||
bitbang_interface->write(0, (bit_cnt==scan_size-1) ? 1 : 0, 0);
|
||||
bitbang_interface->write(1, (bit_cnt==scan_size-1) ? 1 : 0, 0);
|
||||
}
|
||||
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
if (bitbang_interface->read())
|
||||
buffer[(bit_cnt)/8] |= 1 << ((bit_cnt) % 8);
|
||||
else
|
||||
buffer[(bit_cnt)/8] &= ~(1 << ((bit_cnt) % 8));
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit1 -> Pause */
|
||||
bitbang_interface->write(0, 0, 0);
|
||||
bitbang_interface->write(1, 0, 0);
|
||||
|
||||
if (ir_scan)
|
||||
cur_state = TAP_PI;
|
||||
else
|
||||
cur_state = TAP_PD;
|
||||
|
||||
if (cur_state != end_state)
|
||||
bitbang_state_move();
|
||||
}
|
||||
|
||||
int bitbang_execute_queue(void)
|
||||
{
|
||||
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
u8 *buffer;
|
||||
|
||||
if (!bitbang_interface)
|
||||
{
|
||||
ERROR("BUG: Bitbang interface called, but not yet initialized");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
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)
|
||||
bitbang_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;
|
||||
}
|
||||
bitbang_interface->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)
|
||||
bitbang_end_state(cmd->cmd.runtest->end_state);
|
||||
bitbang_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)
|
||||
bitbang_end_state(cmd->cmd.statemove->end_state);
|
||||
bitbang_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)
|
||||
bitbang_end_state(cmd->cmd.scan->end_state);
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
bitbang_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;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/***************************************************************************
|
||||
* 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 BITBANG_H
|
||||
#define BITBANG_H
|
||||
|
||||
typedef struct bitbang_interface_s
|
||||
{
|
||||
/* low level callbacks (for bitbang)
|
||||
*/
|
||||
int (*read)(void);
|
||||
void (*write)(int tck, int tms, int tdi);
|
||||
void (*reset)(int trst, int srst);
|
||||
} bitbang_interface_t;
|
||||
|
||||
extern bitbang_interface_t *bitbang_interface;
|
||||
|
||||
extern int bitbang_execute_queue(void);
|
||||
|
||||
#endif /* BITBANG_H */
|
|
@ -0,0 +1,236 @@
|
|||
/***************************************************************************
|
||||
* 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"
|
||||
#include "bitbang.h"
|
||||
|
||||
#define TDO_BIT 1
|
||||
#define TDI_BIT 2
|
||||
#define TCK_BIT 4
|
||||
#define TMS_BIT 8
|
||||
#define TRST_BIT 16
|
||||
#define SRST_BIT 32
|
||||
#define VCC_BIT 64
|
||||
|
||||
/* system includes */
|
||||
#include <sys/io.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static u8 output_value = 0x0;
|
||||
static int dev_mem_fd;
|
||||
static void *gpio_controller;
|
||||
static volatile u8 *gpio_data_register;
|
||||
static volatile u8 *gpio_data_direction_register;
|
||||
|
||||
/* low level command set
|
||||
*/
|
||||
int ep93xx_read(void);
|
||||
void ep93xx_write(int tck, int tms, int tdi);
|
||||
void ep93xx_reset(int trst, int srst);
|
||||
|
||||
int ep93xx_speed(int speed);
|
||||
int ep93xx_register_commands(struct command_context_s *cmd_ctx);
|
||||
int ep93xx_init(void);
|
||||
int ep93xx_quit(void);
|
||||
|
||||
struct timespec ep93xx_zzzz;
|
||||
|
||||
jtag_interface_t ep93xx_interface =
|
||||
{
|
||||
.name = "ep93xx",
|
||||
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
|
||||
.support_statemove = 0,
|
||||
|
||||
.speed = ep93xx_speed,
|
||||
.register_commands = ep93xx_register_commands,
|
||||
.init = ep93xx_init,
|
||||
.quit = ep93xx_quit,
|
||||
};
|
||||
|
||||
bitbang_interface_t ep93xx_bitbang =
|
||||
{
|
||||
.read = ep93xx_read,
|
||||
.write = ep93xx_write,
|
||||
.reset = ep93xx_reset
|
||||
};
|
||||
|
||||
int ep93xx_read(void)
|
||||
{
|
||||
return !!(*gpio_data_register & TDO_BIT);
|
||||
}
|
||||
|
||||
void ep93xx_write(int tck, int tms, int tdi)
|
||||
{
|
||||
if (tck)
|
||||
output_value |= TCK_BIT;
|
||||
else
|
||||
output_value &= TCK_BIT;
|
||||
|
||||
if (tms)
|
||||
output_value |= TMS_BIT;
|
||||
else
|
||||
output_value &= TMS_BIT;
|
||||
|
||||
if (tdi)
|
||||
output_value |= TDI_BIT;
|
||||
else
|
||||
output_value &= TDI_BIT;
|
||||
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(ep93xx_zzzz);
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
void ep93xx_reset(int trst, int srst)
|
||||
{
|
||||
if (trst == 0)
|
||||
output_value |= TRST_BIT;
|
||||
else if (trst == 1)
|
||||
output_value &= TRST_BIT;
|
||||
|
||||
if (srst == 0)
|
||||
output_value |= SRST_BIT;
|
||||
else if (srst == 1)
|
||||
output_value &= SRST_BIT;
|
||||
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(ep93xx_zzzz);
|
||||
}
|
||||
|
||||
int ep93xx_speed(int speed)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ep93xx_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int set_gonk_mode(void)
|
||||
{
|
||||
void *syscon;
|
||||
u32 devicecfg;
|
||||
|
||||
syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, 0x80930000);
|
||||
if (syscon == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
devicecfg = *((volatile int *)(syscon + 0x80));
|
||||
*((volatile int *)(syscon + 0xc0)) = 0xaa;
|
||||
*((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000;
|
||||
|
||||
munmap(syscon, 4096);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ep93xx_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bitbang_interface = &ep93xx_bitbang;
|
||||
|
||||
ep93xx_zzzz.tv_sec = 0;
|
||||
ep93xx_zzzz.tv_nsec = 10000000;
|
||||
|
||||
dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
|
||||
if (dev_mem_fd < 0) {
|
||||
perror("open");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, dev_mem_fd, 0x80840000);
|
||||
if (gpio_controller == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
close(dev_mem_fd);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ret = set_gonk_mode();
|
||||
if (ret != ERROR_OK) {
|
||||
munmap(gpio_controller, 4096);
|
||||
close(dev_mem_fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Use GPIO port A. */
|
||||
gpio_data_register = gpio_controller + 0x00;
|
||||
gpio_data_direction_register = gpio_controller + 0x10;
|
||||
|
||||
|
||||
/* Use GPIO port B. */
|
||||
gpio_data_register = gpio_controller + 0x04;
|
||||
gpio_data_direction_register = gpio_controller + 0x14;
|
||||
|
||||
/* Use GPIO port C. */
|
||||
gpio_data_register = gpio_controller + 0x08;
|
||||
gpio_data_direction_register = gpio_controller + 0x18;
|
||||
|
||||
/* Use GPIO port D. */
|
||||
gpio_data_register = gpio_controller + 0x0c;
|
||||
gpio_data_direction_register = gpio_controller + 0x1c;
|
||||
#endif
|
||||
|
||||
/* Use GPIO port C. */
|
||||
gpio_data_register = gpio_controller + 0x08;
|
||||
gpio_data_direction_register = gpio_controller + 0x18;
|
||||
|
||||
printf("gpio_data_register = %08x\n", gpio_data_register);
|
||||
printf("gpio_data_direction_reg = %08x\n", gpio_data_direction_register);
|
||||
/*
|
||||
* Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK
|
||||
* TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and
|
||||
* TMS/TRST/SRST high.
|
||||
*/
|
||||
output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||
*gpio_data_register = output_value;
|
||||
nanosleep(ep93xx_zzzz);
|
||||
|
||||
/*
|
||||
* Configure the direction register. 1 = output, 0 = input.
|
||||
*/
|
||||
*gpio_data_direction_register =
|
||||
TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT;
|
||||
|
||||
nanosleep(ep93xx_zzzz);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ep93xx_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,630 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2004 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. *
|
||||
***************************************************************************/
|
||||
|
||||
/* project specific includes */
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "jtag.h"
|
||||
#include "configuration.h"
|
||||
#include "command.h"
|
||||
|
||||
/* system includes */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <usb.h>
|
||||
#include <ftdi.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
/* enable this to debug io latency
|
||||
*/
|
||||
#if 0
|
||||
#define _DEBUG_USB_IO_
|
||||
#endif
|
||||
|
||||
int ftdi2232_execute_queue(void);
|
||||
|
||||
int ftdi2232_speed(int speed);
|
||||
int ftdi2232_register_commands(struct command_context_s *cmd_ctx);
|
||||
int ftdi2232_init(void);
|
||||
int ftdi2232_quit(void);
|
||||
|
||||
enum { FTDI2232_TRST = 0x10, FTDI2232_SRST = 0x40 };
|
||||
static u8 discrete_output = 0x0 | FTDI2232_TRST | FTDI2232_SRST;
|
||||
static struct ftdi_context ftdic;
|
||||
|
||||
static u8 *ftdi2232_buffer = NULL;
|
||||
static int ftdi2232_buffer_size = 0;
|
||||
static int ftdi2232_read_pointer = 0;
|
||||
static int ftdi2232_expect_read = 0;
|
||||
#define FTDI2232_BUFFER_SIZE 131072
|
||||
#define BUFFER_ADD ftdi2232_buffer[ftdi2232_buffer_size++]
|
||||
#define BUFFER_READ ftdi2232_buffer[ftdi2232_read_pointer++]
|
||||
|
||||
#define FTDI2232_SAVE_SIZE 1024
|
||||
|
||||
int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
static u16 ftdi2232_vid = 0x0403;
|
||||
static u16 ftdi2232_pid = 0x6010;
|
||||
|
||||
jtag_interface_t ftdi2232_interface =
|
||||
{
|
||||
|
||||
.name = "ftdi2232",
|
||||
|
||||
.execute_queue = ftdi2232_execute_queue,
|
||||
|
||||
.support_statemove = 1,
|
||||
|
||||
.speed = ftdi2232_speed,
|
||||
.register_commands = ftdi2232_register_commands,
|
||||
.init = ftdi2232_init,
|
||||
.quit = ftdi2232_quit,
|
||||
};
|
||||
|
||||
int ftdi2232_speed(int speed)
|
||||
{
|
||||
u8 buf[3];
|
||||
|
||||
buf[0] = 0x86; /* command "set divisor" */
|
||||
buf[1] = speed & 0xff; /* valueL (0=6MHz, 1=3MHz, 2=1.5MHz, ...*/
|
||||
buf[2] = (speed >> 8) & 0xff; /* valueH */
|
||||
|
||||
DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]);
|
||||
ftdi_write_data(&ftdic, buf, 3);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ftdi2232_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
register_command(cmd_ctx, NULL, "ftdi2232_vid_pid", ftdi2232_handle_vid_pid_command,
|
||||
COMMAND_CONFIG, NULL);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void ftdi2232_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 ftdi2232_read_scan(enum scan_type type, u8* buffer, int scan_size)
|
||||
{
|
||||
int num_bytes = ((scan_size + 7) / 8);
|
||||
int bits_left = scan_size;
|
||||
int cur_byte = 0;
|
||||
|
||||
while(num_bytes-- > 1)
|
||||
{
|
||||
buffer[cur_byte] = BUFFER_READ;
|
||||
cur_byte++;
|
||||
bits_left -= 8;
|
||||
}
|
||||
|
||||
buffer[cur_byte] = 0x0;
|
||||
|
||||
if (bits_left > 1)
|
||||
{
|
||||
buffer[cur_byte] = BUFFER_READ >> 1;
|
||||
}
|
||||
|
||||
buffer[cur_byte] = (buffer[cur_byte] | ((BUFFER_READ & 0x02) << 6)) >> (8 - bits_left);
|
||||
|
||||
}
|
||||
|
||||
void ftdi2232_debug_dump_buffer(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ftdi2232_buffer_size; i++)
|
||||
{
|
||||
printf("%2.2x ", ftdi2232_buffer[i]);
|
||||
if (i % 16 == 15)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int ftdi2232_send_and_recv(jtag_command_t *first, jtag_command_t *last)
|
||||
{
|
||||
jtag_command_t *cmd;
|
||||
u8 *buffer;
|
||||
int scan_size;
|
||||
enum scan_type type;
|
||||
int retval;
|
||||
|
||||
BUFFER_ADD = 0x87; /* send immediate command */
|
||||
|
||||
if (ftdi2232_buffer_size > FTDI2232_SAVE_SIZE)
|
||||
{
|
||||
ERROR("BUG: ftdi2232_buffer grew beyond %i byte (%i) - this is going to fail", FTDI2232_SAVE_SIZE, ftdi2232_buffer_size);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_USB_IO_
|
||||
DEBUG("write buffer (size %i):", ftdi2232_buffer_size);
|
||||
ftdi2232_debug_dump_buffer();
|
||||
#endif
|
||||
|
||||
if ((retval = ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size)) < 0)
|
||||
{
|
||||
ERROR("ftdi_write_data returned %i", retval);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (ftdi2232_expect_read)
|
||||
{
|
||||
int timeout = 100;
|
||||
ftdi2232_buffer_size = 0;
|
||||
|
||||
while ((ftdi2232_buffer_size < ftdi2232_expect_read) && timeout)
|
||||
{
|
||||
ftdi2232_buffer_size += ftdi_read_data(&ftdic, ftdi2232_buffer + ftdi2232_buffer_size, FTDI2232_BUFFER_SIZE - ftdi2232_buffer_size);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (ftdi2232_expect_read != ftdi2232_buffer_size)
|
||||
{
|
||||
ERROR("ftdi2232_expect_read (%i) != ftdi2232_buffer_size (%i) (%i retries)", ftdi2232_expect_read, ftdi2232_buffer_size, 100 - timeout);
|
||||
ftdi2232_debug_dump_buffer();
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG_USB_IO_
|
||||
DEBUG("read buffer (%i retries): %i bytes", 100 - timeout, ftdi2232_buffer_size);
|
||||
ftdi2232_debug_dump_buffer();
|
||||
#endif
|
||||
}
|
||||
|
||||
ftdi2232_expect_read = 0;
|
||||
ftdi2232_read_pointer = 0;
|
||||
|
||||
cmd = first;
|
||||
while (cmd != last)
|
||||
{
|
||||
switch (cmd->type)
|
||||
{
|
||||
case JTAG_SCAN:
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
scan_size = jtag_scan_size(cmd->cmd.scan);
|
||||
buffer = calloc(CEIL(scan_size, 8), 1);
|
||||
ftdi2232_read_scan(type, buffer, scan_size);
|
||||
jtag_read_buffer(buffer, cmd->cmd.scan);
|
||||
free(buffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
ftdi2232_buffer_size = 0;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void ftdi2232_add_scan(int ir_scan, enum scan_type type, u8 *buffer, int scan_size)
|
||||
{
|
||||
int num_bytes = (scan_size + 7) / 8;
|
||||
int bits_left = scan_size;
|
||||
int cur_byte = 0;
|
||||
int last_bit;
|
||||
|
||||
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||
BUFFER_ADD = 0x4b;
|
||||
/* scan 7 bit */
|
||||
BUFFER_ADD = 0x6;
|
||||
/* TMS data bits */
|
||||
if (ir_scan)
|
||||
{
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, TAP_SI);
|
||||
cur_state = TAP_SI;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, TAP_SD);
|
||||
cur_state = TAP_SD;
|
||||
}
|
||||
//DEBUG("added TMS scan (no read)");
|
||||
|
||||
/* add command for complete bytes */
|
||||
if (num_bytes > 1)
|
||||
{
|
||||
if (type == SCAN_IO)
|
||||
{
|
||||
/* Clock Data Bytes In and Out LSB First */
|
||||
BUFFER_ADD = 0x39;
|
||||
//DEBUG("added TDI bytes (io %i)", num_bytes);
|
||||
}
|
||||
else if (type == SCAN_OUT)
|
||||
{
|
||||
/* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */
|
||||
BUFFER_ADD = 0x19;
|
||||
//DEBUG("added TDI bytes (o)");
|
||||
}
|
||||
else if (type == SCAN_IN)
|
||||
{
|
||||
/* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */
|
||||
BUFFER_ADD = 0x28;
|
||||
//DEBUG("added TDI bytes (i %i)", num_bytes);
|
||||
}
|
||||
BUFFER_ADD = (num_bytes-2) & 0xff;
|
||||
BUFFER_ADD = ((num_bytes-2) >> 8) & 0xff;
|
||||
}
|
||||
if (type != SCAN_IN)
|
||||
{
|
||||
/* add complete bytes */
|
||||
while(num_bytes-- > 1)
|
||||
{
|
||||
BUFFER_ADD = buffer[cur_byte];
|
||||
cur_byte++;
|
||||
bits_left -= 8;
|
||||
}
|
||||
}
|
||||
if (type == SCAN_IN)
|
||||
{
|
||||
bits_left -= 8 * (num_bytes - 1);
|
||||
}
|
||||
|
||||
/* the most signifcant bit is scanned during TAP movement */
|
||||
if (type != SCAN_IN)
|
||||
last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1;
|
||||
else
|
||||
last_bit = 0;
|
||||
|
||||
/* process remaining bits but the last one */
|
||||
if (bits_left > 1)
|
||||
{
|
||||
if (type == SCAN_IO)
|
||||
{
|
||||
/* Clock Data Bits In and Out LSB First */
|
||||
BUFFER_ADD = 0x3b;
|
||||
//DEBUG("added TDI bits (io) %i", bits_left - 1);
|
||||
}
|
||||
else if (type == SCAN_OUT)
|
||||
{
|
||||
/* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */
|
||||
BUFFER_ADD = 0x1b;
|
||||
//DEBUG("added TDI bits (o)");
|
||||
}
|
||||
else if (type == SCAN_IN)
|
||||
{
|
||||
/* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */
|
||||
BUFFER_ADD = 0x2a;
|
||||
//DEBUG("added TDI bits (i %i)", bits_left - 1);
|
||||
}
|
||||
BUFFER_ADD = bits_left - 2;
|
||||
if (type != SCAN_IN)
|
||||
BUFFER_ADD = buffer[cur_byte];
|
||||
}
|
||||
|
||||
/* move from Shift-IR/DR to end state */
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
/* Clock Data to TMS/CS Pin with Read */
|
||||
BUFFER_ADD = 0x6b;
|
||||
//DEBUG("added TMS scan (read)");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clock Data to TMS/CS Pin (no Read) */
|
||||
BUFFER_ADD = 0x4b;
|
||||
//DEBUG("added TMS scan (no read)");
|
||||
}
|
||||
BUFFER_ADD = 0x6;
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, end_state) | (last_bit << 7);
|
||||
cur_state = end_state;
|
||||
|
||||
}
|
||||
|
||||
int ftdi2232_predict_scan_out(int scan_size, enum scan_type type)
|
||||
{
|
||||
int predicted_size = 6;
|
||||
if (type == SCAN_IN) /* only from device to host */
|
||||
{
|
||||
predicted_size += (CEIL(scan_size, 8) > 1) ? 3 : 0;
|
||||
predicted_size += ((scan_size - 1) % 8) ? 2 : 0;
|
||||
}
|
||||
else /* host to device, or bidirectional */
|
||||
{
|
||||
predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) + 3 - 1) : 0;
|
||||
predicted_size += ((scan_size - 1) % 8) ? 3 : 0;
|
||||
}
|
||||
|
||||
return predicted_size;
|
||||
}
|
||||
|
||||
int ftdi2232_predict_scan_in(int scan_size, enum scan_type type)
|
||||
{
|
||||
int predicted_size = 0;
|
||||
|
||||
if (type != SCAN_OUT)
|
||||
{
|
||||
/* complete bytes */
|
||||
predicted_size += (CEIL(scan_size, 8) > 1) ? (CEIL(scan_size, 8) - 1) : 0;
|
||||
/* remaining bits - 1 */
|
||||
predicted_size += ((scan_size - 1) % 8) ? 1 : 0;
|
||||
/* last bit (from TMS scan) */
|
||||
predicted_size += 1;
|
||||
}
|
||||
|
||||
//DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size);
|
||||
|
||||
return predicted_size;
|
||||
}
|
||||
|
||||
int ftdi2232_execute_queue()
|
||||
{
|
||||
jtag_command_t *cmd = jtag_command_queue; /* currently processed command */
|
||||
jtag_command_t *first_unsent = cmd; /* next command that has to be sent */
|
||||
u8 *buffer;
|
||||
int scan_size; /* size of IR or DR scan */
|
||||
enum scan_type type;
|
||||
int i;
|
||||
int predicted_size = 0;
|
||||
int require_send = 0;
|
||||
|
||||
ftdi2232_buffer_size = 0;
|
||||
ftdi2232_expect_read = 0;
|
||||
|
||||
while (cmd)
|
||||
{
|
||||
switch(cmd->type)
|
||||
{
|
||||
case JTAG_END_STATE:
|
||||
if (cmd->cmd.end_state->end_state != -1)
|
||||
ftdi2232_end_state(cmd->cmd.end_state->end_state);
|
||||
break;
|
||||
case JTAG_RESET:
|
||||
/* only send the maximum buffer size that FT2232C can handle */
|
||||
predicted_size = 3;
|
||||
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||
{
|
||||
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||
require_send = 0;
|
||||
first_unsent = cmd;
|
||||
}
|
||||
|
||||
if (cmd->cmd.reset->trst == 1)
|
||||
{
|
||||
cur_state = TAP_TLR;
|
||||
discrete_output &= ~FTDI2232_TRST;
|
||||
}
|
||||
else if (cmd->cmd.reset->trst == 0)
|
||||
{
|
||||
discrete_output |= FTDI2232_TRST;
|
||||
}
|
||||
|
||||
if (cmd->cmd.reset->srst == 1)
|
||||
discrete_output &= ~FTDI2232_SRST;
|
||||
else if (cmd->cmd.reset->srst == 0)
|
||||
discrete_output |= FTDI2232_SRST;
|
||||
/* command "set data bits low byte" */
|
||||
BUFFER_ADD = 0x80;
|
||||
/* value (TMS=1,TCK=0, TDI=0, TRST/SRST */
|
||||
BUFFER_ADD = 0x08 | discrete_output;
|
||||
/* dir (output=1), TCK/TDI/TMS=out, TDO=in, TRST/SRST=out */
|
||||
BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST;
|
||||
require_send = 1;
|
||||
break;
|
||||
case JTAG_RUNTEST:
|
||||
/* only send the maximum buffer size that FT2232C can handle */
|
||||
predicted_size = 0;
|
||||
if (cur_state != TAP_RTI)
|
||||
predicted_size += 3;
|
||||
predicted_size += 3 * CEIL(cmd->cmd.runtest->num_cycles, 7);
|
||||
if ((cmd->cmd.runtest->end_state != -1) && (cmd->cmd.runtest->end_state != TAP_RTI))
|
||||
predicted_size += 3;
|
||||
if ((cmd->cmd.runtest->end_state == -1) && (end_state != TAP_RTI))
|
||||
predicted_size += 3;
|
||||
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||
{
|
||||
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||
require_send = 0;
|
||||
first_unsent = cmd;
|
||||
}
|
||||
if (cur_state != TAP_RTI)
|
||||
{
|
||||
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||
BUFFER_ADD = 0x4b;
|
||||
/* scan 7 bit */
|
||||
BUFFER_ADD = 0x6;
|
||||
/* TMS data bits */
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, TAP_RTI);
|
||||
cur_state = TAP_RTI;
|
||||
require_send = 1;
|
||||
}
|
||||
i = cmd->cmd.runtest->num_cycles;
|
||||
while (i > 0)
|
||||
{
|
||||
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||
BUFFER_ADD = 0x4b;
|
||||
/* scan 7 bit */
|
||||
BUFFER_ADD = (i > 7) ? 6 : (i - 1);
|
||||
/* TMS data bits */
|
||||
BUFFER_ADD = 0x0;
|
||||
cur_state = TAP_RTI;
|
||||
i -= (i > 7) ? 7 : i;
|
||||
//DEBUG("added TMS scan (no read)");
|
||||
}
|
||||
if (cmd->cmd.runtest->end_state != -1)
|
||||
ftdi2232_end_state(cmd->cmd.runtest->end_state);
|
||||
if (cur_state != end_state)
|
||||
{
|
||||
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||
BUFFER_ADD = 0x4b;
|
||||
/* scan 7 bit */
|
||||
BUFFER_ADD = 0x6;
|
||||
/* TMS data bits */
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, end_state);
|
||||
cur_state = end_state;
|
||||
//DEBUG("added TMS scan (no read)");
|
||||
}
|
||||
require_send = 1;
|
||||
break;
|
||||
case JTAG_STATEMOVE:
|
||||
/* only send the maximum buffer size that FT2232C can handle */
|
||||
predicted_size = 3;
|
||||
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||
{
|
||||
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||
require_send = 0;
|
||||
first_unsent = cmd;
|
||||
}
|
||||
if (cmd->cmd.statemove->end_state != -1)
|
||||
ftdi2232_end_state(cmd->cmd.statemove->end_state);
|
||||
/* command "Clock Data to TMS/CS Pin (no Read)" */
|
||||
BUFFER_ADD = 0x4b;
|
||||
/* scan 7 bit */
|
||||
BUFFER_ADD = 0x6;
|
||||
/* TMS data bits */
|
||||
BUFFER_ADD = TAP_MOVE(cur_state, end_state);
|
||||
//DEBUG("added TMS scan (no read)");
|
||||
cur_state = end_state;
|
||||
require_send = 1;
|
||||
break;
|
||||
case JTAG_SCAN:
|
||||
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
|
||||
type = jtag_scan_type(cmd->cmd.scan);
|
||||
predicted_size = ftdi2232_predict_scan_out(scan_size, type);
|
||||
if (ftdi2232_buffer_size + predicted_size + 1 > FTDI2232_SAVE_SIZE)
|
||||
{
|
||||
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||
require_send = 0;
|
||||
first_unsent = cmd;
|
||||
}
|
||||
ftdi2232_expect_read += ftdi2232_predict_scan_in(scan_size, type);
|
||||
//DEBUG("new read size: %i", ftdi2232_expect_read);
|
||||
if (cmd->cmd.scan->end_state != -1)
|
||||
ftdi2232_end_state(cmd->cmd.scan->end_state);
|
||||
ftdi2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
|
||||
require_send = 1;
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
break;
|
||||
case JTAG_SLEEP:
|
||||
jtag_sleep(cmd->cmd.sleep->us);
|
||||
break;
|
||||
default:
|
||||
ERROR("BUG: unknown JTAG command type encountered");
|
||||
exit(-1);
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
|
||||
if (require_send > 0)
|
||||
ftdi2232_send_and_recv(first_unsent, cmd);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ftdi2232_init(void)
|
||||
{
|
||||
if (ftdi_init(&ftdic) < 0)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
/* context, vendor id, product id */
|
||||
if (ftdi_usb_open(&ftdic, ftdi2232_vid, ftdi2232_pid) < 0)
|
||||
{
|
||||
ERROR("unable to open ftdi device: %s", ftdic.error_str);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
if (ftdi_usb_reset(&ftdic) < 0)
|
||||
{
|
||||
ERROR("unable to reset ftdi device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
if (ftdi_set_latency_timer(&ftdic, 1) < 0)
|
||||
{
|
||||
ERROR("unable to set latency timer");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
ftdi2232_buffer_size = 0;
|
||||
ftdi2232_buffer = malloc(FTDI2232_BUFFER_SIZE);
|
||||
|
||||
ftdic.bitbang_mode = 0; /* Reset controller */
|
||||
ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
|
||||
|
||||
ftdic.bitbang_mode = 2; /* MPSSE mode */
|
||||
ftdi_enable_bitbang(&ftdic, 0x0b | FTDI2232_SRST | FTDI2232_TRST); /* ctx, i/o mask (out=1, in=0) */
|
||||
|
||||
if (ftdi_usb_purge_buffers(&ftdic) < 0)
|
||||
{
|
||||
ERROR("ftdi_purge_buffers: %s", ftdic.error_str);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
/* initialize low byte for jtag */
|
||||
BUFFER_ADD = 0x80; /* command "set data bits low byte" */
|
||||
BUFFER_ADD = 0x08 | FTDI2232_SRST | FTDI2232_TRST; /* value (TMS=1,TCK=0, TDI=0, xRST high) */
|
||||
BUFFER_ADD = 0x0b | FTDI2232_SRST | FTDI2232_TRST; /* dir (output=1), TCK/TDI/TMS=out, TDO=in */
|
||||
BUFFER_ADD = 0x85; /* command "Disconnect TDI/DO to TDO/DI for Loopback" */
|
||||
ftdi2232_debug_dump_buffer();
|
||||
if (ftdi_write_data(&ftdic, ftdi2232_buffer, ftdi2232_buffer_size) != 4)
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
|
||||
ftdi2232_speed(jtag_speed);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ftdi2232_quit(void)
|
||||
{
|
||||
ftdi_disable_bitbang(&ftdic);
|
||||
|
||||
ftdi_usb_close(&ftdic);
|
||||
|
||||
ftdi_deinit(&ftdic);
|
||||
|
||||
free(ftdi2232_buffer);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int ftdi2232_handle_vid_pid_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
if (argc >= 2)
|
||||
{
|
||||
ftdi2232_vid = strtol(args[0], NULL, 0);
|
||||
ftdi2232_pid = strtol(args[1], NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARNING("incomplete ftdi2232_vid_pid configuration directive");
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,270 @@
|
|||
/***************************************************************************
|
||||
* 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 JTAG_H
|
||||
#define JTAG_H
|
||||
|
||||
#include "types.h"
|
||||
#include "binarybuffer.h"
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#if 0
|
||||
#define _DEBUG_JTAG_IO_
|
||||
#endif
|
||||
|
||||
/* Tap States
|
||||
* TLR - Test-Logic-Reset, RTI - Run-Test/Idle,
|
||||
* SDS - Select-DR-Scan, CD - Capture-DR, SD - Shift-DR, E1D - Exit1-DR,
|
||||
* PD - Pause-DR, E2D - Exit2-DR, UD - Update-DR,
|
||||
* SIS - Select-IR-Scan, CI - Capture-IR, SI - Shift-IR, E1I - Exit1-IR,
|
||||
* PI - Pause-IR, E2I - Exit2-IR, UI - Update-IR
|
||||
*/
|
||||
enum tap_state
|
||||
{
|
||||
TAP_TLR = 0x0, TAP_RTI = 0x8,
|
||||
TAP_SDS = 0x1, TAP_CD = 0x2, TAP_SD = 0x3, TAP_E1D = 0x4,
|
||||
TAP_PD = 0x5, TAP_E2D = 0x6, TAP_UD = 0x7,
|
||||
TAP_SIS = 0x9, TAP_CI = 0xa, TAP_SI = 0xb, TAP_E1I = 0xc,
|
||||
TAP_PI = 0xd, TAP_E2I = 0xe, TAP_UI = 0xf
|
||||
};
|
||||
|
||||
typedef struct tap_transition_s
|
||||
{
|
||||
enum tap_state high;
|
||||
enum tap_state low;
|
||||
} tap_transition_t;
|
||||
|
||||
extern char* tap_state_strings[16];
|
||||
extern int tap_move_map[16]; /* map 16 TAP states to 6 stable states */
|
||||
extern u8 tap_move[6][6]; /* value scanned to TMS to move from one of six stable states to another */
|
||||
extern tap_transition_t tap_transitions[16]; /* describe the TAP state diagram */
|
||||
|
||||
extern enum tap_state end_state; /* finish DR scans in dr_end_state */
|
||||
extern enum tap_state cur_state; /* current TAP state */
|
||||
|
||||
#define TAP_MOVE(from, to) tap_move[tap_move_map[from]][tap_move_map[to]]
|
||||
|
||||
typedef struct scan_field_s
|
||||
{
|
||||
int device; /* ordinal device number this instruction refers to */
|
||||
int num_bits; /* number of bits this field specifies (up to 32) */
|
||||
u8 *out_value; /* value to be scanned into the device */
|
||||
u8 *out_mask; /* only masked bits care */
|
||||
u8 *in_value; /* pointer to a 32-bit memory location to take data scanned out */
|
||||
u8 *in_check_value; /* used to validate scan results */
|
||||
u8 *in_check_mask; /* check specified bits against check_value */
|
||||
int (*in_handler)(u8 *in_value, void *priv); /* process received buffer using this handler */
|
||||
void *in_handler_priv; /* additional information for the in_handler */
|
||||
} scan_field_t;
|
||||
|
||||
enum scan_type
|
||||
{
|
||||
/* IN: from device to host, OUT: from host to device */
|
||||
SCAN_IN = 1, SCAN_OUT = 2, SCAN_IO = 3
|
||||
};
|
||||
|
||||
typedef struct scan_command_s
|
||||
{
|
||||
int ir_scan; /* instruction/not data scan */
|
||||
int num_fields; /* number of fields in *fields array */
|
||||
scan_field_t *fields; /* pointer to an array of data scan fields */
|
||||
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||
} scan_command_t;
|
||||
|
||||
typedef struct statemove_command_s
|
||||
{
|
||||
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||
} statemove_command_t;
|
||||
|
||||
typedef struct pathmove_command_s
|
||||
{
|
||||
int num_states; /* number of states in *path */
|
||||
enum tap_state *path; /* states that have to be passed */
|
||||
} pathmove_command_t;
|
||||
|
||||
typedef struct runtest_command_s
|
||||
{
|
||||
int num_cycles; /* number of cycles that should be spent in Run-Test/Idle */
|
||||
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||
} runtest_command_t;
|
||||
|
||||
typedef struct reset_command_s
|
||||
{
|
||||
int trst; /* trst/srst 0: deassert, 1: assert, -1: don't change */
|
||||
int srst;
|
||||
} reset_command_t;
|
||||
|
||||
typedef struct end_state_command_s
|
||||
{
|
||||
enum tap_state end_state; /* TAP state in which JTAG commands should finish */
|
||||
} end_state_command_t;
|
||||
|
||||
typedef struct sleep_command_s
|
||||
{
|
||||
u32 us; /* number of microseconds to sleep */
|
||||
} sleep_command_t;
|
||||
|
||||
typedef union jtag_command_container_u
|
||||
{
|
||||
scan_command_t *scan;
|
||||
statemove_command_t *statemove;
|
||||
pathmove_command_t *pathmove;
|
||||
runtest_command_t *runtest;
|
||||
reset_command_t *reset;
|
||||
end_state_command_t *end_state;
|
||||
sleep_command_t *sleep;
|
||||
} jtag_command_container_t;
|
||||
|
||||
enum jtag_command_type
|
||||
{
|
||||
JTAG_SCAN = 1,
|
||||
JTAG_STATEMOVE = 2, JTAG_RUNTEST = 3,
|
||||
JTAG_RESET = 4, JTAG_END_STATE = 5,
|
||||
JTAG_PATHMOVE = 6, JTAG_SLEEP = 7
|
||||
};
|
||||
|
||||
typedef struct jtag_command_s
|
||||
{
|
||||
jtag_command_container_t cmd;
|
||||
enum jtag_command_type type;
|
||||
struct jtag_command_s *next;
|
||||
} jtag_command_t;
|
||||
|
||||
extern jtag_command_t *jtag_command_queue;
|
||||
|
||||
typedef struct jtag_device_s
|
||||
{
|
||||
int ir_length; /* size of instruction register */
|
||||
u8 *expected; /* Capture-IR expected value */
|
||||
u8 *expected_mask; /* Capture-IR expected mask */
|
||||
u32 idcode; /* device identification code */
|
||||
u8 *cur_instr; /* current instruction */
|
||||
int bypass; /* bypass register selected */
|
||||
struct jtag_device_s *next;
|
||||
} jtag_device_t;
|
||||
|
||||
extern jtag_device_t *jtag_devices;
|
||||
extern int jtag_num_devices;
|
||||
extern int jtag_ir_scan_size;
|
||||
|
||||
enum reset_line_mode
|
||||
{
|
||||
LINE_OPEN_DRAIN = 0x0,
|
||||
LINE_PUSH_PULL = 0x1,
|
||||
};
|
||||
|
||||
typedef struct jtag_interface_s
|
||||
{
|
||||
char* name;
|
||||
|
||||
/* queued command execution
|
||||
*/
|
||||
int (*execute_queue)(void);
|
||||
|
||||
/* optional command support
|
||||
*/
|
||||
int support_statemove;
|
||||
|
||||
/* interface initalization
|
||||
*/
|
||||
int (*speed)(int speed);
|
||||
int (*register_commands)(struct command_context_s *cmd_ctx);
|
||||
int (*init)(void);
|
||||
int (*quit)(void);
|
||||
|
||||
} jtag_interface_t;
|
||||
|
||||
enum jtag_event
|
||||
{
|
||||
JTAG_SRST_ASSERTED,
|
||||
JTAG_TRST_ASSERTED,
|
||||
JTAG_SRST_RELEASED,
|
||||
JTAG_TRST_RELEASED,
|
||||
};
|
||||
|
||||
typedef struct jtag_event_callback_s
|
||||
{
|
||||
int (*callback)(enum jtag_event event, void *priv);
|
||||
void *priv;
|
||||
struct jtag_event_callback_s *next;
|
||||
} jtag_event_callback_t;
|
||||
|
||||
extern jtag_event_callback_t *jtag_event_callbacks;
|
||||
|
||||
extern jtag_interface_t *jtag; /* global pointer to configured JTAG interface */
|
||||
extern enum tap_state end_state;
|
||||
extern enum tap_state cur_state;
|
||||
|
||||
extern char* jtag_interface;
|
||||
extern int jtag_speed;
|
||||
|
||||
enum reset_types
|
||||
{
|
||||
RESET_NONE = 0x0,
|
||||
RESET_HAS_TRST = 0x1,
|
||||
RESET_HAS_SRST = 0x2,
|
||||
RESET_TRST_AND_SRST = 0x3,
|
||||
RESET_SRST_PULLS_TRST = 0x4,
|
||||
RESET_TRST_PULLS_SRST = 0x8,
|
||||
RESET_TRST_OPEN_DRAIN = 0x10,
|
||||
RESET_SRST_PUSH_PULL = 0x20,
|
||||
};
|
||||
|
||||
extern enum reset_types jtag_reset_config;
|
||||
|
||||
/* JTAG subsystem */
|
||||
extern int jtag_init(struct command_context_s *cmd_ctx);
|
||||
extern int jtag_register_commands(struct command_context_s *cmd_ctx);
|
||||
|
||||
/* JTAG interface */
|
||||
extern int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||
extern int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||
extern int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||
extern int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
|
||||
extern int jtag_add_statemove(enum tap_state endstate);
|
||||
extern int jtag_add_pathmove(int num_states, enum tap_state *path);
|
||||
extern int jtag_add_runtest(int num_cycles, enum tap_state endstate);
|
||||
extern int jtag_add_reset(int trst, int srst);
|
||||
extern int jtag_add_end_state(enum tap_state endstate);
|
||||
extern int jtag_add_sleep(u32 us);
|
||||
extern int jtag_execute_queue(void);
|
||||
extern int jtag_cancel_queue(void);
|
||||
|
||||
/* JTAG support functions */
|
||||
extern enum scan_type jtag_scan_type(scan_command_t *cmd);
|
||||
extern int jtag_scan_size(scan_command_t *cmd);
|
||||
extern int jtag_read_buffer(u8 *buffer, scan_command_t *cmd);
|
||||
extern int jtag_build_buffer(scan_command_t *cmd, u8 **buffer);
|
||||
extern jtag_device_t* jtag_get_device(int num);
|
||||
extern void jtag_sleep(u32 us);
|
||||
extern int jtag_call_event_callbacks(enum jtag_event event);
|
||||
extern int jtag_register_event_callback(int (*callback)(enum jtag_event event, void *priv), void *priv);
|
||||
|
||||
/* error codes
|
||||
* JTAG subsystem uses codes between -100 and -199 */
|
||||
|
||||
#define ERROR_JTAG_INIT_FAILED (-100)
|
||||
#define ERROR_JTAG_INVALID_INTERFACE (-101)
|
||||
#define ERROR_JTAG_NOT_IMPLEMENTED (-102)
|
||||
#define ERROR_JTAG_TRST_ASSERTED (-103)
|
||||
#define ERROR_JTAG_QUEUE_FAILED (-104)
|
||||
#define ERROR_JTAG_RESET_WOULD_ASSERT_TRST (-105)
|
||||
#define ERROR_JTAG_RESET_CANT_SRST (-106)
|
||||
#endif /* JTAG_H */
|
|
@ -0,0 +1,351 @@
|
|||
/***************************************************************************
|
||||
* 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"
|
||||
#include "bitbang.h"
|
||||
|
||||
/* system includes */
|
||||
// -ino: 060521-1036
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <machine/sysarch.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#define ioperm(startport,length,enable)\
|
||||
i386_set_ioperm((startport), (length), (enable))
|
||||
#else
|
||||
#include <sys/io.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
#include <linux/parport.h>
|
||||
#include <linux/ppdev.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
/* parallel port cable description
|
||||
*/
|
||||
typedef struct cable_s
|
||||
{
|
||||
char* name;
|
||||
u8 TDO_MASK; /* status port bit containing current TDO value */
|
||||
u8 TRST_MASK; /* data port bit for TRST */
|
||||
u8 TMS_MASK; /* data port bit for TMS */
|
||||
u8 TCK_MASK; /* data port bit for TCK */
|
||||
u8 TDI_MASK; /* data port bit for TDI */
|
||||
u8 SRST_MASK; /* data port bit for SRST */
|
||||
u8 OUTPUT_INVERT; /* data port bits that should be inverted */
|
||||
u8 INPUT_INVERT; /* status port that should be inverted */
|
||||
u8 PORT_INIT; /* initialize data port with this value */
|
||||
} cable_t;
|
||||
|
||||
cable_t cables[] =
|
||||
{
|
||||
/* name tdo trst tms tck tdi srst o_inv i_inv init */
|
||||
{ "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80 },
|
||||
{ "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80 },
|
||||
{ "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
|
||||
{ "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10 },
|
||||
{ "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
|
||||
{ NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
/* configuration */
|
||||
char* parport_cable;
|
||||
unsigned long parport_port;
|
||||
|
||||
/* interface variables
|
||||
*/
|
||||
static cable_t* cable;
|
||||
static u8 dataport_value = 0x0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
static int device_handle;
|
||||
#else
|
||||
static unsigned long dataport;
|
||||
static unsigned long statusport;
|
||||
#endif
|
||||
|
||||
/* low level command set
|
||||
*/
|
||||
int parport_read(void);
|
||||
void parport_write(int tck, int tms, int tdi);
|
||||
void parport_reset(int trst, int srst);
|
||||
|
||||
int parport_speed(int speed);
|
||||
int parport_register_commands(struct command_context_s *cmd_ctx);
|
||||
int parport_init(void);
|
||||
int parport_quit(void);
|
||||
|
||||
/* interface commands */
|
||||
int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
|
||||
|
||||
jtag_interface_t parport_interface =
|
||||
{
|
||||
.name = "parport",
|
||||
|
||||
.execute_queue = bitbang_execute_queue,
|
||||
|
||||
.support_statemove = 0,
|
||||
|
||||
.speed = parport_speed,
|
||||
.register_commands = parport_register_commands,
|
||||
.init = parport_init,
|
||||
.quit = parport_quit,
|
||||
};
|
||||
|
||||
bitbang_interface_t parport_bitbang =
|
||||
{
|
||||
.read = parport_read,
|
||||
.write = parport_write,
|
||||
.reset = parport_reset
|
||||
};
|
||||
|
||||
int parport_read(void)
|
||||
{
|
||||
int data = 0;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPRSTATUS, & data);
|
||||
#else
|
||||
data = inb(statusport);
|
||||
#endif
|
||||
|
||||
if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void parport_write(int tck, int tms, int tdi)
|
||||
{
|
||||
u8 output;
|
||||
int i = jtag_speed + 1;
|
||||
|
||||
if (tck)
|
||||
dataport_value |= cable->TCK_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TCK_MASK;
|
||||
|
||||
if (tms)
|
||||
dataport_value |= cable->TMS_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TMS_MASK;
|
||||
|
||||
if (tdi)
|
||||
dataport_value |= cable->TDI_MASK;
|
||||
else
|
||||
dataport_value &= ~cable->TDI_MASK;
|
||||
|
||||
output = dataport_value ^ cable->OUTPUT_INVERT;
|
||||
|
||||
while (i-- > 0)
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPWDATA, &output);
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
outb(dataport, output);
|
||||
#else
|
||||
outb(output, dataport);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* (1) assert or (0) deassert reset lines */
|
||||
void parport_reset(int trst, int srst)
|
||||
{
|
||||
u8 output;
|
||||
DEBUG("trst: %i, srst: %i", trst, srst);
|
||||
|
||||
if (trst == 0)
|
||||
dataport_value |= cable->TRST_MASK;
|
||||
else if (trst == 1)
|
||||
dataport_value &= ~cable->TRST_MASK;
|
||||
|
||||
if (srst == 0)
|
||||
dataport_value |= cable->SRST_MASK;
|
||||
else if (srst == 1)
|
||||
dataport_value &= ~cable->SRST_MASK;
|
||||
|
||||
output = dataport_value ^ cable->OUTPUT_INVERT;
|
||||
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
ioctl(device_handle, PPWDATA, &output);
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
outb(dataport, output);
|
||||
#else
|
||||
outb(output, dataport);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int parport_speed(int speed)
|
||||
{
|
||||
jtag_speed = speed;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int parport_register_commands(struct command_context_s *cmd_ctx)
|
||||
{
|
||||
register_command(cmd_ctx, NULL, "parport_port", parport_handle_parport_port_command,
|
||||
COMMAND_CONFIG, NULL);
|
||||
register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
|
||||
COMMAND_CONFIG, NULL);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int parport_init(void)
|
||||
{
|
||||
cable_t *cur_cable;
|
||||
#if PARPORT_USE_PPDEV == 1
|
||||
char buffer[256];
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
cur_cable = cables;
|
||||
|
||||
if ((parport_cable == NULL) || (parport_cable[0] == 0))
|
||||
{
|
||||
parport_cable = "wiggler";
|
||||
WARNING("No parport cable specified, using default 'wiggler'");
|
||||
}
|
||||
|
||||
while (cur_cable->name)
|
||||
{
|
||||
if (strcmp(cur_cable->name, parport_cable) == 0)
|
||||
{
|
||||
cable = cur_cable;
|
||||
break;
|
||||
}
|
||||
cur_cable++;
|
||||
}
|
||||
|
||||
if (!cable)
|
||||
{
|
||||
ERROR("No matching cable found for %s", parport_cable);
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
dataport_value = cable->PORT_INIT;
|
||||
|
||||
#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", parport_port);
|
||||
device_handle = open(buffer, O_WRONLY);
|
||||
|
||||
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 = PARPORT_MODE_COMPAT;
|
||||
i= ioctl(device_handle, PPSETMODE, & i);
|
||||
if (i<0)
|
||||
{
|
||||
ERROR(" cannot set compatible mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
|
||||
i = IEEE1284_MODE_COMPAT;
|
||||
i = ioctl(device_handle, PPNEGOT, & i);
|
||||
if (i<0)
|
||||
{
|
||||
ERROR("cannot set compatible 1284 mode to device");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
#else
|
||||
if (parport_port == 0)
|
||||
{
|
||||
parport_port = 0x378;
|
||||
WARNING("No parport port specified, using default '0x378' (LPT1)");
|
||||
}
|
||||
|
||||
dataport = parport_port;
|
||||
statusport = parport_port + 1;
|
||||
|
||||
if (ioperm(dataport, 3, 1) != 0) {
|
||||
ERROR("missing privileges for direct i/o");
|
||||
return ERROR_JTAG_INIT_FAILED;
|
||||
}
|
||||
#endif
|
||||
|
||||
parport_reset(0, 0);
|
||||
parport_write(0, 0, 0);
|
||||
|
||||
bitbang_interface = &parport_bitbang;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int parport_quit(void)
|
||||
{
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int parport_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 (parport_port == 0)
|
||||
parport_port = strtoul(args[0], NULL, 0);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
|
||||
{
|
||||
if (argc == 0)
|
||||
return ERROR_OK;
|
||||
|
||||
/* only if the cable name wasn't overwritten by cmdline */
|
||||
if (parport_cable == 0)
|
||||
{
|
||||
parport_cable = malloc(strlen(args[0]) + sizeof(char));
|
||||
strcpy(parport_cable, args[0]);
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "types.h"
|
||||
#include "jtag.h"
|
||||
#include "configuration.h"
|
||||
#include "interpreter.h"
|
||||
#include "xsvf.h"
|
||||
#include "target.h"
|
||||
#include "flash.h"
|
||||
|