Compare commits

..

3 Commits

Author SHA1 Message Date
David Brownell
371530224c Version 0.3.1
Remove "-dev" tag

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
2009-11-12 08:27:26 -08:00
David Brownell
c6ac97cf3b target: don't swap MMU/no-MMU work areas
Resolve serious bug inserted by the "target: require working
area for physical/virtual addresses to be specified" patch.
It forced use of (invalid) virtual addresses when the MMU
was disabled, and vice versa.

Observed to break at least Cortex-M3, ARM926, ARM7TDMI whenever
work areas are used, such as during bulk writes to flash, DDR2,
SRAM, and so on.

Also, fix overlong lines and whitespace goofs.

[ Backport from mainline a9abfa7d06 ]

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
2009-11-06 15:10:26 -08:00
David Brownell
7de1c892cd Start v0.3.1 bugfix branch
Add "-dev" tag, increment micro version.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
2009-11-06 15:05:03 -08:00
731 changed files with 66132 additions and 91345 deletions

27
.gitignore vendored
View File

@@ -4,31 +4,14 @@
.libs
.deps
*.o
*.o.??????
*.a
*.lo
*.la
*.in
# generated source files
src/jtag/minidriver_imp.h
src/jtag/jtag_minidriver.h
# OpenULINK driver files generated by SDCC
src/jtag/drivers/OpenULINK/*.rel
src/jtag/drivers/OpenULINK/*.asm
src/jtag/drivers/OpenULINK/*.lst
src/jtag/drivers/OpenULINK/*.sym
src/jtag/drivers/OpenULINK/*.map
src/jtag/drivers/OpenULINK/*.mem
src/jtag/drivers/OpenULINK/*.lnk
src/jtag/drivers/OpenULINK/*.ihx
src/jtag/drivers/OpenULINK/*.rst
# editor files
*.swp
src/startup.tcl
startup_tcl.c
xscale_debug.h
@@ -77,16 +60,6 @@ stamp-vti
INSTALL
NOTES
# coexist with quilt
patches
# Eclipse stuff
.project
.cproject
.settings
# Emacs temp files
*~
# CScope database files
*cscope.out

5
.gitmodules vendored
View File

@@ -1,6 +1,3 @@
[submodule "tools/git2cl"]
path = tools/git2cl
url = http://repo.or.cz/r/git2cl.git
[submodule "jimtcl"]
path = jimtcl
url = http://repo.or.cz/r/jimtcl.git
url = git://repo.or.cz/git2cl.git

16
BUGS
View File

@@ -1,4 +1,4 @@
// This file is part of the Doxygen Developer Manual
// This file is part of the Doyxgen Developer Manual
/** @page bugs Bug Reporting
Please report bugs by subscribing to the OpenOCD mailing list and
@@ -6,12 +6,6 @@ posting a message with your report:
openocd-development@lists.berlios.de
Also, please check the Trac bug database to see if a ticket for
the bug has already been opened. You might be asked to open
such a ticket, or to update an existing ticket with more data.
https://sourceforge.net/apps/trac/openocd/
To minimize work for OpenOCD developers, you should try to include
all of the information listed below. If you feel that some of the
items below are unnecessary for a clear bug report, you may leave
@@ -28,12 +22,12 @@ that may be important.
- If the report is for a regression:
- Include logs for both working and broken versions.
- Find the precise version that caused the regression by binary search.
You can use "git bisect" to expedite this binary search:
You can use "git bisect" to expedite this binary search:
http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html
If possible, please develop and attach a patch that helps to expose or
solve the reported problem. See the PATCHES.txt file for information
about that process.
solve the reported problem. See the PATCHES file for more information
for that process.
Attach all files directly to your posting. The mailing list knows to
transform attachments to links, but attachments must be less than 300KB
@@ -42,7 +36,7 @@ in total.
@section bugscrashdump Obtaining Crash Backtraces
If OpenOCD is crashing, there are two very effective things you can do to
improve your chances of getting help on the development mailing list.
improve your chances of getting help on the development mailing list.
Try to reproduce the problem using the dummy JTAG interface to allow other developers to replicate
your problem robustly and use GDB to get a trace:@par

View File

@@ -1 +1 @@
Retired in favor of git log.
Retired in favour of SVN log.

View File

@@ -38,7 +38,7 @@ PROJECT_NUMBER =
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
OUTPUT_DIRECTORY = doxygen
OUTPUT_DIRECTORY =
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
@@ -384,7 +384,7 @@ HIDE_SCOPE_NAMES = NO
# will put a list of the files that are included by a file in the documentation
# of that file.
SHOW_INCLUDE_FILES = NO
SHOW_INCLUDE_FILES = YES
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
# is inserted in the documentation for inline members.
@@ -403,7 +403,7 @@ SORT_MEMBER_DOCS = YES
# by member name. If set to NO (the default) the members will appear in
# declaration order.
SORT_BRIEF_DOCS = YES
SORT_BRIEF_DOCS = NO
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
# hierarchy of group names into alphabetical order. If set to NO (the default)
@@ -567,9 +567,9 @@ WARN_LOGFILE =
INPUT = @srcdir@/doc/manual \
@srcdir@/TODO \
@srcdir@/BUGS \
@srcdir@/PATCHES.txt \
@srcdir@/PATCHES \
@srcdir@/src \
@builddir@/config.h
@srcdir@/config.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -692,13 +692,13 @@ SOURCE_BROWSER = YES
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = NO
INLINE_SOURCES = YES
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
# fragments. Normal C and C++ comments will always remain visible.
STRIP_CODE_COMMENTS = YES
STRIP_CODE_COMMENTS = NO
# If the REFERENCED_BY_RELATION tag is set to YES
# then for each documented function all documented
@@ -764,13 +764,13 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
# generate HTML output.
GENERATE_HTML = @doxygen_as_html@
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
HTML_OUTPUT = html
HTML_OUTPUT = doxygen
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
@@ -981,7 +981,7 @@ FORMULA_FONTSIZE = 10
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
# generate Latex output.
GENERATE_LATEX = @doxygen_as_pdf@
GENERATE_LATEX = NO
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
@@ -992,7 +992,7 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked. If left blank `latex' will be used as the default command name.
LATEX_CMD_NAME = pdflatex
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
# generate index for LaTeX. If left blank `makeindex' will be used as the
@@ -1004,7 +1004,7 @@ MAKEINDEX_CMD_NAME = makeindex
# LaTeX documents. This may be useful for small projects and may help to
# save some trees in general.
COMPACT_LATEX = YES
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
@@ -1029,20 +1029,20 @@ LATEX_HEADER =
# contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = YES
PDF_HYPERLINKS = NO
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation.
USE_PDFLATEX = YES
USE_PDFLATEX = NO
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep
# running if errors occur, instead of asking the user for help.
# This option is also used when generating formulas in HTML.
LATEX_BATCHMODE = YES
LATEX_BATCHMODE = NO
# If LATEX_HIDE_INDICES is set to YES then doxygen will not
# include the index chapters (such as File Index, Compound Index, etc.)

56
HACKING
View File

@@ -1,56 +0,0 @@
Submitting patches to the OpenOCD mailing list:
By the time you have read this, one supposes that
you have figured out how to clone the OpenOCD git
repository.
Below is a basic workflow and specific instructions
to get you going with git and patches.
0. Clone the git repository, rather than just
download the source.
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
or if you have problems with the "git:" protocol, use
the slower http protocol:
git clone http://repo.or.cz/r/openocd.git
1. Set up git with your name and email:
git config --global user.name "John Smith"
git config --global user.email "john@smith.org"
2. Work on your patches. Split the work into
multiple small patches that can be reviewed and
applied seperately and safely to the OpenOCD
repository.
while(!done) {
work - edit files using your favorite editor.
run "git commit -a" to commit all changes.
}
TIP! use "git add ." before commit to add new files.
--- example comment, notice the short first line w/topic ---
topic: short comment
<blank line>
longer comments over several
lines...
-----
3. Next you need to make sure that your patches
are on top of the latest stuff on the server and
that there are no conflicts.
git pull --rebase
4. Generate the patch files. This will generate
patches for all commits that are on top of
the latest stuff on the server:
git format-patch origin/master
5. Email the patches to openocd-development@lists.berlios.de

View File

@@ -2,9 +2,6 @@
# have all needed files, that a GNU package needs
AUTOMAKE_OPTIONS = gnu 1.6
# make sure we pass the correct jimtcl flags to distcheck
DISTCHECK_CONFIGURE_FLAGS = --with-jim-ext=nvp --disable-lineedit
nobase_dist_pkgdata_DATA = \
contrib/libdcc/dcc_stdio.c \
contrib/libdcc/dcc_stdio.h \
@@ -12,23 +9,11 @@ nobase_dist_pkgdata_DATA = \
contrib/libdcc/README \
contrib/openocd.udev
if INTERNAL_JIMTCL
SUBDIRS = jimtcl
else
SUBDIRS =
endif
SUBDIRS += src doc
SUBDIRS = src doc
EXTRA_DIST = \
BUGS \
HACKING \
NEWTAPS \
PATCHES.txt \
README.Win32 \
Doxyfile.in \
tools/logger.pl \
contrib/loaders
tools/logger.pl
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
@@ -40,27 +25,12 @@ Doxyfile: $(srcdir)/Doxyfile.in
@( \
echo "### @@@ -= DO NOT EDIT THIS FILE =- @@@ ###" && \
echo "### @@@ Make changes to Doxyfile.in @@@ ###" && \
sed -e 's,@srcdir\@,$(srcdir),' \
-e 's,@builddir\@,$(builddir),' \
-e 's,@doxygen_as_html\@,$(doxygen_as_html),' \
-e 's,@doxygen_as_pdf\@,$(doxygen_as_pdf),' $< \
sed -e 's,@srcdir\@,$(srcdir),' $< \
) > $@
THE_MANUAL = doxygen/latex/refman.pdf
doxygen::
$(MAKE) Doxyfile
doxygen Doxyfile 2>&1 | perl $(srcdir)/tools/logger.pl > doxygen.log
@if [ -f doxygen/latex/refman.tex ]; then \
echo "Creating $(THE_MANUAL)..."; \
$(MAKE) $(THE_MANUAL); \
else \
echo "Skipping Doxygen PDF..."; \
fi
$(THE_MANUAL): %.pdf: %.tex
-cd $$(dirname $*) && pdflatex $$(basename $*)
-cd $$(dirname $*) && pdflatex $$(basename $*)
TCL_PATH = tcl
# command to find paths of script files, relative to TCL_PATH
@@ -84,10 +54,10 @@ install-data-hook:
uninstall-hook:
rm -rf $(DESTDIR)$(pkgdatadir)/scripts
distclean-local:
rm -rf Doxyfile doxygen
rm -f $(srcdir)/jimtcl/configure.gnu
DISTCLEANFILES = doxygen.log
MAINTAINERCLEANFILES = \

108
NEWS
View File

@@ -1,65 +1,74 @@
This file includes highlights of the changes made in the
OpenOCD 0.5.0 source archive release. See the repository
history for details about what changed, including bugfixes
and other issues not mentioned here.
This file should include highlights of the changes made in the
OpenOCD openocd-0.3.0 source archive release. See the repository
history for details about what changed, including bugfixes and
other issues not mentioned here.
JTAG Layer:
New driver for "Bus Pirate"
Rename various commands so they're not JTAG-specific
There are migration procedures for most of these, but you should
convert your scripts to the new names, since those procedures
will not be around forever.
jtag jinterface ... is now adapter_name
jtag_khz ... is now adapter_khz
jtag_nsrst_delay ... is now adapter_nsrst_delay
jtag_nsrst_assert_width ... is now adapter_nsrst_assert_width
Support Voipac VPACLink JTAG Adapter.
FT2232H (high speed USB) support doesn't need separate configuration
New FT2232H JTAG adapters: Amontec, Olimex, Signalyzer
New reset_config options for SRST gating the JTAG clock (or not)
TAP declaration no longer requires ircapture and mask attributes
Scan chain setup should be more robust, with better diagnostics
New TAP events:
"post-reset" for TAP-invariant setup code (TAPs not usable yet)
"setup" for use once TAPs are addressable (e.g. with ICEpick)
Overridable Tcl "init_reset" and "jtag_init" procedures
Simple "autoprobe" mechanism to help simplify server setup
Boundary Scan:
Transport framework core ... supporting future work for SWD, SPI, and other
non-JTAG ways to debug targets or program flash.
SVF bugfixes ... parsing fixes, better STATE switch conformance
XSVF bugfixes ... be more correct, handle Xilinx tool output
Target Layer:
ARM:
- basic semihosting support for ARMv7M.
- renamed "armv7m" command prefix as "arm"
MIPS:
- "ejtag_srst" variant removed. The same functionality is
obtained by using "reset_config none".
- added PIC32MX software reset support, this means srst is not
required to be connected anymore.
OTHER:
- preliminary AVR32 AP7000 support.
Warn on use of obsolete numeric target IDs
New commands for use with Cortex-M3 processors:
"cortex_m3 disassemble" ... Thumb2 disassembly (UAL format)
"cortex_m3 vector_catch" ... traps certain hardware faults
without tying up breakpoint resources
If you're willing to help debug it
VERY EARLY Cortex-A8 and ARMv7A support
Updated BeagleBoard.org hardware support
you may need to explicitly "reset" after connect-to-Beagle
New commands for use with XScale processors: "xscale vector_table"
ARM
bugfixes to single-stepping Thumb code
ETM: unavailable registers are not listed
ETB, ETM: report actual hardware status
ARM9
name change: "arm9 vector_catch" not "arm9tdmi vector_catch"
ARM11
single stepping support for i.MX31
bugfix for missing "arm11" prefix on "arm11 memwrite ..."
GDB support
gdb_attach command is gone
Flash Layer:
New "stellaris recover" command, implements the procedure
to recover locked devices (restoring non-volatile
state to the factory defaults, including erasing
the flash and its protection bits, and possibly
re-enabling hardware debugging).
PIC32MX now uses algorithm for flash programming, this
has increased the performance by approx 96%.
New 'pic32mx unlock' cmd to remove readout protection.
New STM32 Value Line Support.
New 'virtual' flash driver, used to associate other addresses
with a flash bank. See pic32mx.cfg for usage.
New iMX27 NAND flash controller driver.
The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips
New drivers:
lpc2900, for NXP LPC2900 chips (ARM968 based)
mx3_nand, for imx31
New "last" flag for NOR "flash erase_sector" and "flash protect"
The "nand erase N" command now erases all of bank N
Speed up davinci_nand by about 3x
Board, Target, and Interface Configuration Scripts:
Support IAR LPC1768 kickstart board (by Olimex)
Support Voipac PXA270/PXA270M module.
New $PARPORTADDR tcl variable used to change default
parallel port address used.
Remove lm3s811.cfg; use "stellaris.cfg" instead
Core Jim/TCL Scripting:
New "add_script_search_dir" command, behaviour is the same
as the "-s" cmd line option.
Amontec JTAGkey2 support
Cleanup and additions for the TI/Luminary Stellaris scripts
LPC1768 target (and flash) support
Keil MCB1700 eval board
Samsung s3c2450
Mini2440 board
Numeric TAP and Target identifiers now trigger warnings
PXA255 partially enumerates
Documentation:
Capture more debugging and setup advice
Notes on target source code changes that may help debugging
Build and Release:
Repository moved from SVN at Berlios to GIT at SourceForge
Clean builds on (32-bit) Cygwin
Clean builds on 64-bit MinGW
For more details about what has changed since the last release,
see the git repository history. With gitweb, you can browse that
@@ -70,5 +79,4 @@ For older NEWS, see the NEWS files associated with each release
For more information about contributing test reports, bug fixes, or new
features and device support, please read the new Developer Manual (or
the BUGS and PATCHES.txt files in the source archive).
the BUGS and PATCHES files in the source archive).

View File

@@ -9,7 +9,7 @@ must past stricter value checks, and many more error conditions have
been handled correctly. These efforts helped to make the 0.2.0 release
more stable and robust, though some changes may expose latent bugs in
your existing configuration scripts.
This release does not maintain backward compatibility in all respects,
so some target or configuration scripts may need to be updated. In some
cases, you may also see warnings; resolve those, because they indicate
@@ -20,7 +20,7 @@ The following areas of OpenOCD functionality changed in this release:
JTAG Layer:
- Improves modularity: core, TCL, driver commands, and interface have
been separated, encapsulated, and documented for developers. Mostly.
- Improves JTAG TAP transition tables:
- Improves JTAG TAP transition tables:
* Makes TAP paths variable length, rather than being fixed at 7 steps.
* Fixes problems with some targets that did not like longer paths.
- Improves JTAG driver/minidriver modularity and encapsulation.

View File

@@ -1,82 +0,0 @@
This file should include highlights of the changes made in the
OpenOCD openocd-0.3.0 source archive release. See the repository
history for details about what changed, including bugfixes and
other issues not mentioned here.
JTAG Layer:
FT2232H (high speed USB) support doesn't need separate configuration
New FT2232H JTAG adapters: Amontec, Olimex, Signalyzer
New reset_config options for SRST gating the JTAG clock (or not)
TAP declaration no longer requires ircapture and mask attributes
Scan chain setup should be more robust, with better diagnostics
New TAP events:
"post-reset" for TAP-invariant setup code (TAPs not usable yet)
"setup" for use once TAPs are addressable (e.g. with ICEpick)
Overridable Tcl "init_reset" and "jtag_init" procedures
Simple "autoprobe" mechanism to help simplify server setup
Boundary Scan:
SVF bugfixes ... parsing fixes, better STATE switch conformance
XSVF bugfixes ... be more correct, handle Xilinx tool output
Target Layer:
Warn on use of obsolete numeric target IDs
New commands for use with Cortex-M3 processors:
"cortex_m3 disassemble" ... Thumb2 disassembly (UAL format)
"cortex_m3 vector_catch" ... traps certain hardware faults
without tying up breakpoint resources
If you're willing to help debug it
VERY EARLY Cortex-A8 and ARMv7A support
Updated BeagleBoard.org hardware support
you may need to explicitly "reset" after connect-to-Beagle
New commands for use with XScale processors: "xscale vector_table"
ARM
bugfixes to single-stepping Thumb code
ETM: unavailable registers are not listed
ETB, ETM: report actual hardware status
ARM9
name change: "arm9 vector_catch" not "arm9tdmi vector_catch"
ARM11
single stepping support for i.MX31
bugfix for missing "arm11" prefix on "arm11 memwrite ..."
GDB support
gdb_attach command is gone
Flash Layer:
The lpc2000 driver handles the new NXP LPC1700 (Cortex-M3) chips
New drivers:
lpc2900, for NXP LPC2900 chips (ARM968 based)
mx3_nand, for imx31
New "last" flag for NOR "flash erase_sector" and "flash protect"
The "nand erase N" command now erases all of bank N
Speed up davinci_nand by about 3x
Board, Target, and Interface Configuration Scripts:
Amontec JTAGkey2 support
Cleanup and additions for the TI/Luminary Stellaris scripts
LPC1768 target (and flash) support
Keil MCB1700 eval board
Samsung s3c2450
Mini2440 board
Numeric TAP and Target identifiers now trigger warnings
PXA255 partially enumerates
Documentation:
Capture more debugging and setup advice
Notes on target source code changes that may help debugging
Build and Release:
Repository moved from SVN at Berlios to GIT at SourceForge
Clean builds on (32-bit) Cygwin
Clean builds on 64-bit MinGW
For more details about what has changed since the last release,
see the git repository history. With gitweb, you can browse that
in various levels of detail.
For older NEWS, see the NEWS files associated with each release
(i.e. NEWS-<version>).
For more information about contributing test reports, bug fixes, or new
features and device support, please read the new Developer Manual (or
the BUGS and PATCHES files in the source archive).

View File

@@ -1,98 +0,0 @@
This file includes highlights of the changes made in the
OpenOCD 0.4.0 source archive release. See the repository
history for details about what changed, including bugfixes
and other issues not mentioned here.
JTAG Layer:
Support KT-Link JTAG adapter.
Support USB-JTAG, Altera USB-Blaster and compatibles.
Boundary Scan:
Target Layer:
General
- Removed commands which have been obsolete for at least
a year (from both documentation and, sometimes, code).
- new "reset-assert" event, for systems without SRST
ARM
- supports "reset-assert" event (except on Cortex-M3)
- renamed "armv4_5" command prefix as "arm"
- recognize TrustZone "Secure Monitor" mode
- "arm regs" command output changed
- register names use "sp" not "r13"
- add top-level "mcr" and "mrc" commands, replacing
various core-specific operations
- basic semihosting support (ARM7/ARM9 only, for now)
ARM11
- Should act much more like other ARM cores:
* Preliminary ETM and ETB hookup
* accelerated "flash erase_check"
* accelerated GDB memory checksum
* support "arm regs" command
* can access all core modes and registers
* watchpoint support
- Shares some core debug code with Cortex-A8
Cortex-A8
- Should act much more like other ARM cores:
* support "arm regs" command
* can access all core modes and registers
* watchpoint support
- Shares some core debug code with ARM11
Cortex-M3
- Exposed DWT registers like cycle counter
- vector_catch settings not clobbered by resets
- no longer interferes with firmware's fault handling
ETM, ETB
- "trigger_percent" command moved ETM --> ETB
- "etm trigger_debug" command added
MIPS
- use fastdata writes
Freescale DSP563xx cores (partial support)
Flash Layer:
'flash bank' and 'nand device' take <bank_name> as first argument.
With this, flash/NAND commands allow referencing banks by name:
- <bank_name>: reference the bank with its defined name
- <driver_name>[.N]: reference the driver's Nth bank
New 'nand verify' command to check bank against an image file.
The "flash erase_address" command now rejects partial sectors;
previously it would silently erase extra data. If you
want to erase the rest of the first and/or last sectors
instead of failing, you must pass an explicit "pad" flag.
New at91sam9 NAND controller driver.
New s3c64xx NAND controller driver.
Board, Target, and Interface Configuration Scripts:
ARM9
- ETM and ETB hookup for iMX2* targets
Add $HOME/.openocd to the search path.
Handle Rev C of LM3S811 eval boards.
- use "luminary-lm3s811.cfg" for older boards
- use "luminary.cfg" for RevC and newer
Core Jim/TCL Scripting:
New 'usage' command to provide terse command help.
Improved command 'help' command output (sorted and indented).
Improved command handling:
- Most boolean settings now accept any of the following:
on/off, enable/disable, true/false, yes/no, 1/0
- More error checking and reporting.
Documentation:
New built-in command development documentation and primer.
Build and Release:
Use --enable-doxygen-pdf to build PDF developer documentation.
Consider upgrading to libftdi 0.17 if you use that library; it
includes bugfixes which improve FT2232H support.
For more details about what has changed since the last release,
see the git repository history. With gitweb, you can browse that
in various levels of detail.
For older NEWS, see the NEWS files associated with each release
(i.e. NEWS-<version>).
For more information about contributing test reports, bug fixes, or new
features and device support, please read the new Developer Manual (or
the BUGS and PATCHES.txt files in the source archive).

20
NEWTAPS
View File

@@ -30,7 +30,7 @@ Version Number Changes:
not a big deal. Please do report this information. We'd like to
know about it.
For example
For example
Error: ERROR: Tap: s3c4510.cpu - Expected id: 0x3f0f0f0f, Got: 0x1f0f0f0f
Error: ERROR: expected: mfg: 0x787, part: 0xf0f0, ver: 0x3
@@ -39,7 +39,7 @@ Error: ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x1
========================================
Updating the Tap ID number your self
Why do this? You just want the warning to go away. And don't want
to update your version/instance of OpenOCD.
@@ -79,11 +79,11 @@ Examples:
0x3f0f0f0f - is a newer ARM7TDMI
0x3ba00477 - is an ARM cortex M3
Some chips have multiple JTAG taps - be sure to list
Some chips have multiple JTAG taps - be sure to list
each one individually - ORDER is important!
========================================
B) The maker of the part
B) The maker of the part
Examples:
Xilinx, Atmel, ST Micro Systems, Freescale
@@ -94,7 +94,7 @@ C) The family of parts it belongs to
Examples:
"NXP LPC Series"
"Atmel SAM7 Series"
========================================
D) The actual part number on the package
@@ -121,7 +121,7 @@ For example: A consumer GPS unit or a cellphone
ie: Olimex, LogicPD, Freescale(eval board)
========================================
(G) Identifying information on the board.
Not good: "iar red ST eval board"
@@ -135,11 +135,3 @@ For example: A consumer GPS unit or a cellphone
ie: An FPGA or CPLD ...
========================================
(I) What target config files need updating?
In fact it's best if you submit a patch with those
updates. Most of the other information listed here
is just to help create a good patch.
========================================

View File

@@ -1,4 +1,4 @@
// This file is part of the Doxygen Developer Manual
// This file is part of the Doyxgen Developer Manual
/** @page patchguide Patch Guidelines
Please mail patches to: @par
@@ -32,7 +32,7 @@ in response to feedback.
Add yourself to the GPL copyright for non-trivial changes.
To create a patch from the command line:
@code
@code
git diff >mypatch.txt
@endcode

17
README
View File

@@ -64,8 +64,8 @@ you can build the in-tree documentation.
Installing OpenOCD
==================
On Linux, you may have permissions problems to address. The best way
to do this is to use the contrib/openocd.udev rules file. It probably
On Linux, you may have permissions problems to address. The best
way to do this is to use the contrib/udev.rules file. It probably
belongs somewhere in /etc/udev/rules.d, but consult your operating
system documentation to be sure. In particular, make sure that it
matches the syntax used by your operating system's version of udev.
@@ -236,8 +236,6 @@ options may be available there:
Programmer
--enable-rlink Enable building support for the Raisonance RLink
JTAG Programmer
--enable-ulink Enable building support for the Keil ULINK JTAG
Programmer
--enable-usbprog Enable building support for the usbprog JTAG
Programmer
--enable-vsllink Enable building support for the Versaloon-Link JTAG
@@ -257,9 +255,8 @@ options may be available there:
--enable-ioutil Enable ioutil functions - useful for standalone
OpenOCD implementations
--disable-doxygen-html Disable building Doxygen manual as HTML.
--enable-doxygen-pdf Enable building Doxygen manual as PDF.
--enable-httpd Enable builtin httpd server - useful for standalone
OpenOCD implementations
Miscellaneous Configure Options
-------------------------------
@@ -317,7 +314,7 @@ The libftdi source code can be download from the following website:
For both Linux and Windows, both libusb and libftdi must be built and
installed. To use the newer FT2232H chips, supporting RTCK and USB high
speed (480 Mbps), use libftdi version 0.17 or newer. Many Linux
speed (480 Mbps), you need libftdi version 0.16 or newer. Many Linux
distributions provide suitable packages for these libraries.
For Windows, libftdi is supported with versions 0.14 and later.
@@ -338,7 +335,7 @@ all operating systems used with OpenOCD. You may, however, build such
copies for personal use.
The FTDICHIP drivers come as either a (win32) ZIP file, or a (Linux)
TAR.GZ file. You must unpack them ``some where'' convenient. As of this
TAR.GZ file. You must unpack them ``some where'' convient. As of this
writing FTDICHIP does not supply means to install these files "in an
appropriate place."
@@ -404,7 +401,7 @@ Then you can update that at your convenience using
git pull
There is also a gitweb interface, which you can use either to browse
the repository or to download arbitrary snapshots using HTTP:
the repository or to downlad arbitrary snapshots using HTTP:
http://openocd.git.sourceforge.net/git/gitweb.cgi?p=openocd/openocd
http://repo.or.cz/w/openocd.git

View File

@@ -27,8 +27,8 @@ based JTAG debuggers.
http://sourceforge.net/projects/libusb-win32/
You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz
package. Extract this file into a temp directory.
You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz
package. Extract this file into a temp directory.
Copy the file libusb-win32-device-bin-0.1.12.2\include\usb.h
to your MinGW include directory.
@@ -59,10 +59,10 @@ released source tarball or the git tree.
If you are using the git tree, the following are the instructions from
README.mingw. You will need to have the cmake utility installed.
- Edit Toolchain-mingw32.cmake to point to the correct MinGW
- Edit Toolchain-mingw32.cmake to point to the correct MinGW
installation.
- Create a build directory like "mkdir build-win32", e.g in ../libftdi/
- cd into that directory and run
- cd into that directory and run
"cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-mingw32.cmake .."
- Copy src/ftdi.h to your MinGW include directory.
- Copy build-win32/src/*.a to your MinGW lib directory.

78
TODO
View File

@@ -1,4 +1,4 @@
// This file is part of the Doxygen Developer Manual
// This file is part of the Doyxgen Developer Manual
/** @page tasks Pending and Open Tasks
This page lists pending and open tasks being considered or worked upon
@@ -27,8 +27,8 @@ This section provides possible things to improve with OpenOCD's TCL support.
parameters. Currently variables assigned through one such parameter
command/script are unset before the next one is invoked.
- Isolate all TCL command support:
- Pure C CLI implementations using --disable-builtin-tcl.
- Isolate all TCL command support:
- Pure C CLI implementations using --disable-builtin-tcl.
- Allow developers to build new dongles using OpenOCD's JTAG core.
- At first, provide only low-level JTAG support; target layer and
above rely heavily on scripting event mechanisms.
@@ -46,7 +46,7 @@ This section list issues that need to be resolved in the JTAG layer.
The following tasks have been suggested for cleaning up the JTAG layer:
- use tap_set_state everywhere to allow logging TAP state transitions
- Encapsulate cmd_queue_cur_state and related variable handling.
- Encapsulate cmd_queue_cur_state and related varaible handling.
- add slick 32 bit versions of jtag_add_xxx_scan() that avoids
buf_set_u32() calls and other evidence of poor impedance match between
API and calling code. New API should cut down # of lines in calling
@@ -85,7 +85,7 @@ There are some known bugs to fix in JTAG adapter drivers:
Workaround: use "tms_sequence long" @par
https://lists.berlios.de/pipermail/openocd-development/2009-July/009426.html
The following tasks have been suggested for improving OpenOCD's JTAG
The following tasks have been suggeted for improving OpenOCD's JTAG
interface support:
- rework USB communication to be more robust. Two possible options are:
@@ -112,7 +112,7 @@ TCP/IP packets handled by the server.
@section thelistswd Serial Wire Debug
- implement Serial Wire Debug interface
- implement Serial Wire Debug interface
@section thelistbs Boundary Scan Support
@@ -142,14 +142,6 @@ Once the above are completed:
https://lists.berlios.de/pipermail/openocd-development/2009-May/006590.html
- regression: "reset halt" between 729(works) and 788(fails): @par
https://lists.berlios.de/pipermail/openocd-development/2009-July/009206.html
- registers
- add flush-value operation, call them all on resume/reset
- mcr/mrc target->type support
- missing from ARM920t, ARM966e, XScale.
It's possible that the current syntax is unable to support read-modify-write
operations(see arm966e).
- mcr/mrc - retire cp15 commands when there the mrc/mrc commands have been
tested from: arm926ejs, arm720t, cortex_a8
- ARM7/9:
- clean up "arm9tdmi vector_catch". Available for some arm7 cores? @par
https://lists.berlios.de/pipermail/openocd-development/2009-October/011488.html
@@ -165,25 +157,18 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
use hardware stepping if available.
- mdb can return garbage data if read byte operation fails for
a memory region(16 & 32 byte access modes may be supported). Is this
a bug in the .MX31 PDK init script? Try on i.MX31 PDK:
a bug in the .MX31 PDK init script? Try on i.MX31 PDK:
mdw 0xb80005f0 0x8, mdh 0xb80005f0 0x10, mdb 0xb80005f0 0x20. mdb returns
garabage.
- implement missing functionality (grep FNC_INFO_NOTIMPLEMENTED ...)
- Thumb2 single stepping: ARM1156T2 needs simulator support
- thumb support is missing: ISTR ARMv6 requires Thumb.
ARM1156 has Thumb2; ARM1136 doesn't.
- Cortex A8 support (ML)
- add target implementation (ML)
- Cortex M3 support
- when stepping, only write dirtied registers (be faster)
- when connecting to halted core, fetch registers (startup is quirky)
- Generic ARM run_algorithm() interface
- tagged struct wrapping ARM instructions and metadata
- not revision-specific (current: ARMv4+ARMv5 -or- ARMv6 -or- ARMv7)
- usable with at least arm_nandwrite() and generic CFI drivers
- ETM
- don't show FIFOFULL registers if they're not supported
- use comparators to get more breakpoints and watchpoints
- add "etm drivers" command
- trace driver init() via examine() paths only, not setup()/reset
- MC1322x support (JW/DE?)
- integrate and test support from JW (and DE?)
- get working with a known good interface (i.e. not today's jlink)
@@ -207,8 +192,8 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
@section thelistsvf SVF/XSVF
- develop SVF unit tests
- develop XSVF unit tests
- develop SVF unit tests
- develop XSVF unit tests
@section thelistflash Flash Support
@@ -219,16 +204,6 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
- ocl
- str9xpec
- Don't expect writing all-ones to be a safe way to write without
changing bit values. Minimally it loses on flash modules with
internal ECC, where it may change the ECC.
- NOR flash_write_unlock() does that between sectors
- there may be other cases too
- Make sure all commands accept either a bank name or a bank number,
and be sure both identifiers show up in "flash banks" and "nand list".
Right now the user-friendly names are pretty much hidden...
@subsection thelistflashcfi CFI
- finish implementing bus width/chip width handling (suggested by NC)
@@ -310,11 +285,11 @@ These ideas were first introduced here: @par
- automatically detect the features that are available, unless
options were specifically provided to configure
- provide a report of the drivers that will be build at the end of
running configure, so the users can verify which drivers will be
running configure, so the users can verify which driverswill be
built during 'make' (and their options) .
- eliminate sources of confusion in @c bootstrap script:
-# Make @c bootstrap call 'configure --enable-maintainer-mode \<opts\>'?
-# Add @c buildstrap script to assist with bootstrap and configure steps.
-# Add @c buildstrap script to assist with boostrap and configure steps.
- automatically build tool-chains required for cross-compiling
- produce mingw32, arm-elf, others using in-tree scripts
- build all required target code from sources
@@ -325,30 +300,13 @@ These ideas were first introduced here: @par
The following architectural tasks need to be accomplished and should be
fairly easy to complete:
- use dynamic allocations for working memory. Scan & fix code
for excessive stack allocations. take linux/scripts/checkstack.pl and
see what the worst offenders are. Dynamic stack allocations are found
at the bottom of the list below. Example, on amd64:
$ objdump -d | checkstack.pl | head -10
0x004311e3 image_open [openocd]: 13464
0x00431301 image_open [openocd]: 13464
0x004237a4 target_array2mem [openocd]: 4376
0x0042382b target_array2mem [openocd]: 4376
0x00423e74 target_mem2array [openocd]: 4360
0x00423ef9 target_mem2array [openocd]: 4360
0x00404aed handle_svf_command [openocd]: 2248
0x00404b7e handle_svf_command [openocd]: 2248
0x00413581 handle_flash_fill_command [openocd]: 2200
0x004135fa handle_flash_fill_command [openocd]: 2200
- clean-up code to match style guides
- factor code to eliminate duplicated functionality
- rewrite code that uses casts to access 16-bit and larger types
from unaligned memory addresses
- libopenocd support: @par
https://lists.berlios.de/pipermail/openocd-development/2009-May/006405.html
- review and clean up interface/target/flash APIs
- review and clean up interface/target/flash APIs
The following strategic tasks will require ambition, knowledge, and time
to complete:
@@ -366,11 +324,9 @@ to complete:
- Develop milestone and release guidelines, processes, and scripts.
- Develop "style" guidelines (and scripts) for maintainers:
- reviewing patches
- committing to git
- Review Users' Guide for documentation errors or omissions
- "capture" and "ocd_find" commands
- "ocd_" prefix on various stuff
- Update Developer's Manual (doxygen output)
- committing to Subversion
- Review The Guide for OpenOCD Users for documentation errors or omissions
- Update The Manual for OpenOCD Developerrs:
- Add documentation describing the architecture of each module
- Provide more Technical Primers to bootstrap contributor knowledge

View File

@@ -1,24 +1,13 @@
#!/bin/sh
#!/bin/sh -e
# Run the autotools bootstrap sequence to create the configure script
# Abort execution on error
set -e
if which libtoolize > /dev/null; then
libtoolize="libtoolize"
elif which glibtoolize >/dev/null; then
libtoolize="glibtoolize"
if libtoolize --version >/dev/null 2>&1; then
libtoolize="libtoolize"
elif glibtoolize --version >/dev/null 2>&1; then
libtoolize="glibtoolize"
else
echo "$0: Error: libtool is required" >&2
exit 1
fi
if [ "$1" = "nosubmodule" ]; then
SKIP_SUBMODULE=1
elif [ -n "$1" ]; then
echo "$0: Illegal argument $1"
echo "USAGE: $0 [nosubmodule]"
exit 1
echo "libtool is required" >&2
exit 1
fi
# bootstrap the autotools
@@ -34,14 +23,4 @@ automake --gnu --add-missing --copy
# AM_MAINTAINER_MODE requires --enable-maintainer-mode from everyone using
# current source snapshots (working from GIT, or some source snapshot, etc)
# otherwise the documentation will fail to build due to missing version.texi
if [ -n "$SKIP_SUBMODULE" ]; then
echo "Skipping submodule setup"
else
echo "Setting up submodules"
git submodule init
git submodule update
fi
echo "Bootstrap complete. Quick build instructions:"
echo "./configure --enable-maintainer-mode ...."
echo "Bootstrap complete; you can './configure --enable-maintainer-mode ....'"

View File

@@ -1,11 +0,0 @@
# common flags used in openocd build
AM_CPPFLAGS = -I$(top_srcdir)/src \
-I$(top_builddir)/src \
-DPKGDATADIR=\"$(pkgdatadir)\" \
-DPKGLIBDIR=\"$(pkglibdir)\"
if INTERNAL_JIMTCL
AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \
-I$(top_builddir)/jimtcl
endif

View File

@@ -1,27 +0,0 @@
dnl
dnl If needed, define the m4_ifblank and m4_ifnblank macros from autoconf 2.64
dnl This allows us to run with earlier Autoconfs as well.
ifdef([m4_ifblank],[],[
m4_define([m4_ifblank],
[m4_if(m4_translit([[$1]], [ ][ ][
]), [], [$2], [$3])])])
dnl
ifdef([m4_ifnblank],[],[
m4_define([m4_ifnblank],
[m4_if(m4_translit([[$1]], [ ][ ][
]), [], [$3], [$2])])])
dnl
dnl AC_CONFIG_SUBDIRS does not allow configure options to be passed
dnl to subdirs, this function allows that by creating a configure.gnu
dnl script that prepends configure options and then calls the real
dnl configure script
AC_DEFUN([AX_CONFIG_SUBDIR_OPTION],
[
AC_CONFIG_SUBDIRS([$1])
m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu],
[printf "#!/bin/sh
"\$"SHELL "../$srcdir/$1/configure" $2 \""\$"@"\" > "$srcdir/$1/configure.gnu"
])
])

View File

@@ -1,17 +1,15 @@
AC_PREREQ(2.60)
AC_INIT([openocd], [0.5.0-dev],
AC_INIT([openocd], [0.3.1],
[OpenOCD Mailing List <openocd-development@lists.berlios.de>])
AC_CONFIG_SRCDIR([src/openocd.c])
m4_include(config_subdir.m4)dnl
AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip])
AM_MAINTAINER_MODE
AM_CONFIG_HEADER(config.h)
AH_BOTTOM([
#include <helper/system.h>
#include <helper/replacements.h>
#include "system.h"
#include "replacements.h"
])
AC_LANG_C
@@ -279,24 +277,6 @@ AC_ARG_WITH(ftd2xx-lib,
with_ftd2xx_lib=static
])
AC_ARG_ENABLE(doxygen-html,
AS_HELP_STRING([--disable-doxygen-html],
[Disable building Doxygen manual as HTML.]),
[doxygen_as_html=$enableval], [doxygen_as_html=yes])
AC_SUBST(doxygen_as_html)
AC_MSG_CHECKING([whether to build Doxygen as HTML])
AC_MSG_RESULT($doxygen_as_html)
AC_ARG_ENABLE(doxygen-pdf,
AS_HELP_STRING([--enable-doxygen-pdf],
[Enable building Doxygen manual as PDF.]),
[doxygen_as_pdf=$enableval], [doxygen_as_pdf=no])
AC_SUBST(doxygen_as_pdf)
AC_MSG_CHECKING([whether to build Doxygen as PDF])
AC_MSG_RESULT($doxygen_as_pdf)
AC_ARG_ENABLE(gccwarnings,
AS_HELP_STRING([--disable-gccwarnings], [Disable compiler warnings]),
[gcc_warnings=$enableval], [gcc_warnings=yes])
@@ -394,14 +374,6 @@ AC_ARG_ENABLE(ft2232_ftd2xx,
AS_HELP_STRING([--enable-ft2232_ftd2xx], [Enable building support for FT2232 based devices using the FTD2XX driver from ftdichip.com]),
[build_ft2232_ftd2xx=$enableval], [build_ft2232_ftd2xx=no])
AC_ARG_ENABLE(usb_blaster_libftdi,
AS_HELP_STRING([--enable-usb_blaster_libftdi], [Enable building support for the Altera USB-Blaster using the libftdi driver, opensource alternate of FTD2XX]),
[build_usb_blaster_libftdi=$enableval], [build_usb_blaster_libftdi=no])
AC_ARG_ENABLE(usb_blaster_ftd2xx,
AS_HELP_STRING([--enable-usb_blaster_ftd2xx], [Enable building support for the Altera USB-Blaster using the FTD2XX driver from ftdichip.com]),
[build_usb_blaster_ftd2xx=$enableval], [build_usb_blaster_ftd2xx=no])
AC_ARG_ENABLE(amtjtagaccel,
AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]),
[build_amtjtagaccel=$enableval], [build_amtjtagaccel=no])
@@ -410,10 +382,6 @@ AC_ARG_ENABLE(ecosboard,
AS_HELP_STRING([--enable-ecosboard], [Enable building support for eCos based JTAG debugger]),
[build_ecosboard=$enableval], [build_ecosboard=no])
AC_ARG_ENABLE(zy1000_master,
AS_HELP_STRING([--enable-zy1000-master], [Use ZY1000 JTAG master registers]),
[build_zy1000_master=$enableval], [build_zy1000_master=no])
AC_ARG_ENABLE(zy1000,
AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]),
[build_zy1000=$enableval], [build_zy1000=no])
@@ -422,6 +390,10 @@ AC_ARG_ENABLE(ioutil,
AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]),
[build_ioutil=$enableval], [build_ioutil=no])
AC_ARG_ENABLE(httpd,
AS_HELP_STRING([--enable-httpd], [Enable builtin httpd server - useful for standalone OpenOCD implementations]),
[build_httpd=$enableval], [build_httpd=no])
case "${host_cpu}" in
arm*)
AC_ARG_ENABLE(ep93xx,
@@ -472,25 +444,14 @@ AC_ARG_ENABLE(rlink,
AS_HELP_STRING([--enable-rlink], [Enable building support for the Raisonance RLink JTAG Programmer]),
[build_rlink=$enableval], [build_rlink=no])
AC_ARG_ENABLE(ulink,
AS_HELP_STRING([--enable-ulink], [Enable building support for the Keil ULINK JTAG Programmer]),
[build_ulink=$enableval], [build_ulink=no])
AC_ARG_ENABLE(arm-jtag-ew,
AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]),
[build_armjtagew=$enableval], [build_armjtagew=no])
AC_ARG_ENABLE(buspirate,
AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]),
[build_buspirate=$enableval], [build_buspirate=no])
AC_ARG_ENABLE(minidriver_dummy,
AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]),
[build_minidriver_dummy=$enableval], [build_minidriver_dummy=no])
AC_ARG_ENABLE(internal-jimtcl,
AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]),
[use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes])
build_minidriver=no
AC_MSG_CHECKING([whether to enable ZY1000 minidriver])
@@ -542,7 +503,7 @@ case $host in
is_win32=yes
parport_use_ppdev=no
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[return __MINGW32__;]])],
AC_COMPILE_IFELSE(AC_LANG_PROGRAM([],[return __MINGW32__;]),
[is_mingw=yes],[is_mingw=no])
if test $is_mingw = yes; then
AC_DEFINE(IS_MINGW, 1, [1 if building for MinGW.])
@@ -572,7 +533,7 @@ case $host in
AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts])
fi
parport_use_giveio=yes
CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO"
AC_DEFINE(IS_MINGW, 1, [1 if building for MinGW.])
@@ -635,10 +596,16 @@ else
AC_DEFINE(BUILD_ZY1000, 0, [0 if you don't want ZY1000.])
fi
if test $build_zy1000_master = yes; then
AC_DEFINE(BUILD_ZY1000_MASTER, 1, [1 if you want ZY1000 JTAG master registers.])
if test $build_ioutil = yes; then
AC_DEFINE(BUILD_IOUTIL, 1, [1 if you want ioutils.])
else
AC_DEFINE(BUILD_ZY1000_MASTER, 0, [0 if you don't want ZY1000 JTAG master registers.])
AC_DEFINE(BUILD_IOUTIL, 0, [0 if you don't want ioutils.])
fi
if test $build_httpd = yes; then
AC_DEFINE(BUILD_HTTPD, 1, [1 if you want httpd.])
else
AC_DEFINE(BUILD_HTTPD, 0, [0 if you don't want httpd.])
fi
if test $build_at91rm9200 = yes; then
@@ -678,20 +645,6 @@ else
AC_DEFINE(BUILD_FT2232_FTD2XX, 0, [0 if you don't want ftd2xx ft2232.])
fi
if test $build_usb_blaster_libftdi = yes; then
build_bitbang=yes
AC_DEFINE(BUILD_USB_BLASTER_LIBFTDI, 1, [1 if you want libftdi usb_blaster.])
else
AC_DEFINE(BUILD_USB_BLASTER_LIBFTDI, 0, [0 if you don't want libftdi usb_blaster.])
fi
if test $build_usb_blaster_ftd2xx = yes; then
build_bitbang=yes
AC_DEFINE(BUILD_USB_BLASTER_FTD2XX, 1, [1 if you want ftd2xx usb_blaster.])
else
AC_DEFINE(BUILD_USB_BLASTER_FTD2XX, 0, [0 if you don't want ftd2xx usb_blaster.])
fi
if test $build_amtjtagaccel = yes; then
AC_DEFINE(BUILD_AMTJTAGACCEL, 1, [1 if you want the Amontec JTAG-Accelerator driver.])
else
@@ -754,32 +707,12 @@ else
AC_DEFINE(BUILD_RLINK, 0, [0 if you don't want the RLink JTAG driver.])
fi
if test $build_ulink = yes; then
AC_DEFINE(BUILD_ULINK, 1, [1 if you want the ULINK JTAG driver.])
else
AC_DEFINE(BUILD_ULINK, 0, [0 if you don't want the ULINK JTAG driver.])
fi
if test $build_armjtagew = yes; then
AC_DEFINE(BUILD_ARMJTAGEW, 1, [1 if you want the ARM-JTAG-EW JTAG driver.])
else
AC_DEFINE(BUILD_ARMJTAGEW, 0, [0 if you don't want the ARM-JTAG-EW JTAG driver.])
fi
if test $build_buspirate = yes; then
AC_DEFINE(BUILD_BUSPIRATE, 1, [1 if you want the Buspirate JTAG driver.])
else
AC_DEFINE(BUILD_BUSPIRATE, 0, [0 if you don't want the Buspirate JTAG driver.])
fi
if test "$use_internal_jimtcl" = yes; then
if test -f "$srcdir/jimtcl/configure.ac"; then
AX_CONFIG_SUBDIR_OPTION([jimtcl], [--with-jim-ext=nvp --disable-lineedit])
else
AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.])
fi
fi
#-- Deal with MingW/Cygwin FTD2XX issues
if test $is_win32 = yes; then
@@ -788,7 +721,7 @@ then
AC_MSG_ERROR([The option: with_ftd2xx_linux_tardir is for LINUX only.])
fi
if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then
if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes ; then
AC_MSG_CHECKING([for ftd2xx.lib exists (win32)])
# if we are given a zipdir...
@@ -803,12 +736,12 @@ if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_b
# And calculate the LDFLAGS for the machine
case "$host_cpu" in
i?86|x86_32)
i?86|x86_*)
LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/i386"
LIBS="$LIBS -lftd2xx"
f=$with_ftd2xx_win32_zipdir/i386/ftd2xx.lib
;;
amd64|x86_64)
amd64)
LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/amd64"
LIBS="$LIBS -lftd2xx"
f=$with_ftd2xx_win32_zipdir/amd64/ftd2xx.lib
@@ -928,17 +861,22 @@ _CFLAGS=`eval echo $CFLAGS`
LDFLAGS=$_LDFLAGS
CFLAGS=$_CFLAGS
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
AC_RUN_IFELSE([
#include "confdefs.h"
#if IS_WIN32
#include "windows.h"
#endif
#include <stdio.h>
#include <ftd2xx.h>
]], [[
int
main( int argc, char **argv )
{
DWORD x;
FT_GetLibraryVersion( &x );
]])], [
return 0;
}
], [
AC_MSG_RESULT([Success!])
], [
AC_MSG_ERROR([Cannot build & run test program using ftd2xx.lib])
@@ -947,16 +885,15 @@ AC_RUN_IFELSE([AC_LANG_PROGRAM([[
])
AC_MSG_CHECKING([for ftd2xx highspeed device support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_COMPILE_IFELSE([
#include "confdefs.h"
#if IS_WIN32
#include "windows.h"
#endif
#include <stdio.h>
#include <ftd2xx.h>
DWORD x = FT_DEVICE_4232H;
]], [])], [
], [
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
build_ft2232_highspeed=yes
@@ -988,10 +925,13 @@ if test $build_ft2232_libftdi = yes ; then
LDFLAGS=$_LDFLAGS
CFLAGS=$_CFLAGS
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
AC_RUN_IFELSE([
#include <stdio.h>
#include <ftdi.h>
]], [[
int
main( int argc, char **argv )
{
struct ftdi_context *p;
p = ftdi_new();
if( p != NULL ){
@@ -1000,7 +940,8 @@ if test $build_ft2232_libftdi = yes ; then
fprintf( stderr, "calling ftdi_new() failed\n");
return 1;
}
]])], [
}
], [
AC_MSG_RESULT([Success])
], [
AC_MSG_ERROR([Cannot build & run test program using libftdi])
@@ -1009,12 +950,11 @@ if test $build_ft2232_libftdi = yes ; then
])
AC_MSG_CHECKING([for libftdi highspeed device support])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_COMPILE_IFELSE([
#include <stdio.h>
#include <ftdi.h>
]], [[
enum ftdi_chip_type x = TYPE_2232H;
]])], [
], [
AC_DEFINE(BUILD_FT2232_HIGHSPEED, [1],
[Support FT2232H/FT4232HS with FTD2XX or libftdi.])
build_ft2232_highspeed=yes
@@ -1033,13 +973,11 @@ enum ftdi_chip_type x = TYPE_2232H;
fi
# check for usb.h when a driver will require it
build_usb=no
if test $build_jlink = yes -o $build_vsllink = yes -o $build_usbprog = yes -o \
$build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes
$build_rlink = yes -o $build_armjtagew = yes
then
AC_CHECK_HEADERS([usb.h],[],
[AC_MSG_ERROR([usb.h is required to build some OpenOCD driver(s)])])
build_usb=yes
fi
AM_CONDITIONAL(RELEASE, test $build_release = yes)
@@ -1049,14 +987,12 @@ AM_CONDITIONAL(GIVEIO, test x$parport_use_giveio = xyes)
AM_CONDITIONAL(EP93XX, test $build_ep93xx = yes)
AM_CONDITIONAL(ECOSBOARD, test $build_ecosboard = yes)
AM_CONDITIONAL(ZY1000, test $build_zy1000 = yes)
AM_CONDITIONAL(ZY1000_MASTER, test $build_zy1000_master = yes)
AM_CONDITIONAL(IOUTIL, test $build_ioutil = yes)
AM_CONDITIONAL(HTTPD, test $build_httpd = yes)
AM_CONDITIONAL(AT91RM9200, test $build_at91rm9200 = yes)
AM_CONDITIONAL(BITBANG, test $build_bitbang = yes)
AM_CONDITIONAL(FT2232_LIBFTDI, test $build_ft2232_libftdi = yes)
AM_CONDITIONAL(FT2232_DRIVER, test $build_ft2232_ftd2xx = yes -o $build_ft2232_libftdi = yes)
AM_CONDITIONAL(USB_BLASTER_LIBFTDI, test $build_usb_blaster_libftdi = yes)
AM_CONDITIONAL(USB_BLASTER_DRIVER, test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes)
AM_CONDITIONAL(AMTJTAGACCEL, test $build_amtjtagaccel = yes)
AM_CONDITIONAL(GW16012, test $build_gw16012 = yes)
AM_CONDITIONAL(PRESTO_LIBFTDI, test $build_presto_libftdi = yes)
@@ -1066,10 +1002,7 @@ AM_CONDITIONAL(OOCD_TRACE, test $build_oocd_trace = yes)
AM_CONDITIONAL(JLINK, test $build_jlink = yes)
AM_CONDITIONAL(VSLLINK, test $build_vsllink = yes)
AM_CONDITIONAL(RLINK, test $build_rlink = yes)
AM_CONDITIONAL(ULINK, test $build_ulink = yes)
AM_CONDITIONAL(ARMJTAGEW, test $build_armjtagew = yes)
AM_CONDITIONAL(BUSPIRATE, test $build_buspirate = yes)
AM_CONDITIONAL(USB, test $build_usb = yes)
AM_CONDITIONAL(IS_CYGWIN, test $is_cygwin = yes)
AM_CONDITIONAL(IS_MINGW, test $is_mingw = yes)
AM_CONDITIONAL(IS_WIN32, test $is_win32 = yes)
@@ -1079,16 +1012,14 @@ AM_CONDITIONAL(BITQ, test $build_bitq = yes)
AM_CONDITIONAL(MINIDRIVER, test $build_minidriver = yes)
AM_CONDITIONAL(MINIDRIVER_DUMMY, test $build_minidriver_dummy = yes)
AM_CONDITIONAL(INTERNAL_JIMTCL, test $use_internal_jimtcl = yes)
# Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h?
AC_MSG_CHECKING([for environ in unistd.h and stdlib.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_COMPILE_IFELSE([
#define _GNU_SOURCE
#include <unistd.h>
#include <stdlib.h>
]], [[char **ep = environ;]]
)], [
int main(int argc, char **argv) { char **ep = environ; }
], [
AC_MSG_RESULT([yes])
has_environ=yes
], [
@@ -1096,10 +1027,10 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
# Possibility #2: can environ be found in an available library?
AC_MSG_CHECKING([for extern environ])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
extern char **environ;
]], [[char **ep = environ;]]
)], [
AC_LINK_IFELSE([
extern char **environ;
int main(int argc, char **argv) { char **ep = environ; }
], [
AC_DEFINE(NEED_ENVIRON_EXTERN, [1], [Must declare 'environ' to use it.])
has_environ=yes
], [
@@ -1115,7 +1046,7 @@ fi
AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).])
# set default gcc warnings
GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow"
GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security"
if test "${gcc_wextra}" = yes; then
GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter"
GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast"
@@ -1177,16 +1108,11 @@ AC_OUTPUT(dnl
src/Makefile dnl
src/helper/Makefile dnl
src/jtag/Makefile dnl
src/jtag/drivers/Makefile dnl
src/transport/Makefile dnl
src/xsvf/Makefile dnl
src/svf/Makefile dnl
src/target/Makefile dnl
src/rtos/Makefile dnl
src/server/Makefile dnl
src/flash/Makefile dnl
src/flash/nor/Makefile dnl
src/flash/nand/Makefile dnl
src/pld/Makefile dnl
doc/Makefile dnl
)

View File

@@ -1,68 +0,0 @@
+OpenOCD and CoreSight Tracing
+
Many recent ARM chips (Using e..g. Cortex-M3 and
Cortex-M4 cores) support CoreSight debug/trace.
This note sketches an approach currently planned for those cores
with OpenOCD.
This tracing data can help debug and tune ARM software, but not
all cores support tracing. Some support more extensive tracing
other cores with trace support +should be able to use the same
approach and maybe some of the same analysis code.
+the Cortex-M3 is assumed here to be the
+core in use, for simplicity and to reflect current OpenOCD users.
This note summarizes a software model to generate, collect, and
analyze such trace data . That is not fully implemented as of early
January 2011, +and thus is not *yet* usable.
+
+
+Some microcontroller cores support a low pin-count Single-wire trace,
with a mode where +trace data is emitted (usually to a UART. To use
this mode, +SWD must be in use.
+At this writing, OpenOCD SWD support is not yet complete either.
(There are also multi-wire trace ports requiring more complex debug
adapters than OpenOCD currently supports, and offering richer data.
+
+
+* ENABLING involves activating SWD and (single wire) trace.
+
+current expectations are that OpenOCD itself will handle enabling;
activating single wire trace involves a debug adapter interaction, and
collecting that trace data requires particular (re)wiring.
+
+* CONFIGURATION involves setting up ITM and/or ETM modules to emit the
+desired data from the Cortex core. (This might include dumping
+event counters printf-style messages; code profiling; and more. Not all
+cores offer the same trace capabilities.
+
+current expectations are that Tcl scripts will be used to configure these
+modules for the desired tracing, by direct writes to registers. In some
+cases (as with RTOS event tracking and similar messaging, this might
+be augmented or replaced by user code running on the ARM core.
+
+COLLECTION involves reading that trace data, probably through UART, and
+saving it in a useful format to analyse For now, deferred analysis modes
are assumed, not than real-time or interactive ones.
+
+
+current expectations are to to dump data in text using contrib/itmdump.c
+or derived tools, and to post-process it into reports. Such reports might
+include program messaging (such as application data streams via ITM, maybe
+using printf type messaging; code coverage analysis or so forth. Recent
+versions of CMSIS software reserve some ITM codespace for RTOS event
tracing and include ITM messaging support.
Clearly some of that data would be valuable for interactive debugging.
+
+Should someone get ambitious, GUI reports should be possible. GNU tools
+for simpler reports like gprof may be simpler to support at first.
+In any case, OpenOCD is not currently GUI-oriented. Accordingly, we now
+expect any such graphics to come from postprocessing.
measurments for RTOS event timings should also be easy to collect.
+Examples include context and message switch times, as well as times
for application interactions.
+

View File

@@ -1,91 +0,0 @@
#!/usr/bin/perl
# Automatically generates the StellarisParts struct in src/flash/nor/stellaris.c
# Uses the header files from TI/Luminary's StellarisWare complete Firmware Development Package
# available from: http://www.luminarymicro.com/products/software_updates.html
$comment = "// Autogenerated by contrib/gen-stellaris-part-header.pl
// From Stellaris Firmware Development Package revision";
$struct_header = "static struct {
uint32_t partno;
const char *partname;
} StellarisParts[] =
{
";
$struct_footer = "\t{0,\"Unknown part\"}\n};\n";
$#ARGV == 1 || die "Usage: $0 <inc directory> <output file>\n";
-d $ARGV[0] || die $ARGV[0]." is not a directory\n";
$dir = $ARGV[0];
-f $ARGV[1] || die $ARGV[1]." is not a file\n";
$file = $ARGV[1];
print STDERR "Scanning $dir, Updating $file\n";
opendir(DIR, $dir) || die "can't open $dir: $!";
@files = readdir(DIR);
closedir(DIR);
@short_files = sort(grep(/lm3s...\.h/, @files));
@long_files = sort(grep(/lm3s....\.h/, @files));
$ver = 0;
$new_struct = $struct_header;
process_file(@short_files);
process_file(@long_files);
$new_struct .= $struct_footer;
$dump = "$comment $ver\n$new_struct";
{
local($/, *INPUT);
open(INPUT, $file) || die "can't open $file: $!";
$contents = <INPUT>;
close(INPUT);
}
$old_struct = qr/((^\/\/.*?\n)*)\Q$struct_header\E.*?$struct_footer/sm;
$contents =~ s/$old_struct/$dump/;
open(OUTPUT, ">$file") || die "can't open file $file for writing: $!";
print OUTPUT $contents;
close(OUTPUT);
sub process_file {
foreach $h_file (@_) {
($base) = ($h_file =~ m/lm3s(.{3,4})\.h/ig);
$base = uc($base);
local($/, *FILE);
open(FILE, "$dir/$h_file");
$content = <FILE>;
close(FILE);
$invalid = 0;
if ($content =~ /This is part of revision (\d+) of/) {
if ($ver != 0 and $ver != $1) {
print STDERR "File version mismatch: $ver != $1\n";
$ver = max($ver, $1);
} else {
$ver = $1;
}
}
if ($content =~ /SYSCTL_DID1_VER_[^M]\s+0x(\S+)/) {
$did1_ver = hex($1);
} else {
print STDERR "$h_file is missing SYSCTL_DID1_VER\n";
$did1_ver = 255;
$invalid = 1;
}
if ($content =~ /SYSCTL_DID1_PRTNO_$base\s+0x(\S+)/) {
$prtno = hex($1);
} else {
print STDERR "$h_file is missing SYSCTL_DID1_PRTNO\n";
$prtno = 0;
$invalid = 1;
}
$id = ($did1_ver | $prtno) >> 16;
$new_member = sprintf "{0x%04X,\"LM3S%s\"},", $id, $base;
if ($invalid == 1) {
#$new_struct .= "\t//$new_member\t// Invalid\n";
} else {
$new_struct .= "\t$new_member\n";
}
}
}

View File

@@ -1,441 +0,0 @@
/*
* Copyright (C) 2010 by David Brownell
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
/*
* Simple utility to parse and dump ARM Cortex-M3 SWO trace output. Once the
* mechanisms work right, this information can be used for various purposes
* including profiling (particularly easy for flat PC-sample profiles) and
* for debugging.
*
* SWO is the Single Wire Output found on some ARM cores, most notably on the
* Cortex-M3. It combines data from several sources:
*
* - Software trace (ITM): so-called "printf-style" application messaging
* using "ITM stimulus ports"; and differential timestamps.
* - Hardware trace (DWT): for profiling counters and comparator matches.
* - TPIU may issue sync packets.
*
* The trace data format is defined in Appendix E, "Debug ITM and DWT packet
* protocol", of the ARMv7-M Architecture Reference Manual (DDI 0403C). It
* is a superset of the ITM data format from the Coresight TRM.
*
* The trace data has two encodings. The working assumption is that data
* gets into this program using the UART encoding.
*/
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
/* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
* on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
* WWXX: event code (0..3 pre-assigned, 4..15 reserved)
* YY: task priority
* ZZ: task number
*
* NOTE that this specific encoding could be space-optimized; and that
* trace data streams could also be history-sensitive.
*/
static void show_task(int port, unsigned data)
{
unsigned code = data >> 16;
char buf[16];
switch (code) {
case 0:
strcpy(buf, "run");
break;
case 1:
strcpy(buf, "block");
break;
case 2:
strcpy(buf, "create");
break;
case 3:
strcpy(buf, "destroy");
break;
/* 4..15 reserved for other infrastructure ops */
default:
sprintf(buf, "code %d", code);
break;
}
printf("TASK %d, pri %d: %s",
(data >> 0) & 0xff,
(data >> 8) & 0xff,
buf);
}
static void show_reserved(FILE *f, char *label, int c)
{
unsigned i;
printf("%s - %#02x", label, c);
for (i = 0; (c & 0x80) && i < 4; i++) {
c = fgetc(f);
if (c == EOF) {
printf("(ERROR %d - %s) ", errno, strerror(errno));
break;
}
printf(" %#02x", c);
}
printf("\n");
}
static bool read_varlen(FILE *f, int c, unsigned *value)
{
unsigned size;
unsigned char buf[4];
unsigned i;
*value = 0;
switch (c & 3) {
case 3:
size = 4;
break;
case 2:
size = 2;
break;
case 1:
size = 1;
break;
default:
printf("INVALID SIZE\n");
return false;
}
memset(buf, 0, sizeof buf);
if (fread(buf, 1, size, f) != size)
goto err;
*value = (buf[3] << 24)
+ (buf[2] << 16)
+ (buf[2] << 8)
+ (buf[0] << 0);
return true;
err:
printf("(ERROR %d - %s)\n", errno, strerror(errno));
return;
}
static void show_hard(FILE *f, int c)
{
unsigned type = c >> 3;
unsigned value;
unsigned size;
char *label;
printf("DWT - ", type);
if (!read_varlen(f, c, &value))
return;
printf("%#x", value);
switch (type) {
case 0: /* event counter wrapping */
printf("overflow %s%s%s%s%s%s",
(value & (1 << 5)) ? "cyc " : "",
(value & (1 << 4)) ? "fold " : "",
(value & (1 << 3)) ? "lsu " : "",
(value & (1 << 2)) ? "slp " : "",
(value & (1 << 1)) ? "exc " : "",
(value & (1 << 0)) ? "cpi " : "");
break;
case 1: /* exception tracing */
switch (value >> 12) {
case 1:
label = "entry to";
break;
case 2:
label = "exit from";
break;
case 3:
label = "return to";
break;
default:
label = "?";
break;
}
printf("%s exception %d", label, value & 0x1ff);
break;
case 2: /* PC sampling */
if (c == 0x15)
printf("PC - sleep");
else
printf("PC - %#08x", value);
break;
case 8: /* data tracing, pc value */
case 10:
case 12:
case 14:
printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
/* optionally followed by data value */
break;
case 9: /* data tracing, address offset */
case 11:
case 13:
case 15:
printf("Data trace %d, address offset %#04x",
(c >> 4) & 3, value);
/* always followed by data value */
break;
case 16 ... 23: /* data tracing, data value */
printf("Data trace %d, ", (c >> 4) & 3);
label = (c & 0x8) ? "write" : "read";
switch (c & 3) {
case 3:
printf("word %s, value %#08x", label, value);
break;
case 2:
printf("halfword %s, value %#04x", label, value);
break;
case 1:
printf("byte %s, value %#02x", label, value);
break;
}
break;
default:
printf("UNDEFINED");
break;
}
printf("\n");
return;
}
/*
* Table of SWIT (SoftWare InstrumentTation) message dump formats, for
* ITM port 0..31 application data.
*
* Eventually this should be customizable; all usage is application defined.
*
* REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
*/
struct {
int port;
void (*show)(int port, unsigned data);
} format[] = {
{ .port = 31, .show = show_task, },
};
static void show_swit(FILE *f, int c)
{
unsigned size;
unsigned port = c >> 3;
unsigned char buf[4];
unsigned value = 0;
unsigned i;
printf("SWIT %u - ", port);
if (!read_varlen(f, c, &value))
return;
printf("%#08x", value);
for (i = 0; i <= sizeof(format) / sizeof(format[0]); i++) {
if (format[i].port == port) {
printf(", ");
format[i].show(port, value);
break;
}
}
printf("\n");
return;
err:
printf("(ERROR %d - %s)\n", errno, strerror(errno));
return;
}
static void show_timestamp(FILE *f, int c)
{
unsigned counter = 0;
char *label = "";
bool delayed = false;
printf("TIMESTAMP - ");
/* Format 2: header only */
if (!(c & 0x80)) {
switch (c) {
case 0: /* sync packet -- coding error! */
case 0x70: /* overflow -- ditto! */
printf("ERROR - %#02x\n", c);
break;
default:
/* synchronous to ITM */
counter = c >> 4;
goto done;
}
return;
}
/* Format 1: one to four bytes of data too */
switch (c) {
default:
label = ", reserved control\n";
break;
case 0xc:
/* synchronous to ITM */
break;
case 0xd:
label = ", timestamp delayed";
delayed = true;
break;
case 0xe:
label = ", packet delayed";
delayed = true;
break;
case 0xf:
label = ", packet and timetamp delayed";
delayed = true;
break;
}
c = fgetc(f);
if (c == EOF)
goto err;
counter = c & 0x7f;
if (!(c & 0x80))
goto done;
c = fgetc(f);
if (c == EOF)
goto err;
counter |= (c & 0x7f) << 7;
if (!(c & 0x80))
goto done;
c = fgetc(f);
if (c == EOF)
goto err;
counter |= (c & 0x7f) << 14;
if (!(c & 0x80))
goto done;
c = fgetc(f);
if (c == EOF)
goto err;
counter |= (c & 0x7f) << 21;
done:
/* REVISIT should we try to convert from delta values? */
printf("+%u%s\n", counter, label);
return;
err:
printf("(ERROR %d - %s) ", errno, strerror(errno));
goto done;
}
int main(int argc, char **argv)
{
FILE *f = stdin;
int c;
/* parse arguments */
while ((c = getopt(argc, argv, "f:")) != EOF) {
switch (c) {
case 'f':
/* e.g. from UART connected to /dev/ttyUSB0 */
f = fopen(optarg, "r");
if (!f) {
perror(optarg);
return 1;
}
break;
default:
usage:
fprintf(stderr, "usage: %s [-f input]",
basename(argv[0]));
return 1;
}
}
/* Parse data ... records have a header then data bytes.
* NOTE: we assume getc() deals in 8-bit bytes.
*/
bool overflow = false;
while ((c = getc(f)) != EOF) {
/* Sync packet ... 7 zeroes, 0x80 */
if (c == 0) {
int i;
for (i = 0; i < 6; i++) {
c = fgetc(f);
if (c == EOF)
break;
if (c != 0)
goto bad_sync;
}
c = fgetc(f);
if (c == 0x80) {
printf("SYNC\n");
continue;
}
bad_sync:
printf("BAD SYNC\n");
continue;
}
/* Overflow packet */
if (c == 0x70) {
/* REVISIT later, report just what overflowed!
* Timestamp and SWIT can happen. Non-ITM too?
*/
overflow = true;
printf("OVERFLOW ...\n");
continue;
}
overflow = false;
switch (c & 0x0f) {
case 0x00: /* Timestamp */
show_timestamp(f, c);
break;
case 0x04: /* "Reserved" */
show_reserved(f, "RESERVED", c);
break;
case 0x08: /* ITM Extension */
/* FIXME someday, handle these ... */
show_reserved(f, "ITM EXT", c);
break;
case 0x0c: /* DWT Extension */
show_reserved(f, "DWT EXT", c);
break;
default:
if (c & 4)
show_hard(f, c);
else
show_swit(f, c);
break;
}
}
return 0;
}

View File

@@ -1,33 +0,0 @@
Included in these directories are the src to the various ram loaders used
within openocd.
** target checksum loaders **
checksum/armv4_5_crc.s :
- ARMv4 and ARMv5 checksum loader : see target/arm_crc_code.c:arm_crc_code
checksum/armv7m_crc.s :
- ARMv7m checksum loader : see target/armv7m.c:cortex_m3_crc_code
checksum/mips32.s :
- MIPS32 checksum loader : see target/mips32.c:mips_crc_code
** target flash loaders **
flash/pic32mx.s :
- Microchip PIC32 flash loader : see flash/nor/pic32mx.c:pic32mx_flash_write_code
flash/stellaris.s :
- TI Stellaris flash loader : see flash/nor/stellaris.c:stellaris_write_code
flash/stm32x.s :
- ST STM32 flash loader : see flash/nor/stm32x.c:stm32x_flash_write_code
flash/str7x.s :
- ST STR7 flash loader : see flash/nor/str7x.c:str7x_flash_write_code
flash/str9x.s :
- ST STR9 flash loader : see flash/nor/str9x.c:str9x_flash_write_code
Spencer Oliver
spen@spen-soft.co.uk

View File

@@ -1,58 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
/*
r0 - address in - crc out
r1 - char count
*/
.text
.arm
_start:
main:
mov r2, r0
mov r0, #0xffffffff /* crc */
mov r3, r1
mov r4, #0
b ncomp
nbyte:
ldrb r1, [r2, r4]
ldr r7, CRC32XOR
eor r0, r0, r1, asl #24
mov r5, #0
loop:
cmp r0, #0
mov r6, r0, asl #1
add r5, r5, #1
mov r0, r6
eorlt r0, r6, r7
cmp r5, #8
bne loop
add r4, r4, #1
ncomp:
cmp r4, r3
bne nbyte
end:
bkpt #0
CRC32XOR: .word 0x04c11db7
.end

View File

@@ -1,66 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
/*
parameters:
r0 - address in - crc out
r1 - char count
*/
.text
.syntax unified
.arch armv7-m
.thumb
.thumb_func
.align 2
_start:
main:
mov r2, r0
mov r0, #0xffffffff /* crc */
mov r3, r1
mov r4, #0
b ncomp
nbyte:
ldrb r1, [r2, r4]
ldr r7, CRC32XOR
eor r0, r0, r1, asl #24
mov r5, #0
loop:
cmp r0, #0
mov r6, r0, asl #1
add r5, r5, #1
mov r0, r6
it lt
eorlt r0, r6, r7
cmp r5, #8
bne loop
add r4, r4, #1
ncomp:
cmp r4, r3
bne nbyte
bkpt #0
CRC32XOR: .word 0x04c11db7
.end

View File

@@ -1,72 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.global main
.text
.set noreorder
/* params:
* $a0 address in
* $a1 byte count
* vars
* $a0 crc
* $a1 crc data byte
* temps:
* t3 v0 a3 a2 t0 v1
*/
.ent main
main:
addiu $t4, $a0, 0 /* address in */
addiu $t2, $a1, 0 /* count */
addiu $a0, $zero, 0xffffffff /* a0 crc - result */
beq $zero, $zero, ncomp
addiu $t3, $zero, 0 /* clear bytes read */
nbyte:
lb $a1, ($t4) /* load byte from source address */
addi $t4, $t4, 1 /* inc byte count */
crc:
sll $a1, $a1, 24
lui $v0, 0x04c1
xor $a0, $a0, $a1
ori $a3, $v0, 0x1db7
addu $a2, $zero, $zero /* clear bit count */
loop:
sll $t0, $a0, 1
addiu $a2, $a2, 1 /* inc bit count */
slti $a0, $a0, 0
xor $t1, $t0, $a3
movn $t0, $t1, $a0
slti $v1, $a2, 8 /* 8bits processed */
bne $v1, $zero, loop
addu $a0, $t0, $zero
ncomp:
bne $t2, $t3, nbyte /* all bytes processed */
addiu $t3, $t3, 1
wait:
sdbbp
.end main

View File

@@ -1,57 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* algorithm register usage:
* r0: source address (in RAM)
* r1: target address (in Flash)
* r2: count
* r3: flash write command
* r4: status byte (returned to host)
* r5: busy test pattern
* r6: error test pattern
*/
loop:
ldrh r4, [r0], #2
strh r3, [r1]
strh r4, [r1]
busy:
ldrh r4, [r1]
and r7, r4, r5
cmp r7, r5
bne busy
tst r4, r6
bne done
subs r2, r2, #1
beq done
add r1, r1, #2
b loop
done:
b done
.end

View File

@@ -1,57 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* algorithm register usage:
* r0: source address (in RAM)
* r1: target address (in Flash)
* r2: count
* r3: flash write command
* r4: status byte (returned to host)
* r5: busy test pattern
* r6: error test pattern
*/
loop:
ldr r4, [r0], #4
str r3, [r1]
str r4, [r1]
busy:
ldr r4, [r1]
and r7, r4, r5
cmp r7, r5
bne busy
tst r4, r6
bne done
subs r2, r2, #1
beq done
add r1, r1, #4
b loop
done:
b done
.end

View File

@@ -1,57 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* algorithm register usage:
* r0: source address (in RAM)
* r1: target address (in Flash)
* r2: count
* r3: flash write command
* r4: status byte (returned to host)
* r5: busy test pattern
* r6: error test pattern
*/
loop:
ldrb r4, [r0], #1
strb r3, [r1]
strb r4, [r1]
busy:
ldrb r4, [r1]
and r7, r4, r5
cmp r7, r5
bne busy
tst r4, r6
bne done
subs r2, r2, #1
beq done
add r1, r1, #1
b loop
done:
b done
.end

View File

@@ -1,75 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* input parameters - */
/* R0 = source address */
/* R1 = destination address */
/* R2 = number of writes */
/* R3 = flash write command */
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
/* output parameters - */
/* R5 = 0x80 ok 0x00 bad */
/* temp registers - */
/* R6 = value read from flash to test status */
/* R7 = holding register */
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
/* R10 = unlock2_addr */
/* R11 = unlock2_cmd */
code:
ldrh r5, [r0], #2
strh r9, [r8]
strh r11, [r10]
strh r3, [r8]
strh r5, [r1]
nop
busy:
ldrh r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
ands r6, r6, r4, lsr #2
beq busy /* b if DQ5 low */
ldrh r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
mov r5, #0 /* 0x0 - return 0x00, error */
bne done
cont:
subs r2, r2, #1 /* 0x1 */
moveq r5, #128 /* 0x80 */
beq done
add r1, r1, #2 /* 0x2 */
b code
done:
b done
.end

View File

@@ -1,66 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* input parameters - */
/* R0 = source address */
/* R1 = destination address */
/* R2 = number of writes */
/* R3 = flash write command */
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
/* output parameters - */
/* R5 = 0x80 ok 0x00 bad */
/* temp registers - */
/* R6 = value read from flash to test status */
/* R7 = holding register */
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
/* R10 = unlock2_addr */
/* R11 = unlock2_cmd */
code:
ldrh r5, [r0], #2
strh r9, [r8]
strh r11, [r10]
strh r3, [r8]
strh r5, [r1]
nop
busy:
ldrh r6, [r1]
eor r7, r5, r6
ands r7, #0x80
bne busy
subs r2, r2, #1 /* 0x1 */
moveq r5, #128 /* 0x80 */
beq done
add r1, r1, #2 /* 0x2 */
b code
done:
b done
.end

View File

@@ -1,75 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* input parameters - */
/* R0 = source address */
/* R1 = destination address */
/* R2 = number of writes */
/* R3 = flash write command */
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
/* output parameters - */
/* R5 = 0x80 ok 0x00 bad */
/* temp registers - */
/* R6 = value read from flash to test status */
/* R7 = holding register */
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
/* R10 = unlock2_addr */
/* R11 = unlock2_cmd */
code:
ldr r5, [r0], #4
str r9, [r8]
str r11, [r10]
str r3, [r8]
str r5, [r1]
nop
busy:
ldr r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
ands r6, r6, r4, lsr #2
beq busy /* b if DQ5 low */
ldr r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
mov r5, #0 /* 0x0 - return 0x00, error */
bne done
cont:
subs r2, r2, #1 /* 0x1 */
moveq r5, #128 /* 0x80 */
beq done
add r1, r1, #4 /* 0x4 */
b code
done:
b done
.end

View File

@@ -1,75 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4
.section .init
/* input parameters - */
/* R0 = source address */
/* R1 = destination address */
/* R2 = number of writes */
/* R3 = flash write command */
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
/* output parameters - */
/* R5 = 0x80 ok 0x00 bad */
/* temp registers - */
/* R6 = value read from flash to test status */
/* R7 = holding register */
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
/* R10 = unlock2_addr */
/* R11 = unlock2_cmd */
code:
ldrb r5, [r0], #1
strb r9, [r8]
strb r11, [r10]
strb r3, [r8]
strb r5, [r1]
nop
busy:
ldrb r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
ands r6, r6, r4, lsr #2
beq busy /* b if DQ5 low */
ldrb r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
mov r5, #0 /* 0x0 - return 0x00, error */
bne done
cont:
subs r2, r2, #1 /* 0x1 */
moveq r5, #128 /* 0x80 */
beq done
add r1, r1, #1 /* 0x1 */
b code
done:
b done
.end

View File

@@ -1,81 +0,0 @@
/***************************************************************************
* Copyright (C) 2005, 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* Copyright (C) 2010 Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.syntax unified
.arch armv7-m
.thumb
.thumb_func
.align 2
/* input parameters - */
/* R0 = source address */
/* R1 = destination address */
/* R2 = number of writes */
/* R3 = flash write command */
/* R4 = constant to mask DQ7 bits (also used for Dq5 with shift) */
/* output parameters - */
/* R5 = 0x80 ok 0x00 bad */
/* temp registers - */
/* R6 = value read from flash to test status */
/* R7 = holding register */
/* unlock registers - */
/* R8 = unlock1_addr */
/* R9 = unlock1_cmd */
/* R10 = unlock2_addr */
/* R11 = unlock2_cmd */
code:
ldrh r5, [r0], #2
strh r9, [r8]
strh r11, [r10]
strh r3, [r8]
strh r5, [r1]
nop
busy:
ldrh r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
ands r6, r6, r4, lsr #2
beq busy /* b if DQ5 low */
ldrh r6, [r1]
eor r7, r5, r6
ands r7, r4, r7
beq cont /* b if DQ7 == Data7 */
mov r5, #0 /* 0x0 - return 0x00, error */
bne done
cont:
subs r2, r2, #1 /* 0x1 */
beq success
add r1, r1, #2 /* 0x2 */
b code
success:
mov r5, #128 /* 0x80 */
b done
done:
bkpt #0
.end

View File

@@ -1,132 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arch m4k
.set noreorder
.set noat
/* params:
* $a0 src adr - ram + result
* $a1 dest adr - flash
* $a2 count (32bit words)
* vars
*
* temps:
* $t0, $t1, $t2, $t3, $t4, $t5
* $s0, $s1, $s3, $s4, $s5
*/
.type main, @function
.global main
.ent main
main:
/* setup constants */
lui $t0, 0xaa99
ori $t0, 0x6655 /* NVMKEY1 */
lui $t1, 0x5566
ori $t1, 0x99AA /* NVMKEY2 */
lui $t2, 0xBF80
ori $t2, 0xF400 /* NVMCON */
ori $t3, $zero, 0x4003 /* NVMCON row write cmd */
ori $t4, $zero, 0x8000 /* NVMCON start cmd */
write_row:
/* can we perform a row write: 128 32bit words */
sltiu $s3, $a2, 128
bne $s3, $zero, write_word
ori $t5, $zero, 0x4000 /* NVMCON clear cmd */
/* perform row write 512 bytes */
sw $a1, 32($t2) /* set NVMADDR with dest addr - real addr */
sw $a0, 64($t2) /* set NVMSRCADDR with src addr - real addr */
bal progflash
addiu $a0, $a0, 512
addiu $a1, $a1, 512
beq $zero, $zero, write_row
addiu $a2, $a2, -128
write_word:
/* write 32bit words */
lui $s5, 0xa000
ori $s5, 0x0000
or $a0, $a0, $s5 /* convert to virtual addr */
beq $zero, $zero, next_word
ori $t3, $zero, 0x4001 /* NVMCON word write cmd */
prog_word:
lw $s4, 0($a0) /* load data - from virtual addr */
sw $s4, 48($t2) /* set NVMDATA with data */
sw $a1, 32($t2) /* set NVMADDR with dest addr - real addr */
bal progflash
addiu $a0, $a0, 4
addiu $a1, $a1, 4
addiu $a2, $a2, -1
next_word:
bne $a2, $zero, prog_word
nop
done:
beq $zero, $zero, exit
addiu $a0, $zero, 0
error:
/* save result to $a0 */
addiu $a0, $s1, 0
exit:
sdbbp
.end main
.type progflash, @function
.global progflash
.ent progflash
progflash:
sw $t3, 0($t2) /* set NVMWREN */
sw $t0, 16($t2) /* write NVMKEY1 */
sw $t1, 16($t2) /* write NVMKEY2 */
sw $t4, 8($t2) /* start operation */
waitflash:
lw $s0, 0($t2)
and $s0, $s0, $t4
bne $s0, $zero, waitflash
nop
/* following is to comply with errata #34
* 500ns delay required */
nop
nop
nop
nop
/* check for errors */
lw $s1, 0($t2)
andi $s1, $zero, 0x3000
bne $s1, $zero, error
sw $t5, 4($t2) /* clear NVMWREN */
jr $ra
nop
.end progflash

View File

@@ -1,66 +0,0 @@
/***************************************************************************
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m3
.thumb
.thumb_func
.align 2
/*
Call with :
r0 = buffer address
r1 = destination address
r2 = bytecount (in) - endaddr (work)
Used registers:
r3 = pFLASH_CTRL_BASE
r4 = FLASHWRITECMD
r5 = #1
r6 = bytes written
r7 = temp reg
*/
write:
ldr r3,pFLASH_CTRL_BASE
ldr r4,FLASHWRITECMD
movs r5, 1
movs r6, #0
mainloop:
str r1, [r3, #0]
ldr r7, [r0, r6]
str r7, [r3, #4]
str r4, [r3, #8]
waitloop:
ldr r7, [r3, #8]
tst r7, r5
bne waitloop
adds r1, r1, #4
adds r6, r6, #4
cmp r6, r2
bne mainloop
bkpt #0
pFLASH_CTRL_BASE: .word 0x400FD000
FLASHWRITECMD: .word 0xA4420001

View File

@@ -1,63 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2011 Øyvind Harboe *
* oyvind.harboe@zylin.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. *
***************************************************************************/
// Build : arm-eabi-gcc -c stm32f2xxx.S
.text
.syntax unified
.cpu cortex-m3
.thumb
.thumb_func
.global write
/*
r0 - source address
r1 - target address
r2 - count (halfword-16bit)
r3 - result out
r4 - flash base
*/
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
write:
write_half_word:
ldr r3, STM32_PROG16
str r3, [r4, #STM32_FLASH_CR_OFFSET]
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
busy:
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
tst r3, #0x10000 /* BSY (bit0) == 1 => operation in progress */
beq busy /* wait more... */
tst r3, #0xf0 /* PGSERR | PGPERR | PGAERR | WRPERR */
bne exit /* fail... */
subs r2, r2, #0x01 /* decrement counter */
bne write_half_word /* write next half-word if anything left */
exit:
bkpt #0x00
STM32_PROG16: .word 0x101 /* PG | PSIZE_16*/

View File

@@ -1,58 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.syntax unified
.cpu cortex-m3
.thumb
.thumb_func
.global write
/*
r0 - source address
r1 - target address
r2 - count (halfword-16bit)
r3 - sector offet in : result out
r4 - flash base
*/
#define STM32_FLASH_CR_OFFSET 0x10 /* offset of CR register in FLASH struct */
#define STM32_FLASH_SR_OFFSET 0x0c /* offset of CR register in FLASH struct */
write:
ldr r4, STM32_FLASH_BASE
add r4, r3 /* add offset 0x00 for sector 0 : 0x40 for sector 1 */
write_half_word:
movs r3, #0x01
str r3, [r4, #STM32_FLASH_CR_OFFSET] /* PG (bit0) == 1 => flash programming enabled */
ldrh r3, [r0], #0x02 /* read one half-word from src, increment ptr */
strh r3, [r1], #0x02 /* write one half-word from src, increment ptr */
busy:
ldr r3, [r4, #STM32_FLASH_SR_OFFSET]
tst r3, #0x01 /* BSY (bit0) == 1 => operation in progress */
beq busy /* wait more... */
tst r3, #0x14 /* PGERR (bit2) == 1 or WRPRTERR (bit4) == 1 => error */
bne exit /* fail... */
subs r2, r2, #0x01 /* decrement counter */
bne write_half_word /* write next half-word if anything left */
exit:
bkpt #0x00
STM32_FLASH_BASE: .word 0x40022000 /* base address of FLASH struct */

View File

@@ -1,59 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv4t
.section .init
/*
r0 source address
r1 address
r2 FLASH_CR0
r3 dword count
r4 result
r5 busy mask
*/
write:
mov r4, #0x10000000 /* set DWPG bit */
str r4, [r2, #0x0] /* FLASH_CR0 */
str r1, [r2, #0x10] /* FLASH_AR */
ldr r4, [r0], #4 /* load data */
str r4, [r2, #0x8] /* FLASH_DR0 */
ldr r4, [r0], #4 /* load data */
str r4, [r2, #0xc] /* FLASH_DR1 */
mov r4, #0x90000000 /* set DWPG and WMS bits */
str r4, [r2, #0x0] /* FLASH_CR0 */
busy:
ldr r4, [r2, #0x0] /* FLASH_CR0 */
tst r4, r5
bne busy
ldr r4, [r2, #0x14] /* FLASH_ER */
tst r4, #0xff /* do we have errors */
tsteq r4, #0x100 /* write protection set */
bne exit
add r1, r1, #0x8 /* next 8 bytes */
subs r3, r3, #1 /* decremment dword count */
bne write
exit:
b exit
.end

View File

@@ -1,56 +0,0 @@
/***************************************************************************
* Copyright (C) 2010 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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. *
***************************************************************************/
.text
.arm
.arch armv5t
.section .init
/*
r0 source address (in)
r1 target address (in)
r2 word count (in)
r3 result (out)
*/
write:
bic r4, r1, #3 /* word address */
mov r3, #0x40 /* write command */
strh r3, [r4, #0]
ldrh r3, [r0], #2 /* read data */
strh r3, [r1], #2 /* write data */
mov r3, #0x70 /* status command */
strh r3, [r4, #0]
busy:
ldrb r3, [r4, #0] /* status */
tst r3, #0x80
beq busy
mov r5, #0x50 /* clear status command */
strh r5, [r4, #0]
mov r5, #0xFF /* read array */
strh r5, [r4, #0]
tst r3, #0x12
bne exit
subs r2, r2, #1 /* decremment word count */
bne write
exit:
bkpt #0
.end

View File

@@ -1,71 +1,60 @@
ACTION!="add|change", GOTO="openocd_rules_end"
SUBSYSTEM!="usb", GOTO="openocd_rules_end"
ENV{DEVTYPE}!="usb_device", GOTO="openocd_rules_end"
BUS!="usb", ACTION!="add", SUBSYSTEM!=="usb_device", GOTO="openocd_rules_end"
# Olimex ARM-USB-OCD
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0003", MODE="664", GROUP="plugdev"
# Olimex ARM-USB-OCD-TINY
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0004", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="0004", MODE="664", GROUP="plugdev"
# Olimex ARM-JTAG-EW
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="001e", MODE="664", GROUP="plugdev"
# Olimex ARM-USB-OCD-TINY-H
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="15ba", SYSFS{idProduct}=="001e", MODE="664", GROUP="plugdev"
# USBprog with OpenOCD firmware
ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="1781", SYSFS{idProduct}=="0c63", MODE="664", GROUP="plugdev"
# Amontec JTAGkey and JTAGkey-tiny
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="cff8", MODE="664", GROUP="plugdev"
# Amontec JTAGkey-HiSpeed
ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0fbb", SYSFS{idProduct}=="1000", MODE="664", GROUP="plugdev"
# Axiom AXM-0432 Link (Symphony SoundBite?)
# Calao Systems USB-A9260-C01
# TinCanTools Flyswatter
# OOCD-Link
# Marvell Sheevaplug (early development versions)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6010", MODE="664", GROUP="plugdev"
# Calao Systems USB-A9260-C02
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="6001", MODE="664", GROUP="plugdev"
# IAR J-Link USB
ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0101", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="1366", SYSFS{idProduct}=="0101", MODE="664", GROUP="plugdev"
# Raisonance RLink
ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="138e", SYSFS{idProduct}=="9000", MODE="664", GROUP="plugdev"
# Hitex STR9-comStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002c", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002c", MODE="664", GROUP="plugdev"
# Hitex STM32-PerformanceStick
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="002d", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0640", SYSFS{idProduct}=="002d", MODE="664", GROUP="plugdev"
# TI/Luminary Stellaris Evaluation Board (several)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcda", MODE="664", GROUP="plugdev"
# Luminary Micro Stellaris/LM3S811
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bcd9", MODE="664", GROUP="plugdev"
# Xverve Signalyzer Tool (DT-USB-ST)
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bca0", MODE="664", GROUP="plugdev"
# egnite Turtelizer 2
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="bdc8", MODE="664", GROUP="plugdev"
# Marvell Sheevaplug
ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="9e88", SYSFS{idProduct}=="9e8f", MODE="664", GROUP="plugdev"
# Section5 ICEbear
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c140", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c141", MODE="664", GROUP="plugdev"
# Hilscher NXHX Boards
ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c140", MODE="664", GROUP="plugdev"
SYSFS{idVendor}=="0403", SYSFS{idProduct}=="c141", MODE="664", GROUP="plugdev"
LABEL="openocd_rules_end"

View File

@@ -1,8 +1,7 @@
info_TEXINFOS = openocd.texi
openocd_TEXINFOS = fdl.texi
man_MANS = openocd.1
EXTRA_DIST = openocd.1 \
INSTALL.txt
EXTRA_DIST = openocd.1
dist-hook:
mkdir $(distdir)/manual

View File

@@ -31,95 +31,7 @@ This section needs to be expanded to describe OpenOCD's Jim API.
/** @page helpercommand OpenOCD Command API
OpenOCD's command API allows modules to register callbacks that are then
available to the scripting services. It provides the mechanism for
these commands to be dispatched to the modlue using a standard
interfaces. It provides macros for defining functions that use and
extend this interface.
@section helpercmdhandler Command Handlers
Command handlers are functions with a particular signature, which can
be extended by modules for passing additional parameters to helpers or
another layer of handlers.
@subsection helpercmdhandlerdef Defining and Calling Command Handlers
These functions should be defined using the @c COMMAND_HANDLER macro.
These methods must be defined as static, as their principle entry point
should be the run_command dispatch mechanism.
Command helper functions that require access to the full set of
parameters should be defined using the @c COMMAND_HELPER. These must be
declared static by you, as sometimes you might want to share a helper
among several files (e.g. @c s3c24xx_nand.h).
Both types of routines must be called using the @c CALL_COMMAND_HANDLER macro.
Calls using this macro to normal handlers require the name of the command
handler (which can a name or function pointer). Calls to helpers and
derived handlers must pass those extra parameters specified by their
definitions; however, lexical capture is used for the core parameters.
This dirty trick is being used as a stop-gap measure while the API is
migrated to one that passes a pointer to a structure containing the
same ingredients. At that point, this macro will be removed and callers
will be able to use direct invocations.
Thus, the following macros can be used to define and call command
handlers or helpers:
- @c COMMAND_HANDLER - declare or define a command handler.
- @c COMMAND_HELPER - declare or define a derived command handler or helper.
- @c CALL_COMMAND_COMMAND - call a command handler/helper.
@subsection helpercmdhandlermacros Command Handler Macros
In addition, the following macros may be used in the context of
command handlers and helpers:
- @c CMD_CTX - the current @c command_context
- @c CMD_NAME - invoked command name
- @c CMD_ARGC - the number of command arguments
- @c CMD_ARGV - array of command argument strings
@section helpercmdregister Command Registration
In order to use a command handler, it must be registered with the
command subsystem. All commands are registered with command_registration
structures, specifying the name of the command, its handler, its allowed
mode(s) of execution, and strings that provide usage and help text.
A single handler may be registered using multiple names, but any name
may have only one handler associated with it.
The @c register_commands() and @c register_commands() functions provide
registration, while the @c unregister_command() and
@c unregister_all_commands() functions will remove existing commands.
These may be called at any time, allowing the command set to change in
response to system actions.
@subsection helpercmdjim Jim Command Registration
The command_registration structure provides support for registering
native Jim command handlers (@c jim_handler) too. For these handlers,
the module can provide help and usage support; however, this mechanism
allows Jim handlers to be called as sub-commands of other commands.
These commands may be registered with a private data value (@c
jim_handler_data) that will be available when called, as with low-level
Jim command registration.
A command may have a normal @c handler or a @c jim_handler, but not both.
@subsection helpercmdregisterchains Command Chaining
When using register_commands(), the array of commands may reference
other arrays. When the @c chain field is filled in a
command_registration record, the commands on in the chained list will
added in one of two places. If the record defines a new command, then
the chained commands are added under it; otherwise, the commands are
added in the same context as the other commands in the array.
@section helpercmdprimer Command Development Primer
This @ref primercommand provides details about the @c hello module,
showing how the pieces desrcribed on this page fit together.
This section needs to be expanded to describe OpenOCD's Command API.
*/

View File

@@ -1,6 +1,6 @@
/** @mainpage OpenOCD Developer's Guide
/** @mainpage OpenOCD Reference Manual
Welcome to the OpenOCD Developer's Guide -- the developer's resource for
Welcome to the OpenOCD Reference Manual -- the developer's resource for
learning about the internal architecture of the OpenOCD project. @par
In addition, this document contains the tactical and strategic plans
@@ -42,17 +42,11 @@ associated with the fundamental technologies used by OpenOCD.
- @subpage primertcl
- @subpage primerjtag
The above documents should bridge any "ancillary" gaps in contributor
These documents should bridge any "ancillary" gaps in contributor
knowledge, without having to learn the complete languages or technology.
They should provide enough information for experienced developers to
learn how to make "correct" changes when creating patches.
Beyond the fundamentals, the following primers provide introductory
tutorials for OpenOCD's sub-systems. These complement the @ref oocd
pages that provide more high-level perspective on related topics.
- @subpage primercommand
In all cases, these Primers should use idiomatic conventions that the
community has agreed are the "right way of doing things". In this
respect, these documents typically assume some familiarity with the

View File

@@ -1,138 +0,0 @@
/** @page primercommand Command Development Primer
This page provides a primer for writing commands by introducing @c hello
module. The full source code used in this example can be found in
hello.c, and the @ref primercmdcode section shows how to use it.
A summary of this information can be found in @ref helpercommand .
@section primercmdhandler Command Handlers
Defining new commands and their helpers is easy. The following code
defines a simple command handler that delegates its argument parsing:
@code
COMMAND_HANDLER(handle_hello_command)
{
const char *sep, *name;
int retval = CALL_COMMAND_HANDLER(handle_hello_args);
if (ERROR_OK == retval)
command_print(CMD_CTX, "Greetings%s%s!", sep, name);
return retval;
}
@endcode
Here, the @c COMMAND_HANDLER macro establishes the function signature,
see in command.h by the @c __COMMAND_HANDLER macro.
The COMMAND_HELPER macro function allows defining functions with an
extended version of the base signature. These helper functions can be
called (with the appropriate parameters), the @c CALL_COMMAND_HANDLER
macro to pass any e as parameters to the following helper function:
The subsequent blocks of code are a normal C function that can do
anything, so only complex commands deserve should use comamnd helper
functions. In this respect, this example uses one to demonstrate how --
not when -- they should be used.
@code
static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name)
{
if (argc > 1)
{
LOG_ERROR("%s: too many arguments", CMD_NAME);
return ERROR_COMMAND_SYNTAX_ERROR;
}
if (1 == CMD_ARGC)
{
*sep = ", ";
*name = CMD_ARGV[0];
}
else
*sep = *name = "";
return ERROR_OK;
}
@endcode
Of course, you may also call other macros or functions, but that extends
beyond the scope of this tutorial on writing commands.
@section primercmdreg Command Registration
Before this new function can be used, it must be registered somehow.
For a new module, registering should be done in a new function for
the purpose, which must be called from @c openocd.c:
@code
static const struct command_registration hello_command_handlers[] = {
{
.name = "hello",
.mode = COMMAND_ANY,
.handler = handle_hello_command,
.help = "print a warm greeting",
.usage = "[name]",
},
{
.chain = foo_command_handlers,
}
COMMAND_REGISTRATION_DONE
};
int hello_register_commands(struct command_context_s *cmd_ctx)
{
return register_commands(cmd_ctx, NULL, handle_command_handlers);
}
@endcode
Note that the "usage" text should use the same EBNF that's found
in the User's Guide: literals in 'single quotes', sequences of
optional parameters in [square brackets], and alternatives in
(parentheses|with|vertical bars), and so forth. No angle brackets.
That's it! The command should now be registered and available to scripts.
@section primercmdchain Command Chaining
This example also shows how to chain command handler registration, so
your modules can "inherit" commands provided by other (sub)modules.
Here, the hello module includes the foo commands in the same context
that the 'hello' command will be registered.
If the @c chain field had been put in the 'hello' command, then the
@c foo module commands would be registered under it. Indeed, that
technique is used to define the 'foo bar' and 'foo baz' commands,
as well as for the example drivers that use these modules.
The code for the 'foo' command handlers can be found in @c hello.c.
@section primercmdcode Trying These Example Commands
These commands have been inherited by the dummy interface, faux flash,
and testee target drivers. The easiest way to test these is by using the
dummy interface.
Once OpenOCD has been built with this example code, the following command
demonstrates the abilities that the @c hello module provides:
@code
openocd -c 'interface dummy' \
-c 'dummy hello' \
-c 'dummy hello World' \
-c 'dummy hello {John Doe}' \
-c 'dummy hello John Doe' # error: too many arguments
@endcode
If saved in @c hello.cfg, then running <code>openocd -f hello.cfg</code>
should produce the following output before displaying the help text and
exiting:
@code
Greetings!
Greetings, World!
Greetings, John Doe!
Error: hello: too many arguments
Runtime error, file "openocd.cfg", line 14:
hello: too many arguments
dummy hello [<name>]
prints a warm welcome
@endcode
*/

View File

@@ -29,7 +29,7 @@ TMS which will select different shift registers.
The first thing you need to do is reset the state machine, because when
you connect to a chip you do not know what state the controller is in,you need
to clock TMS as 1, at least 5 times. This will put you into "Test Logic
to clock TMS as 1, at least 7 times. This will put you into "Test Logic
Reset" State. Knowing this, you can, once reset, then track what each
transition on TMS will do, and hence know what state the JTAG state
machine is in.
@@ -45,9 +45,9 @@ instruction register.
For example, one of the data registers will be known as "bypass" this is
(usually) a single bit which has no function and is used to bypass the
chip. Assume we have 3 identical chips, wired up like the picture(wikipedia)
and each has a 3 bits instruction register, and there are 2 known
instructions (110 = bypass, 010 = "some other function") if we want to use
chip. Assume we have 3 identical chips, wired up like the picture
and each has a 3 bit instruction register, and there are 2 known
instructions (110 = bypass, 010 = some other function) if we want to use
"some other function", on the second chip in the line, and not change
the other chips we would do the following transitions.
@@ -66,13 +66,13 @@ each chip [110] [010] [110]
The order is reversed, because we shift out the least significant bit
first. Then we transition TMS:
1 1 1 0 0
1 1 1 1 0 0
which puts us in the "Shift DR state".
Now when we clock data onto TDI (again while holding TMS to 0) , the
data shifts through the data registers, and because of the instruction
registers we selected ("some other function" has 8 bits in its data
registers we selected (some other function has 8 bits in its data
register), our total data register in the chain looks like this:
0 00000000 0
@@ -107,6 +107,10 @@ gets interesting. But in and of itself, JTAG is actually very simple.
@section primerjtag More Reading
The following link goes to an HTML (or PDF) introduction to JTAG,
written by one of the original members of the JTAG committee: @par
http://www.asset-intertech.com/products/boundscan.htm
A separate primer contains information about @subpage primerjtagbs for
developers that want to extend OpenOCD for such purposes.

View File

@@ -84,8 +84,8 @@ the minor version will @a also be zero (<code>y = 0, z = 0</code>).
After these required numeric components, release version strings
may contain tags such as as <em>-rc1</em> or <em>-rc2</em>.
These 'rc' tags indicate "release candidate" versions of the package.
Like major/minor/micro numbers, these are updated
as part of the release process.
Like the major/minor/micro numbers, these tags will be manipulated
by the automated release process.
The release process includes version number manipulations to the tree
being released, ensuring that all numbers are incremented (or rolled
@@ -277,34 +277,22 @@ support; the Release Manager isn't the only participant.
The following steps should be followed to produce each release:
-# Produce final patches using a local clone of mainline. Nobody
except the RM should be committing anything. <em>Everyone with commit
privileges needs to know and agree to this in advance!</em> Even the RM
only commits a handful of updates as part of the release process
itself ... to files which are part of the version identification scheme
or release process; and to create the version tag; and then to open the
merge window for the next release cycle.
-# Finalize @c the NEWS file to describe the changes in the release
-# Produce final patches to mainline (or a release branch). Nobody
except the RM should be committing anything.
-# Finalize @c NEWS file to describe the changes in the release
- This file is used to automatically post "blurbs" about the project.
- This material should have been produced during the development cycle,
by adding items for each @c NEWS-worthy contribution, when committed
during the merge window. (One part of closing the merge window, by
opening the RC phase of the release, is the commitment to hold all
further such contributions until the next merge window opens.)
- The RM should make sure nothing important was omitted, as part of
the RC1 cycle. From then on, no more updates to NEWS content should
be needed (except to seed the process for the next release, or maybe
if a significant and longstanding bug is fixed late in the RC phase).
- This material should be produced during the development cycle.
- Add a new item for each @c NEWS-worthy contribution, when committed.
-# Bump library version if our API changed (not yet required)
-# Update and commit the final package version in @c configure.in:
(The <code>tools/release/version.sh</code> script might help ensure
the versions are named properly.):
<code>tools/release/version.sh</code> may help ensure the versions
are named consistently:
-# Remove @c -dev tag.
-# Update any @c -rc tag:
-# Update the @c -rc tag:
- If producing the final release from an -rc series, remove it
- If producing the first RC in a series, add rc1
- If producing the next RC in a series, bump the rc number
-# Commit that version change, with a good descriptive comment.
-# Commit that version change.
-# Create a git tag for the final commit, with a tag name matching
the version string in <code>configure.in</code> (including <em>-rcN</em>
where relevant):
@@ -313,92 +301,49 @@ PACKAGE_VERSION="x.y.z"
PACKAGE_TAG="v${PACKAGE_VERSION}"
git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}"
@endverbatim
-# Do not push those changes to mainline yet; only builds using the
source archives you will be creating should ever be labeled as
official releases (with no "-dev" suffix). Since mainline is a
development tree, these will be pushed later, as part of opening
the merge window for the next release cycle (restoring the "-dev"
suffix for that next release.) Those version and tag updates are
the last ones to be included in the release being made.
-# Produce the release files, using the local clone of the source
tree which holds the release's tag and updated version in
@c configure.in ... this is used only to produce the release, and
all files should already be properly checked out.
-# Run <code>tools/release.sh package</code> to produce the
source archives. This automatically bootstraps and
configures the process.
-# Run <code>tools/release.sh stage</code> to create an @c archives
directory with the release data, including MD5 and SHA1
checksum files (which are used with Berlios).
-# Sanity check at least one of those archives, by extracting and
configuring its contents, using them to build a copy of OpenOCD,
and verifying that the result prints the correct release version
in its startup banner. (For example,
"configure --enable-ft2232_libftdi --enable-parport"
then "make" and run "src/openocd -v" as a sanity check.)
-# Run <code>make docs</code> to create the
documentation which will be published.
-# Upload packages and post announcements of their availability:
-# Release packages into files section of project sites:
- SF.net:
-# Under "Project Admin", use the "File Manager"
-# Create a new folder under "openocd" named "${PACKAGE_VERSION}"
-# Upload the @c NEWS file and mark it as the release notes.
-# Upload the three source archive files, using the Web interface,
into that folder. Verify the upload worked OK by checking the
MD5 and SHA1 checksums computed by SourceForge against the
versions created as part of staging the release.
-# Also upload doc/openocd.pdf (the User's Guide) so the version
matching each release will be easily available.
-# Select each file in the release, and use the property panel
to set its type and select the right release notes.
- .tar.bz2: Linux, Mac
- .tar.gz: BSD, Solaris, Others
- .zip: Windows
- For openocd.pdf just associate it with the right release notes.
-# Create an SF.net project news update.
- Berlios:
-# Provide @c NEWS file, as requested.
-# Upload the release files via FTP to ftp://ftp.berlios.de/incoming/
-# Edit descriptions for each file (one at a time) Note that Berlios
does not automatically checksum files, and it uses a very old
version of the SourceForge code with user interface issues.
-# Click button to send E-mail Release Notice.
-# Depending on how paranoid you're feeling today, verify the images by
downloading them from the websites and making sure there are no
differences between the downloaded copies and your originals.
-# Publish User's and Developer's Guides to the project web sites:
-# Use SCP to update the SF.net web site with PDF and HTML for the
User's Guide, and HTML for the developer's guide ... you can
instantiate a shell.sourceforge.net instance and set up symlinks
from your home directory, to simplify this process.
-# (How to update the Berlios web site with the same data?)
-# Post announcement e-mail to the openocd-development list.
-# optionally:
-# Post an update on the Berlios blog (if it lets you)
-# Announce updates on freshmeat.net and other trackers.
-# Submit updates to news feeds (e.g. Digg, Reddit, etc.).
-# Resume normal development on mainline, by opening the merge window for
the next major or minor release cycle. (You might want to do this
before all the release bits are fully published.)
- Update the version label in the @c configure.in file:
-# Prepare to resume normal development on mainline (major or minor release)
- Update the version label
- Restore @c -dev version tag.
- For a new minor release cycle, increment the release's minor number
- For a new major release cycle, increment the release's major number
and zero its minor number
- Archive @c NEWS file as "<code>doc/news/NEWS-${PACKAGE_VERSION}</code>".
- Create a new @c NEWS file for the next release
- Commit those changes.
- Push all the updates to mainline.
- Last updates for the release, including the release tag (you
will need to "git push --tags").
- Updates opening the merge window
- At this point, it's OK for commiters to start pushing changes
which have been held off until the next release. (Any bugfixes to
this release will be against a bug-fix release branch starting from
the commit you tagged as this release, not mainline.)
- Announce to the openocd-development list. Ideally, you will also
be able to say who is managing the next release cycle.
- Commit those changes, and push the commit and the release tag
to mainline.
-# Produce the package source archives:
-# <em>Start with a new clone of the source tree</em>, with the
release's tag. This is used only for producing these packages.
-# Checkout the appropriate tag:
<code>git checkout "${PACKAGE_VERSION}"</code>
-# @c bootstrap, @c configure, and @c make the package.
-# Run <code>make distcheck</code> to produce the distribution archives.
-# Run <code>make maintainer-clean</code> verify the repository is empty.
-# Create signature files using @c md5sum, @c sha1sum, etc.
-# Publish documentation for the release:
- Allow users to access the documentation for each of our releases.
- Place static copies of the following files on the project website:
- @c NEWS: to provide a blurb for each release
- User's Guide, Developer Manual: to allow easy on-line viewing
-# Upload packages and post announcements of their availability:
-# Release packages into files section of project sites:
- SF.net:
-# Create a new folder named "${PACKAGE_VERSION}"
-# Select new folder as the target for uploads.
-# Upload files via Web interface into new
-# Set platform types for each archive:
- .tar.bz2: Linux, Mac
- .tar.gz: BSD, Solaris, Others
- .zip: Windows
- Berlios:
-# Create the new release for the new version.
-# Provide @c NEWS file, as requested.
-# Upload files via FTP to ftp://ftp.berlios.de/incoming/
-# Edit descriptions for each file.
-# Click button to send E-mail Release Notice.
-# Post announcement e-mail to the openocd-development list.
-# Announce updates on freshmeat.net and other trackers.
-# Submit big updates to news feeds (e.g. Digg, Reddit, etc.).
To start a bug-fix release branch:
-# Create a new branch, starting from a major or
@@ -454,7 +399,7 @@ affect its behavior:
@section releasetutorial Release Tutorials
This section should contain a brief tutorial for using the Release
This section should contain a brief tutorial for using the Release
Script to perform release tasks, but the new script needs to be
used for 0.3.0.

View File

@@ -207,7 +207,7 @@ upon it, sometimes that is the only scheme available.
As a small group of developers, supporting all the platforms and
targets in the debugger will be difficult, as there are enough problem
with the plethora of Adapters, Chips, and different target boards.
with the plethora of Dongles, Chips, and different target boards.
Yes, the TCL interface might be suitable, but it has not received much
love or attention. Perhaps it will after you read and understand this.
@@ -235,7 +235,7 @@ different host-side GDB..
Sure - a <em>man on a mission</em> can make that work. The GUI might be
libopenocd + Perl/TK, or maybe an Eclipse Plug-in.
That is a development support nightmare for reasons described
above. We have enough support problems as it is with targets, adapters,
above. We have enough support problems as it is with targets, dongles,
etc.
@section serverdocshttpbg HTTP Server Background
@@ -270,8 +270,8 @@ every peripheral register on the target platform.
That also is transportable, regardless of the OpenOCD host
platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX.
You could even port OpenOCD to an Android system and use it as a
bit-banging JTAG Adapter serving web pages.
You could even port OpenOCD to an Google Android and use it as a
bit-bang dongle JTAG serving web pages.
@subsection serverdocshtmladv Advanced HTML Pages
@@ -309,3 +309,17 @@ This section needs to be expanded.
*/
/** @page serverhttp OpenOCD HTTP Server API
Smoketest:
configure --enable-httpd --enable-dummy --enable-ioutil
openocd -s /usr/local/share/openocd -f httpd/httpd.tcl -f interface/dummy.cfg -f target/lpc2148.cfg
Navigate to: http://localhost:8888/
*/

View File

@@ -66,9 +66,8 @@ Finally, try to avoid lines of code that are longer than than 72-80 columns:
- most identifiers must use lower-case letters (and digits) only.
- macros must use upper-case letters (and digits) only.
- OpenOCD identifiers should NEVER use @c MixedCaps.
- @c typedef names must end with the '_t' suffix.
- This should be reserved for types that should be passed by value.
- Do @b not mix the typedef keyword with @c struct.
- structure names must end with the '_s' suffix.
- typedef names must end with the '_t' suffix.
- use underline characters between consecutive words in identifiers
(e.g. @c more_than_one_word).
@@ -78,11 +77,8 @@ Finally, try to avoid lines of code that are longer than than 72-80 columns:
- @c // comments -- in new code, prefer these for single-line comments
- trailing comma allowed in enum declarations
- designated initializers (@{ .field = value @})
- variables declarations should occur at the point of first use
- variables declarations may be mixed with code
- new block scopes for selection and iteration statements
- use malloc() to create dynamic arrays. Do @b not use @c alloca
or variable length arrays on the stack. non-MMU hosts(uClinux) and
pthreads require modest and predictable stack usage.
@section styletypes Type Guidelines
- use native types (@c int or @c unsigned) if the type is not important
@@ -180,7 +176,7 @@ The following guidelines apply to all Doxygen comment blocks:
-# @c function_name() can be used to reference functions
(e.g. flash_set_dirty()).
-# @c struct_name::member_name should be used to reference structure
fields in the documentation (e.g. @c flash_driver::name).
fields in the documentation (e.g. @c flash_driver_s::name).
-# URLS get converted to markup automatically, without any extra effort.
-# new pages can be linked into the heirarchy by using the @c \@subpage
command somewhere the page(s) under which they should be linked:
@@ -308,7 +304,7 @@ For technical reference material:
- Else it's a "Config Command" if it must be used before the
configuration stage completes.
- For a "Driver", list its name.
- Use EBNF style regular expressions to define parameters:
- Use BNF style regular expressions to define parameters:
brackets around zero-or-one choices, parentheses around
exactly-one choices.
- Use \@option, \@file, \@var and other mechanisms where appropriate.

View File

@@ -1,4 +1,4 @@
.TH "OPENOCD" "1" "November 24, 2009"
.TH "OPENOCD" "1" "January 08, 2009"
.SH "NAME"
openocd \- A free and open on\-chip debugging, in\-system programming and
boundary\-scan testing tool for ARM and MIPS systems
@@ -22,23 +22,19 @@ please check the \fIopenocd\fR info page for the complete list.
.SH "OPTIONS"
.TP
.B "\-f, \-\-file <filename>"
This is a shortcut for a \fB\-c "[script \fI<filename>\fB]"\fR
command, using a search path to load the configuration file
.IR <filename> .
Use configuration file
.BR <filename> .
In order to specify multiple config files, you can use multiple
.B \-\-file
arguments. If no such \fB\-c\fR
options are included, the first config file
arguments. If this option is omitted, the config file
.B openocd.cfg
in the search path will be used.
in the current working directory will be used.
.TP
.B "\-s, \-\-search <dirname>"
Add
.I <dirname>
to the search path used for config files and scripts.
The search path begins with the current directory,
then includes these additional directories before other
components such as the standard OpenOCD script libraries.
Search for config files and scripts in the directory
.BR <dirname> .
If this option is omitted, OpenOCD searches for config files and scripts
in the current directory.
.TP
.B "\-d, \-\-debug <debuglevel>"
Set debug level. Possible values are:
@@ -56,17 +52,13 @@ The default level is
.TP
.B "\-l, \-\-log_output <filename>"
Redirect log output to the file
.IR <filename> .
.BR <filename> .
Per default the log output is printed on
.BR stderr .
.TP
.B "\-c, \-\-command <cmd>"
Add the command
.I <cmd>
to a list of commands executed on server startup.
Note that you will need to explicitly invoke
.I init
if the command requires access to a target or flash.
Run the command
.BR <cmd> .
.TP
.B "\-p, \-\-pipe"
Use pipes when talking to gdb.
@@ -77,7 +69,9 @@ Show a help text and exit.
.B "\-v, \-\-version"
Show version information and exit.
.SH "BUGS"
Please report any bugs on the mailing list at
Please report any bugs at
.B http://developer.berlios.de/bugs/?group_id=4148
or on the mailing list
.BR openocd\-development@lists.berlios.de .
.SH "LICENCE"
.B OpenOCD
@@ -96,6 +90,9 @@ and
programs are properly installed at your site, the command
.B info openocd
should give you access to the complete manual.
.PP
Also, the OpenOCD wiki contains some more information and examples:
.B http://openfacts.berlios.de/index-en.phtml?title=Open_On-Chip_Debugger
.SH "AUTHORS"
Please see the file AUTHORS.
.PP

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
Some of these binaries are build & linked using eCos.
Some of these binaries are build & linked using eCos.
For source for the flash drivers, see:

1
jimtcl

Submodule jimtcl deleted from 411e92fea9

View File

@@ -1,16 +1,4 @@
include $(top_srcdir)/common.mk
SUBDIRS = \
jtag \
helper \
target \
transport \
flash \
svf \
xsvf \
pld \
server \
rtos
SUBDIRS = helper jtag xsvf svf target server flash pld
lib_LTLIBRARIES = libopenocd.la
bin_PROGRAMS = openocd
@@ -24,20 +12,19 @@ endif
openocd_SOURCES = $(MAINFILE)
openocd_LDADD = libopenocd.la
if INTERNAL_JIMTCL
openocd_LDADD += $(top_builddir)/jimtcl/libjim.a
else
openocd_LDADD += -ljim
endif
libopenocd_la_SOURCES = openocd.c
libopenocd_la_SOURCES = \
hello.c \
openocd.c \
startup_tcl.c
noinst_HEADERS = \
hello.h \
openocd.h
# set the include path found by configure
AM_CPPFLAGS = \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/helper \
-I$(top_srcdir)/src/jtag \
-I$(top_srcdir)/src/target \
-I$(top_srcdir)/src/xsvf \
-I$(top_srcdir)/src/svf \
-I$(top_srcdir)/src/server \
-I$(top_srcdir)/src/flash \
-I$(top_srcdir)/src/pld
libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\"
@@ -48,7 +35,6 @@ libopenocd_la_CPPFLAGS += -DRELSTR=\"\"
else
libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\"
endif
libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\"
# add default CPPFLAGS
libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS)
@@ -65,16 +51,12 @@ endif
if FT2232_LIBFTDI
FTDI2232LIB = -lftdi -lusb
else
if USB_BLASTER_LIBFTDI
FTDI2232LIB = -lftdi -lusb
else
if PRESTO_LIBFTDI
FTDI2232LIB = -lftdi -lusb
else
FTDI2232LIB =
endif
endif
endif
if USBPROG
LIBUSB = -lusb
@@ -85,9 +67,6 @@ else
if RLINK
LIBUSB = -lusb
else
if ULINK
LIBUSB = -lusb
else
if VSLLINK
LIBUSB = -lusb
else
@@ -96,48 +75,22 @@ endif
endif
endif
endif
endif
libopenocd_la_LIBADD = \
$(top_builddir)/src/xsvf/libxsvf.la \
$(top_builddir)/src/svf/libsvf.la \
$(top_builddir)/src/pld/libpld.la \
$(top_builddir)/src/jtag/libjtag.la \
$(top_builddir)/src/transport/libtransport.la \
$(top_builddir)/src/flash/libflash.la \
$(top_builddir)/src/target/libtarget.la \
$(top_builddir)/src/server/libserver.la \
$(top_builddir)/src/rtos/librtos.la \
$(top_builddir)/src/helper/libhelper.la \
$(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB)
STARTUP_TCL_SRCS = \
$(srcdir)/helper/startup.tcl \
$(srcdir)/jtag/startup.tcl \
$(srcdir)/target/startup.tcl \
$(srcdir)/flash/startup.tcl \
$(srcdir)/server/startup.tcl
if HTTPD
libopenocd_la_LIBADD += -lmicrohttpd
endif
EXTRA_DIST = $(STARTUP_TCL_SRCS)
BUILT_SOURCES = startup.tcl
startup.tcl: $(STARTUP_TCL_SRCS)
cat $^ > $@
BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD)
# Convert .tcl to cfile
startup_tcl.c: startup.tcl $(BIN2C)
$(BIN2C) openocd_startup_tcl < $< > $@ || rm -f $@
# add startup_tcl.c to make clean list
CLEANFILES = startup.tcl startup_tcl.c
# we do not want generated file in the dist
dist-hook:
rm -f $(distdir)/startup_tcl.c
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
# The "quick" target builds executables & reinstalls the executables

View File

@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2007-2010 by Øyvind Harboe *
* Copyright (C) 2007-2008 by Øyvind Harboe *
* *
* 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 *
@@ -21,19 +21,23 @@
#include "config.h"
#endif
#include <helper/types.h>
#include <jtag/jtag.h>
#include <helper/ioutil.h>
#include <helper/util.h>
#include <helper/configuration.h>
#include "log.h"
#include "types.h"
#include "jtag.h"
#include "configuration.h"
#include "xsvf.h"
#include "svf.h"
#include "target.h"
#include "flash.h"
#include "nand.h"
#include "pld.h"
#include <server/server.h>
#include <server/telnet_server.h>
#include <server/gdb_server.h>
#include <openocd.h>
#include <helper/time_support.h>
#include "command.h"
#include "server.h"
#include "telnet_server.h"
#include "gdb_server.h"
#include <time_support.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
@@ -55,20 +59,29 @@
#include <cyg/athttpd/cgi.h>
#include <cyg/athttpd/forms.h>
#include <cyg/discover/discover.h>
#include <cyg/io/io.h>
#include <cyg/io/serialio.h>
#include <netinet/tcp.h>
#include <cyg/hal/hal_diag.h>
#include <cyg/kernel/kapi.h>
#include <cyg/io/serialio.h>
#include <cyg/io/io.h>
#include <netinet/tcp.h>
#include "rom.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <ifaddrs.h>
#include <string.h>
#ifdef CYGPKG_HAL_NIOS2
#include <cyg/hal/io.h>
#define ZY1000_SER_DEV "/dev/uart_0"
#else
#define ZY1000_SER_DEV "/dev/ser0"
#endif
#include <unistd.h>
#include <stdio.h>
#define MAX_IFS 64
@@ -100,6 +113,10 @@ static bool writeLog = true;
char hwaddr[512];
extern flash_driver_t *flash_drivers[];
extern target_type_t *target_types[];
#ifdef CYGPKG_PROFILE_GPROF
#include <cyg/profile/profile.h>
@@ -143,14 +160,7 @@ static void zylinjtag_reboot(cyg_addrword_t data)
diag_printf("Unmounting /config..\n");
umount("/config");
diag_printf("Rebooting..\n");
#ifdef CYGPKG_HAL_NIOS2
/* This will reboot & reconfigure the FPGA from the bootloader
* and on.
*/
IOWR(REMOTE_UPDATE_BASE, 0x20, 0x1);
#else
HAL_PLATFORM_RESET();
#endif
}
static cyg_thread zylinjtag_thread_object;
static cyg_handle_t zylinjtag_thread_handle;
@@ -219,7 +229,7 @@ void reboot_port(void)
cyg_thread_resume(zylinjtag_reboot_port_thread_handle);
}
int configuration_output_handler(struct command_context *context,
int configuration_output_handler(struct command_context_s *context,
const char* line)
{
diag_printf("%s", line);
@@ -227,7 +237,7 @@ int configuration_output_handler(struct command_context *context,
return ERROR_OK;
}
int zy1000_configuration_output_handler_log(struct command_context *context,
int zy1000_configuration_output_handler_log(struct command_context_s *context,
const char* line)
{
LOG_USER_N("%s", line);
@@ -236,21 +246,11 @@ int zy1000_configuration_output_handler_log(struct command_context *context,
}
#ifdef CYGPKG_PROFILE_GPROF
//extern int64_t totaltime;
static int zylinjtag_Jim_Command_profile(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
int eCosBoard_handle_eCosBoard_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
if ((argc == 2) && (strcmp(Jim_GetString(argv[1], NULL), "stats")==0))
{
// profile_off();
//LOG_USER("Stats %dms sleeping in select()", (int)totaltime);
} else
{
LOG_USER("Profiling started");
start_profile();
//totaltime = 0;
}
command_print(cmd_ctx, "Profiling started");
start_profile();
return ERROR_OK;
}
@@ -258,7 +258,7 @@ static int zylinjtag_Jim_Command_profile(Jim_Interp *interp, int argc,
externC void phi_init_all_network_interfaces(void);
struct command_context *cmd_ctx;
command_context_t *cmd_ctx;
static bool webRunning = false;
@@ -474,6 +474,7 @@ static int zylinjtag_Jim_Command_reboot(Jim_Interp *interp, int argc,
return JIM_OK;
}
static void zylinjtag_startNetwork(void)
{
// Bring TCP/IP up immediately before we're ready to accept commands.
@@ -500,9 +501,7 @@ static void zylinjtag_startNetwork(void)
cyg_httpd_init_tcl_interpreter();
// Kludge! Why can't I do this from httpd.c??? I get linker errors...
// some of that --start/end-group stuff?
Jim_InitStaticExtensions(httpstate.jim_interp);
interp = httpstate.jim_interp;
Jim_CreateCommand(httpstate.jim_interp, "log", zylinjtag_Jim_Command_log,
NULL, NULL);
@@ -592,7 +591,6 @@ static void print_exception_handler(cyg_addrword_t data, cyg_code_t exception,
}
#ifdef CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION
static void setHandler(cyg_code_t exception)
{
cyg_exception_handler_t *old_handler;
@@ -601,7 +599,6 @@ static void setHandler(cyg_code_t exception)
cyg_exception_set_handler(exception, print_exception_handler, 0,
&old_handler, &old_data);
}
#endif
static cyg_thread zylinjtag_uart_thread_object;
static cyg_handle_t zylinjtag_uart_thread_handle;
@@ -689,7 +686,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
int oldopts = fcntl(session, F_GETFL, 0);
fcntl(session, F_SETFL, oldopts | O_NONBLOCK); //
int serHandle = open(ZY1000_SER_DEV, O_RDWR | O_NONBLOCK);
int serHandle = open("/dev/ser0", O_RDWR | O_NONBLOCK);
if (serHandle < 0)
{
close(session);
@@ -751,6 +748,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
pos2 = 0;
}
size_t x = actual2;
size_t y = 0;
if (actual2 > 0)
{
@@ -780,6 +778,7 @@ static void zylinjtag_uart(cyg_addrword_t data)
actual += t;
}
int x2 = actual;
int y2 = 0;
if (actual > 0)
{
@@ -842,25 +841,21 @@ void startUart(void)
cyg_thread_resume(zylinjtag_uart_thread_handle);
}
static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
Jim_Obj * const *argv)
int handle_uart_command(struct command_context_s *cmd_ctx, char *cmd,
char **args, int argc)
{
static int current_baud = 38400;
if (argc == 1)
if (argc == 0)
{
Jim_SetResult(interp, Jim_NewIntObj(interp, current_baud));
return JIM_OK;
command_print(cmd_ctx, "%d", current_baud);
return ERROR_OK;
}
else if (argc != 2)
else if (argc != 1)
{
return JIM_ERR;
return ERROR_INVALID_ARGUMENTS;
}
long new_baudrate;
if (Jim_GetLong(interp, argv[1], &new_baudrate) != JIM_OK)
return JIM_ERR;
current_baud = new_baudrate;
current_baud = atol(args[0]);
int baud;
switch (current_baud)
@@ -884,8 +879,8 @@ static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
baud = CYGNUM_SERIAL_BAUD_230400;
break;
default:
Jim_SetResult(interp, Jim_NewStringObj(interp, "unsupported baudrate", -1));
return JIM_ERR;
command_print(cmd_ctx, "unsupported baudrate");
return ERROR_INVALID_ARGUMENTS;
}
cyg_serial_info_t buf;
@@ -895,11 +890,11 @@ static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
int err;
cyg_io_handle_t serial_handle;
err = cyg_io_lookup(ZY1000_SER_DEV, &serial_handle);
err = cyg_io_lookup("/dev/ser0", &serial_handle);
if (err != ENOERR)
{
Jim_SetResult(interp, Jim_NewStringObj(interp, "Could not open serial port", -1));
return JIM_ERR;
LOG_ERROR("/dev/ser0 not found\n");
return ERROR_FAIL;
}
err = cyg_io_get_config(serial_handle,
@@ -908,8 +903,8 @@ static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
&len);
if (err != ENOERR)
{
Jim_SetResult(interp, Jim_NewStringObj(interp, "Failed to get serial port settings", -1));
return JIM_ERR;
command_print(cmd_ctx, "Failed to get serial port settings %d", err);
return ERROR_OK;
}
buf.baud = baud;
@@ -917,11 +912,11 @@ static int zylinjtag_Jim_Command_uart(Jim_Interp *interp, int argc,
&len);
if (err != ENOERR)
{
Jim_SetResult(interp, Jim_NewStringObj(interp, "Failed to set serial port settings", -1));
return JIM_ERR;
command_print(cmd_ctx, "Failed to set serial port settings %d", err);
return ERROR_OK;
}
return JIM_OK;
return ERROR_OK;
}
bool logAllToSerial = false;
@@ -930,6 +925,8 @@ bool logAllToSerial = false;
int boolParam(char *var);
command_context_t *setup_command_handler(void);
static const char *zylin_config_dir="/config/settings";
static int add_default_dirs(void)
@@ -940,6 +937,8 @@ static int add_default_dirs(void)
return ERROR_OK;
}
int ioutil_init(struct command_context_s *cmd_ctx);
int main(int argc, char *argv[])
{
/* ramblockdevice will be the same address every time. The deflate app uses a buffer 16mBytes out, so we
@@ -957,11 +956,7 @@ int main(int argc, char *argv[])
diag_init_putc(_zylinjtag_diag_write_char);
// We want this in the log.
#ifdef CYGPKG_HAL_NIOS2
diag_printf("Zylin ZY1000 PCB revc.\n");
#else
diag_printf("Zylin ZY1000 PCB revb.\n");
#endif
diag_printf("Zylin ZY1000.\n");
err = mount("", "/ram", "ramfs");
if (err < 0)
@@ -1000,20 +995,6 @@ int main(int argc, char *argv[])
copydir("/rom", "/ram/cgi");
#ifdef CYGPKG_HAL_NIOS2
cyg_flashaddr_t err_address;
#define UNCACHED_EXT_FLASH_BASE (0x80000000 + EXT_FLASH_BASE)
/* The revc flash is locked upon reset, unlock it */
#ifdef CYGHWR_IO_FLASH_BLOCK_LOCKING
if ((err = flash_unlock((void *) UNCACHED_EXT_FLASH_BASE, EXT_FLASH_SPAN,
(void **) &err_address)) != 0)
{
diag_printf("Error: could not unlock flash\n");
}
#endif
#endif
err = mount("/dev/flash1", "/config", "jffs2");
if (err < 0)
{
@@ -1088,27 +1069,34 @@ int main(int argc, char *argv[])
add_default_dirs();
/* initialize commandline interface */
struct command_context * cmd_ctx;
struct command_context *setup_command_handler(Jim_Interp *interp);
cmd_ctx = setup_command_handler(httpstate.jim_interp);
command_context_t * cmd_ctx;
cmd_ctx = setup_command_handler();
command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);
command_context_mode(cmd_ctx, COMMAND_CONFIG);
if (util_init(cmd_ctx) != ERROR_OK)
return EXIT_FAILURE;
#if BUILD_IOUTIL
if (ioutil_init(cmd_ctx) != ERROR_OK)
{
return EXIT_FAILURE;
#ifdef CYGPKG_PROFILE_GPROF
Jim_CreateCommand(httpstate.jim_interp, "zy1000_profile", zylinjtag_Jim_Command_profile,
NULL, NULL);
}
#endif
Jim_CreateCommand(httpstate.jim_interp, "zy1000_uart", zylinjtag_Jim_Command_uart, NULL, NULL);
#ifdef CYGPKG_PROFILE_GPROF
register_command(cmd_ctx, NULL, "ecosboard_profile", eCosBoard_handle_eCosBoard_profile_command,
COMMAND_ANY, NULL);
#endif
log_init();
register_command(cmd_ctx, NULL, "uart", handle_uart_command, COMMAND_ANY,
"uart <baud> - forward uart on port 5555");
int errVal;
errVal = log_init(cmd_ctx);
if (errVal != ERROR_OK)
{
diag_printf("log_init() failed %d\n", errVal);
exit(-1);
}
set_log_output(cmd_ctx, log);
@@ -1125,11 +1113,6 @@ int main(int argc, char *argv[])
command_run_linef(cmd_ctx, "script /rom/openocd.cfg");
int ret;
ret = server_init(cmd_ctx);
if (ERROR_OK != ret)
return EXIT_FAILURE;
/* we MUST always run the init command as it will launch telnet sessions */
command_run_line(cmd_ctx, "init");
@@ -1281,7 +1264,6 @@ struct Tftp
cyg_uint8 *mem;
int actual;
char *server;
int port;
char *file;
};
@@ -1338,15 +1320,6 @@ static int tftpfs_open(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
strncpy(tftp->server, name, server - name);
tftp->server[server - name] = 0;
tftp->port = 0; /* default port 69 */
char *port;
port = strchr(tftp->server, ':');
if (port != NULL)
{
tftp->port = atoi(port + 1);
*port = 0;
}
tftp->file = strdup(server + 1);
if (tftp->file == NULL)
{
@@ -1364,7 +1337,7 @@ static int fetchTftp(struct Tftp *tftp)
if (!tftp->readFile)
{
int err;
tftp->actual = tftp_client_get(tftp->file, tftp->server, tftp->port, tftp->mem,
tftp->actual = tftp_client_get(tftp->file, tftp->server, 0, tftp->mem,
tftpMaxSize, TFTP_OCTET, &err);
if (tftp->actual < 0)

View File

@@ -1,23 +1,70 @@
include $(top_srcdir)/common.mk
SUBDIRS = \
nor \
nand
AM_CPPFLAGS = \
-I$(top_srcdir)/src/helper \
-I$(top_srcdir)/src/jtag \
-I$(top_srcdir)/src/target
METASOURCES = AUTO
noinst_LTLIBRARIES = libflash.la
libflash_la_SOURCES = \
common.c \
mflash.c
libflash_la_LIBADD = \
$(top_builddir)/src/flash/nor/libocdflashnor.la \
$(top_builddir)/src/flash/nand/libocdflashnand.la
arm_nandio.c \
flash.c \
lpc2000.c \
lpc288x.c \
lpc2900.c \
cfi.c \
non_cfi.c \
at91sam7.c \
at91sam3.c \
davinci_nand.c \
str7x.c \
str9x.c \
aduc702x.c \
nand.c \
nand_ecc.c \
nand_ecc_kw.c \
lpc3180_nand_controller.c \
stellaris.c \
str9xpec.c \
stm32x.c \
tms470.c \
ecos.c \
orion_nand.c \
s3c24xx_nand.c \
s3c2410_nand.c \
s3c2412_nand.c \
s3c2440_nand.c \
s3c2443_nand.c \
ocl.c \
mflash.c \
pic32mx.c \
avrf.c \
faux.c \
mx3_nand.c
noinst_HEADERS = \
common.h \
mflash.h
EXTRA_DIST = startup.tcl
arm_nandio.h \
flash.h \
lpc2000.h \
lpc288x.h \
lpc2900.h \
cfi.h \
non_cfi.h \
at91sam7.h \
at91sam3.h \
str7x.h \
str9x.h \
nand.h \
lpc3180_nand_controller.h \
stellaris.h \
str9xpec.h \
stm32x.h \
tms470.h \
s3c24xx_nand.h \
s3c24xx_regs_nand.h \
mflash.h \
ocl.h \
pic32mx.h \
avrf.h \
mx3_nand.h
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@@ -23,16 +23,25 @@
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <helper/time_support.h>
#include <target/algorithm.h>
#include <target/arm.h>
#include "flash.h"
#include "armv4_5.h"
#include "binarybuffer.h"
#include "time_support.h"
static int aduc702x_build_sector_list(struct flash_bank *bank);
static int aduc702x_check_flash_completion(struct target* target, unsigned int timeout_ms);
static int aduc702x_set_write_enable(struct target *target, int enable);
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int aduc702x_register_commands(struct command_context_s *cmd_ctx);
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last);
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last);
static int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int aduc702x_probe(struct flash_bank_s *bank);
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size);
static int aduc702x_protect_check(struct flash_bank_s *bank);
static int aduc702x_build_sector_list(struct flash_bank_s *bank);
static int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms);
static int aduc702x_set_write_enable(target_t *target, int enable);
#define ADUC702x_FLASH 0xfffff800
#define ADUC702x_FLASH_FEESTA (0*4)
@@ -44,17 +53,49 @@ static int aduc702x_set_write_enable(struct target *target, int enable);
#define ADUC702x_FLASH_FEEPRO (6*4)
#define ADUC702x_FLASH_FEEHIDE (7*4)
struct aduc702x_flash_bank {
struct working_area *write_algorithm;
typedef struct {
uint32_t feesta;
uint32_t feemod;
uint32_t feecon;
uint32_t feedat;
uint32_t feeadr;
uint32_t feesign;
uint32_t feepro;
uint32_t feehide;
} ADUC702x_FLASH_MMIO;
typedef struct
{
working_area_t *write_algorithm;
} aduc702x_flash_bank_t;
flash_driver_t aduc702x_flash =
{
.name = "aduc702x",
.register_commands = aduc702x_register_commands,
.flash_bank_command = aduc702x_flash_bank_command,
.erase = aduc702x_erase,
.protect = aduc702x_protect,
.write = aduc702x_write,
.probe = aduc702x_probe,
.auto_probe = aduc702x_probe,
.erase_check = default_flash_blank_check,
.protect_check = aduc702x_protect_check,
.info = aduc702x_info
};
static int aduc702x_register_commands(struct command_context_s *cmd_ctx)
{
return ERROR_OK;
}
/* flash bank aduc702x 0 0 0 0 <target#>
* The ADC7019-28 devices all have the same flash layout */
FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
static int aduc702x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct aduc702x_flash_bank *nbank;
aduc702x_flash_bank_t *nbank;
nbank = malloc(sizeof(struct aduc702x_flash_bank));
nbank = malloc(sizeof(aduc702x_flash_bank_t));
bank->base = 0x80000;
bank->size = 0xF800; // top 4k not accessible
@@ -65,16 +106,16 @@ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command)
return ERROR_OK;
}
static int aduc702x_build_sector_list(struct flash_bank *bank)
static int aduc702x_build_sector_list(struct flash_bank_s *bank)
{
//aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv;
//aduc7026_flash_bank_t *aduc7026_info = bank->driver_priv;
int i = 0;
uint32_t offset = 0;
// sector size is 512
bank->num_sectors = bank->size / 512;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
for (i = 0; i < bank->num_sectors; ++i)
{
bank->sectors[i].offset = offset;
@@ -87,37 +128,37 @@ static int aduc702x_build_sector_list(struct flash_bank *bank)
return ERROR_OK;
}
static int aduc702x_protect_check(struct flash_bank *bank)
static int aduc702x_protect_check(struct flash_bank_s *bank)
{
printf("aduc702x_protect_check not implemented yet.\n");
return ERROR_OK;
}
static int aduc702x_erase(struct flash_bank *bank, int first, int last)
static int aduc702x_erase(struct flash_bank_s *bank, int first, int last)
{
//int res;
int x;
int count;
//uint32_t v;
struct target *target = bank->target;
target_t *target = bank->target;
aduc702x_set_write_enable(target, 1);
/* mass erase */
if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) {
LOG_DEBUG("performing mass erase.");
LOG_DEBUG("performing mass erase.\n");
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff);
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3);
target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06);
if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK)
{
LOG_ERROR("mass erase failed");
LOG_ERROR("mass erase failed\n");
aduc702x_set_write_enable(target, 0);
return ERROR_FLASH_OPERATION_FAILED;
}
LOG_DEBUG("mass erase successful.");
LOG_DEBUG("mass erase successful.\n");
return ERROR_OK;
} else {
unsigned long adr;
@@ -132,12 +173,12 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
if (aduc702x_check_flash_completion(target, 50) != ERROR_OK)
{
LOG_ERROR("failed to erase sector at address 0x%08lX", adr);
LOG_ERROR("failed to erase sector at address 0x%08lX\n", adr);
aduc702x_set_write_enable(target, 0);
return ERROR_FLASH_SECTOR_NOT_ERASED;
}
LOG_DEBUG("erased sector at address 0x%08lX", adr);
LOG_DEBUG("erased sector at address 0x%08lX\n", adr);
}
}
@@ -146,7 +187,7 @@ static int aduc702x_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last)
static int aduc702x_protect(struct flash_bank_s *bank, int set, int first, int last)
{
printf("aduc702x_protect not implemented yet.\n");
return ERROR_FLASH_OPERATION_FAILED;
@@ -157,15 +198,15 @@ static int aduc702x_protect(struct flash_bank *bank, int set, int first, int las
*
* Caller should not check for other return values specifically
*/
static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int aduc702x_write_block(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct aduc702x_flash_bank *aduc702x_info = bank->driver_priv;
struct target *target = bank->target;
aduc702x_flash_bank_t *aduc702x_info = bank->driver_priv;
target_t *target = bank->target;
uint32_t buffer_size = 7000;
struct working_area *source;
working_area_t *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[6];
struct arm_algorithm armv4_5_info;
reg_param_t reg_params[6];
armv4_5_algorithm_t armv4_5_info;
int retval = ERROR_OK;
if (((count%2)!=0)||((offset%2)!=0))
@@ -188,7 +229,7 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
r6 - set to 2, used to write flash command
*/
static const uint32_t aduc702x_flash_write_code[] = {
uint32_t aduc702x_flash_write_code[] = {
//<_start>:
0xe3a05008, // mov r5, #8 ; 0x8
0xe5845004, // str r5, [r4, #4]
@@ -227,7 +268,7 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
}
/* memory buffer */
while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
{
buffer_size /= 2;
if (buffer_size <= 256)
@@ -241,9 +282,9 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
}
}
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
armv4_5_info.core_mode = ARM_MODE_SVC;
armv4_5_info.core_state = ARM_STATE_ARM;
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
@@ -302,11 +343,11 @@ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32
/* All-JTAG, single-access method. Very slow. Used only if there is no
* working area available. */
static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int aduc702x_write_single(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
uint32_t x;
uint8_t b;
struct target *target = bank->target;
target_t *target = bank->target;
aduc702x_set_write_enable(target, 1);
@@ -330,20 +371,20 @@ static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint3
if (aduc702x_check_flash_completion(target, 1) != ERROR_OK)
{
LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x));
LOG_ERROR("single write failed for address 0x%08lX\n", (unsigned long)(offset + x));
aduc702x_set_write_enable(target, 0);
return ERROR_FLASH_OPERATION_FAILED;
}
}
LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x));
LOG_DEBUG("wrote %d bytes at address 0x%08lX\n", (int)count, (unsigned long)(offset + x));
aduc702x_set_write_enable(target, 0);
return ERROR_OK;
}
static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
int aduc702x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
@@ -367,12 +408,12 @@ static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
return retval;
}
static int aduc702x_probe(struct flash_bank *bank)
static int aduc702x_probe(struct flash_bank_s *bank)
{
return ERROR_OK;
}
static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
static int aduc702x_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "aduc702x flash driver info");
return ERROR_OK;
@@ -380,7 +421,7 @@ static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size)
/* sets FEEMOD bit 3
* enable = 1 enables writes & erases, 0 disables them */
static int aduc702x_set_write_enable(struct target *target, int enable)
static int aduc702x_set_write_enable(target_t *target, int enable)
{
// don't bother to preserve int enable bit here
target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0);
@@ -393,7 +434,7 @@ static int aduc702x_set_write_enable(struct target *target, int enable)
*
* this function sleeps 1ms between checks (after the first one),
* so in some cases may slow things down without a usleep after the first read */
static int aduc702x_check_flash_completion(struct target* target, unsigned int timeout_ms)
static int aduc702x_check_flash_completion(target_t* target, unsigned int timeout_ms)
{
uint8_t v = 4;
@@ -411,16 +452,3 @@ static int aduc702x_check_flash_completion(struct target* target, unsigned int t
else return ERROR_OK;
}
struct flash_driver aduc702x_flash = {
.name = "aduc702x",
.flash_bank_command = aduc702x_flash_bank_command,
.erase = aduc702x_erase,
.protect = aduc702x_protect,
.write = aduc702x_write,
.read = default_flash_read,
.probe = aduc702x_probe,
.auto_probe = aduc702x_probe,
.erase_check = default_flash_blank_check,
.protect_check = aduc702x_protect_check,
.info = aduc702x_info
};

134
src/flash/arm_nandio.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2009 by Marvell Semiconductors, Inc.
* Written by Nicolas Pitre <nico at marvell.com>
*
* Copyright (C) 2009 by David Brownell
*
* 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 "arm_nandio.h"
#include "armv4_5.h"
/*
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
* For now this only supports ARMv4 and ARMv5 cores.
*
* Enhancements to target_run_algorithm() could enable:
* - ARMv6 and ARMv7 cores in ARM mode
*
* Different code fragments could handle:
* - Thumb2 cores like Cortex-M (needs different byteswapping)
* - 16-bit wide data (needs different setup too)
*/
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
{
target_t *target = nand->target;
armv4_5_algorithm_t algo;
armv4_5_common_t *armv4_5 = target->arch_info;
reg_param_t reg_params[3];
uint32_t target_buf;
uint32_t exit = 0;
int retval;
/* Inputs:
* r0 NAND data address (byte wide)
* r1 buffer address
* r2 buffer length
*/
static const uint32_t code[] = {
0xe4d13001, /* s: ldrb r3, [r1], #1 */
0xe5c03000, /* strb r3, [r0] */
0xe2522001, /* subs r2, r2, #1 */
0x1afffffb, /* bne s */
/* exit: ARMv4 needs hardware breakpoint */
0xe1200070, /* e: bkpt #0 */
};
if (!nand->copy_area) {
uint8_t code_buf[sizeof(code)];
unsigned i;
/* make sure we have a working area */
if (target_alloc_working_area(target,
sizeof(code) + nand->chunk_size,
&nand->copy_area) != ERROR_OK) {
LOG_DEBUG("%s: no %d byte buffer",
__FUNCTION__,
(int) sizeof(code) + nand->chunk_size);
return ERROR_NAND_NO_BUFFER;
}
/* buffer code in target endianness */
for (i = 0; i < sizeof(code) / 4; i++)
target_buffer_set_u32(target, code_buf + i * 4, code[i]);
/* copy code to work area */
retval = target_write_memory(target,
nand->copy_area->address,
4, sizeof(code) / 4, code_buf);
if (retval != ERROR_OK)
return retval;
}
/* copy data to work area */
target_buf = nand->copy_area->address + sizeof(code);
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
if (retval == ERROR_OK && (size & 3) != 0)
retval = target_write_memory(target,
target_buf + (size & ~3),
1, size & 3, data + (size & ~3));
if (retval != ERROR_OK)
return retval;
/* set up algorithm and parameters */
algo.common_magic = ARMV4_5_COMMON_MAGIC;
algo.core_mode = ARMV4_5_MODE_SVC;
algo.core_state = ARMV4_5_STATE_ARM;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
buf_set_u32(reg_params[0].value, 0, 32, nand->data);
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
buf_set_u32(reg_params[2].value, 0, 32, size);
/* armv4 must exit using a hardware breakpoint */
if (armv4_5->is_armv4)
exit = nand->copy_area->address + sizeof(code) - 4;
/* use alg to write data from work area to NAND chip */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
nand->copy_area->address, exit, 1000, &algo);
if (retval != ERROR_OK)
LOG_ERROR("error executing hosted NAND write");
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
return retval;
}
/* REVISIT do the same for bulk *read* too ... */

25
src/flash/arm_nandio.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef __ARM_NANDIO_H
#define __ARM_NANDIO_H
#include "nand.h"
#include "binarybuffer.h"
struct arm_nand_data {
/* target is proxy for some ARM core */
struct target_s *target;
/* copy_area holds write-to-NAND loop and data to write */
struct working_area_s *copy_area;
/* chunk_size == page or ECC unit */
unsigned chunk_size;
/* data == where to write the data */
uint32_t data;
/* currently implicit: data width == 8 bits (not 16) */
};
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size);
#endif /* __ARM_NANDIO_H */

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* Copyright (C) 2009 by Duane Ellis *
* openocd@duaneellis.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 *
@@ -18,9 +18,6 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef __COMMON_H
#define __COMMON_H
#define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n))
#endif
// nothing to do here other then export this.
extern flash_driver_t at91sam3_flash;

View File

@@ -49,63 +49,41 @@
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include "at91sam7.h"
#include "binarybuffer.h"
/* AT91SAM7 control registers */
#define DBGU_CIDR 0xFFFFF240
#define CKGR_MCFR 0xFFFFFC24
#define CKGR_MOR 0xFFFFFC20
#define CKGR_MCFR_MAINRDY 0x10000
#define CKGR_PLLR 0xFFFFFC2c
#define CKGR_PLLR_DIV 0xff
#define CKGR_PLLR_MUL 0x07ff0000
#define PMC_MCKR 0xFFFFFC30
#define PMC_MCKR_CSS 0x03
#define PMC_MCKR_PRES 0x1c
static int at91sam7_register_commands(struct command_context_s *cmd_ctx);
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last);
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last);
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int at91sam7_probe(struct flash_bank_s *bank);
//static int at91sam7_auto_probe(struct flash_bank_s *bank);
static int at91sam7_erase_check(struct flash_bank_s *bank);
static int at91sam7_protect_check(struct flash_bank_s *bank);
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size);
/* 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
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number);
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode);
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen);
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
/* MC_FSR bit definitions */
#define MC_FSR_FRDY 1
#define MC_FSR_EOL 2
/* AT91SAM7 constants */
#define RC_FREQ 32000
/* Flash timing modes */
#define FMR_TIMING_NONE 0
#define FMR_TIMING_NVBITS 1
#define FMR_TIMING_FLASH 2
/* Flash size constants */
#define FLASH_SIZE_8KB 1
#define FLASH_SIZE_16KB 2
#define FLASH_SIZE_32KB 3
#define FLASH_SIZE_64KB 5
#define FLASH_SIZE_128KB 7
#define FLASH_SIZE_256KB 9
#define FLASH_SIZE_512KB 10
#define FLASH_SIZE_1024KB 12
#define FLASH_SIZE_2048KB 14
static int at91sam7_protect_check(struct flash_bank *bank);
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number);
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode);
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen);
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,
.auto_probe = at91sam7_probe,
.erase_check = at91sam7_erase_check,
.protect_check = at91sam7_protect_check,
.info = at91sam7_info
};
static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 };
static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 };
@@ -113,50 +91,6 @@ static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 };
static char * EPROC[8]= {"Unknown","ARM946-E","ARM7TDMI","Unknown","ARM920T","ARM926EJ-S","Unknown","Unknown"};
struct at91sam7_flash_bank
{
/* chip id register */
uint32_t cidr;
uint16_t cidr_ext;
uint16_t cidr_nvptyp;
uint16_t cidr_arch;
uint16_t cidr_sramsiz;
uint16_t cidr_nvpsiz;
uint16_t cidr_nvpsiz2;
uint16_t cidr_eproc;
uint16_t cidr_version;
const char *target_name;
/* flash auto-detection */
uint8_t flash_autodetection;
/* flash geometry */
uint16_t pages_per_sector;
uint16_t pagesize;
uint16_t pages_in_lockregion;
/* nv memory bits */
uint16_t num_lockbits_on;
uint16_t lockbits;
uint16_t num_nvmbits;
uint16_t num_nvmbits_on;
uint16_t nvmbits;
uint8_t securitybit;
/* 0: not init
* 1: fmcn for nvbits (1uS)
* 2: fmcn for flash (1.5uS) */
uint8_t flashmode;
/* main clock status */
uint8_t mck_valid;
uint32_t mck_freq;
/* external clock frequency */
uint32_t ext_freq;
};
#if 0
static long SRAMSIZ[16] = {
-1,
@@ -178,8 +112,16 @@ static long SRAMSIZ[16] = {
};
#endif
static int at91sam7_register_commands(struct command_context_s *cmd_ctx)
{
command_t *at91sam7_cmd = register_command(cmd_ctx, NULL, "at91sam7", NULL, COMMAND_ANY, NULL);
static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number)
register_command(cmd_ctx, at91sam7_cmd, "gpnvm", at91sam7_handle_gpnvm_command, COMMAND_EXEC,
"at91sam7 gpnvm <bit> set | clear, set or clear one gpnvm bit");
return ERROR_OK;
}
static uint32_t at91sam7_get_flash_status(target_t *target, int bank_number)
{
uint32_t fsr;
target_read_u32(target, MC_FSR[bank_number], &fsr);
@@ -188,10 +130,10 @@ static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number
}
/* Read clock configuration and set at91sam7_info->mck_freq */
static void at91sam7_read_clock_info(struct flash_bank *bank)
static void at91sam7_read_clock_info(flash_bank_t *bank)
{
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
struct target *target = bank->target;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
target_t *target = bank->target;
uint32_t mckr, mcfr, pllr, mor;
unsigned long tmp = 0, mainfreq;
@@ -267,11 +209,11 @@ static void at91sam7_read_clock_info(struct flash_bank *bank)
}
/* Setup the timimg registers for nvbits or normal flash */
static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
static void at91sam7_set_flash_mode(flash_bank_t *bank, int mode)
{
uint32_t fmr, fmcn = 0, fws = 0;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
struct target *target = bank->target;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
target_t *target = bank->target;
if (mode && (mode != at91sam7_info->flashmode))
{
@@ -315,7 +257,7 @@ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode)
at91sam7_info->flashmode = mode;
}
static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
static uint32_t at91sam7_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
{
uint32_t status;
@@ -342,11 +284,11 @@ static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t wait
}
/* Send one command to the AT91SAM flash controller */
static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen)
static int at91sam7_flash_command(struct flash_bank_s *bank, uint8_t cmd, uint16_t pagen)
{
uint32_t fcr;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
struct target *target = bank->target;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
target_t *target = bank->target;
fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd;
target_write_u32(target, MC_FCR[bank->bank_number], fcr);
@@ -371,11 +313,11 @@ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t
}
/* Read device id register, main clock frequency register and fill in driver info structure */
static int at91sam7_read_part_info(struct flash_bank *bank)
static int at91sam7_read_part_info(struct flash_bank_s *bank)
{
struct flash_bank *t_bank = bank;
struct at91sam7_flash_bank *at91sam7_info;
struct target *target = t_bank->target;
flash_bank_t *t_bank = bank;
at91sam7_flash_bank_t *at91sam7_info;
target_t *target = t_bank->target;
uint16_t bnk, sec;
uint16_t arch;
@@ -388,14 +330,14 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
uint32_t ext_freq;
uint32_t bank_size;
uint32_t base_address = 0;
char *target_name_t = "Unknown";
char *target_name = "Unknown";
at91sam7_info = t_bank->driver_priv;
if (at91sam7_info->cidr != 0)
{
/* flash already configured, update clock and check for protected sectors */
struct flash_bank *fb = bank;
flash_bank_t *fb = bank;
t_bank = fb;
while (t_bank)
@@ -427,7 +369,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (at91sam7_info->flash_autodetection == 0)
{
/* banks and sectors are already created, based on data from input file */
struct flash_bank *fb = bank;
flash_bank_t *fb = bank;
t_bank = fb;
while (t_bank)
{
@@ -476,7 +418,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S161/16";
target_name = "AT91SAM7S161/16";
}
break;
@@ -489,12 +431,12 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S321/32";
target_name = "AT91SAM7S321/32";
}
if (arch == 0x72)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7SE32";
target_name = "AT91SAM7SE32";
}
break;
@@ -507,7 +449,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S64";
target_name = "AT91SAM7S64";
}
break;
@@ -520,22 +462,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S128";
target_name = "AT91SAM7S128";
}
if (arch == 0x71)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7XC128";
target_name = "AT91SAM7XC128";
}
if (arch == 0x72)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7SE128";
target_name = "AT91SAM7SE128";
}
if (arch == 0x75)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7X128";
target_name = "AT91SAM7X128";
}
break;
@@ -548,27 +490,27 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x60)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7A3";
target_name = "AT91SAM7A3";
}
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S256";
target_name = "AT91SAM7S256";
}
if (arch == 0x71)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7XC256";
target_name = "AT91SAM7XC256";
}
if (arch == 0x72)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7SE256";
target_name = "AT91SAM7SE256";
}
if (arch == 0x75)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7X256";
target_name = "AT91SAM7X256";
}
break;
@@ -581,22 +523,22 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (arch == 0x70)
{
num_nvmbits = 2;
target_name_t = "AT91SAM7S512";
target_name = "AT91SAM7S512";
}
if (arch == 0x71)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7XC512";
target_name = "AT91SAM7XC512";
}
if (arch == 0x72)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7SE512";
target_name = "AT91SAM7SE512";
}
if (arch == 0x75)
{
num_nvmbits = 3;
target_name_t = "AT91SAM7X512";
target_name = "AT91SAM7X512";
}
break;
@@ -607,7 +549,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
break;
}
if (strcmp(target_name_t, "Unknown") == 0)
if (strcmp(target_name, "Unknown") == 0)
{
LOG_ERROR("Target autodetection failed! Please specify target parameters in configuration file");
return ERROR_FLASH_OPERATION_FAILED;
@@ -623,10 +565,10 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (bnk > 0)
{
/* create a new flash bank element */
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
flash_bank_t *fb = malloc(sizeof(flash_bank_t));
fb->target = target;
fb->driver = bank->driver;
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
fb->driver = &at91sam7_flash;
fb->driver_priv = malloc(sizeof(at91sam7_flash_bank_t));
fb->next = NULL;
/* link created bank in 'flash_banks' list and redirect t_bank */
@@ -642,7 +584,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
t_bank->num_sectors = sectors_num;
/* allocate sectors */
t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector));
t_bank->sectors = malloc(sectors_num * sizeof(flash_sector_t));
for (sec = 0; sec < sectors_num; sec++)
{
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
@@ -663,7 +605,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007;
at91sam7_info->cidr_version = cidr&0x001F;
at91sam7_info->target_name = target_name_t;
at91sam7_info->target_name = target_name;
at91sam7_info->flashmode = 0;
at91sam7_info->ext_freq = ext_freq;
at91sam7_info->num_nvmbits = num_nvmbits;
@@ -686,9 +628,9 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
return ERROR_OK;
}
static int at91sam7_erase_check(struct flash_bank *bank)
static int at91sam7_erase_check(struct flash_bank_s *bank)
{
struct target *target = bank->target;
target_t *target = bank->target;
uint16_t retval;
uint32_t blank;
uint16_t fast_check;
@@ -752,12 +694,12 @@ static int at91sam7_erase_check(struct flash_bank *bank)
return ERROR_OK;
}
static int at91sam7_protect_check(struct flash_bank *bank)
static int at91sam7_protect_check(struct flash_bank_s *bank)
{
uint8_t lock_pos, gpnvm_pos;
uint32_t status;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->cidr == 0)
{
@@ -802,15 +744,15 @@ static int at91sam7_protect_check(struct flash_bank *bank)
return ERROR_OK;
}
FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
static int at91sam7_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct flash_bank *t_bank = bank;
struct at91sam7_flash_bank *at91sam7_info;
struct target *target = t_bank->target;
flash_bank_t *t_bank = bank;
at91sam7_flash_bank_t *at91sam7_info;
target_t *target = t_bank->target;
uint32_t base_address;
uint32_t bank_size;
uint32_t ext_freq = 0;
uint32_t ext_freq;
int chip_width;
int bus_width;
@@ -821,11 +763,11 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
uint16_t page_size;
uint16_t num_nvmbits;
char *target_name_t;
char *target_name;
int bnk, sec;
at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank));
at91sam7_info = malloc(sizeof(at91sam7_flash_bank_t));
t_bank->driver_priv = at91sam7_info;
/* part wasn't probed for info yet */
@@ -834,39 +776,35 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
at91sam7_info->ext_freq = 0;
at91sam7_info->flash_autodetection = 0;
if (CMD_ARGC < 13)
if (argc == 14)
{
at91sam7_info->flash_autodetection = 1;
return ERROR_OK;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size);
COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits);
if (CMD_ARGC == 14) {
unsigned long freq;
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq);
ext_freq = freq * 1000;
ext_freq = atol(args[13]) * 1000;
at91sam7_info->ext_freq = ext_freq;
}
if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) ||
(pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0))
if ((argc != 14) ||
(atoi(args[4]) == 0) || /* bus width */
(atoi(args[8]) == 0) || /* banks number */
(atoi(args[9]) == 0) || /* sectors per bank */
(atoi(args[10]) == 0) || /* pages per sector */
(atoi(args[11]) == 0) || /* page size */
(atoi(args[12]) == 0)) /* nvmbits number */
{
at91sam7_info->flash_autodetection = 1;
return ERROR_OK;
}
target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char));
strcpy(target_name_t, CMD_ARGV[7]);
base_address = strtoul(args[1], NULL, 0);
chip_width = atoi(args[3]);
bus_width = atoi(args[4]);
banks_num = atoi(args[8]);
num_sectors = atoi(args[9]);
pages_per_sector = atoi(args[10]);
page_size = atoi(args[11]);
num_nvmbits = atoi(args[12]);
target_name = calloc(strlen(args[7]) + 1, sizeof(char));
strcpy(target_name, args[7]);
/* calculate bank size */
bank_size = num_sectors * pages_per_sector * page_size;
@@ -876,10 +814,10 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
if (bnk > 0)
{
/* create a new bank element */
struct flash_bank *fb = malloc(sizeof(struct flash_bank));
flash_bank_t *fb = malloc(sizeof(flash_bank_t));
fb->target = target;
fb->driver = bank->driver;
fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank));
fb->driver = &at91sam7_flash;
fb->driver_priv = malloc(sizeof(at91sam7_flash_bank_t));
fb->next = NULL;
/* link created bank in 'flash_banks' list and redirect t_bank */
@@ -895,7 +833,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
t_bank->num_sectors = num_sectors;
/* allocate sectors */
t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector));
t_bank->sectors = malloc(num_sectors * sizeof(flash_sector_t));
for (sec = 0; sec < num_sectors; sec++)
{
t_bank->sectors[sec].offset = sec * pages_per_sector * page_size;
@@ -906,7 +844,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
at91sam7_info = t_bank->driver_priv;
at91sam7_info->target_name = target_name_t;
at91sam7_info->target_name = target_name;
at91sam7_info->flashmode = 0;
at91sam7_info->ext_freq = ext_freq;
at91sam7_info->num_nvmbits = num_nvmbits;
@@ -918,9 +856,9 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
return ERROR_OK;
}
static int at91sam7_erase(struct flash_bank *bank, int first, int last)
static int at91sam7_erase(struct flash_bank_s *bank, int first, int last)
{
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
int sec;
uint32_t nbytes, pos;
uint8_t *buffer;
@@ -986,13 +924,13 @@ static int at91sam7_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last)
static int at91sam7_protect(struct flash_bank_s *bank, int set, int first, int last)
{
uint32_t cmd;
int sector;
uint32_t pagen;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->cidr == 0)
{
@@ -1036,11 +974,11 @@ static int at91sam7_protect(struct flash_bank *bank, int set, int first, int las
return ERROR_OK;
}
static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int at91sam7_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
int retval;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
struct target *target = bank->target;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
target_t *target = bank->target;
uint32_t dst_min_alignment, wcount, bytes_remaining = count;
uint32_t first_page, last_page, pagen, buffer_pos;
@@ -1070,7 +1008,7 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
return ERROR_FLASH_BANK_NOT_PROBED;
first_page = offset/dst_min_alignment;
last_page = DIV_ROUND_UP(offset + count, dst_min_alignment);
last_page = CEIL(offset + count, dst_min_alignment);
LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count);
@@ -1088,7 +1026,7 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
/* Write one block to the PageWriteBuffer */
buffer_pos = (pagen-first_page)*dst_min_alignment;
wcount = DIV_ROUND_UP(count,4);
wcount = CEIL(count,4);
if ((retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos)) != ERROR_OK)
{
return retval;
@@ -1105,7 +1043,7 @@ static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t off
return ERROR_OK;
}
static int at91sam7_probe(struct flash_bank *bank)
static 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 */
@@ -1124,10 +1062,10 @@ static int at91sam7_probe(struct flash_bank *bank)
return ERROR_OK;
}
static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
static int at91sam7_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
int printed;
struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv;
at91sam7_flash_bank_t *at91sam7_info = bank->driver_priv;
if (at91sam7_info->cidr == 0)
{
@@ -1189,18 +1127,18 @@ static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size)
* The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes
* Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit.
*/
COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
static int at91sam7_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
struct flash_bank *bank;
flash_bank_t *bank;
int bit;
uint8_t flashcmd;
uint32_t status;
struct at91sam7_flash_bank *at91sam7_info;
at91sam7_flash_bank_t *at91sam7_info;
int retval;
if (CMD_ARGC != 2)
if (argc != 2)
{
command_print(CMD_CTX, "at91sam7 gpnvm <bit> <set | clear>");
command_print(cmd_ctx, "at91sam7 gpnvm <bit> <set | clear>");
return ERROR_OK;
}
@@ -1209,9 +1147,9 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
{
return ERROR_FLASH_BANK_INVALID;
}
if (strcmp(bank->driver->name, "at91sam7"))
if (bank->driver != &at91sam7_flash)
{
command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]);
command_print(cmd_ctx, "not an at91sam7 flash bank '%s'", args[0]);
return ERROR_FLASH_BANK_INVALID;
}
if (bank->target->state != TARGET_HALTED)
@@ -1220,11 +1158,11 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
return ERROR_TARGET_NOT_HALTED;
}
if (strcmp(CMD_ARGV[1], "set") == 0)
if (strcmp(args[1], "set") == 0)
{
flashcmd = SGPB;
}
else if (strcmp(CMD_ARGV[1], "clear") == 0)
else if (strcmp(args[1], "clear") == 0)
{
flashcmd = CGPB;
}
@@ -1243,10 +1181,10 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
}
}
COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit);
bit = atoi(args[0]);
if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits))
{
command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name);
command_print(cmd_ctx, "gpnvm bit '#%s' is out of bounds for target %s", args[0], at91sam7_info->target_name);
return ERROR_OK;
}
@@ -1261,46 +1199,10 @@ COMMAND_HANDLER(at91sam7_handle_gpnvm_command)
/* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */
status = at91sam7_get_flash_status(bank->target, 0);
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32, flashcmd, bit, status);
LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32 " \n", flashcmd, bit, status);
/* check protect state */
at91sam7_protect_check(bank);
return ERROR_OK;
}
static const struct command_registration at91sam7_exec_command_handlers[] = {
{
.name = "gpnvm",
.handler = at91sam7_handle_gpnvm_command,
.mode = COMMAND_EXEC,
.help = "set or clear one General Purpose Non-Volatile Memory "
"(gpnvm) bit",
.usage = "bitnum ('set'|'clear')",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration at91sam7_command_handlers[] = {
{
.name = "at91sam7",
.mode = COMMAND_ANY,
.help = "at91sam7 flash command group",
.chain = at91sam7_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver at91sam7_flash = {
.name = "at91sam7",
.commands = at91sam7_command_handlers,
.flash_bank_command = at91sam7_flash_bank_command,
.erase = at91sam7_erase,
.protect = at91sam7_protect,
.write = at91sam7_write,
.read = default_flash_read,
.probe = at91sam7_probe,
.auto_probe = at91sam7_probe,
.erase_check = at91sam7_erase_check,
.protect_check = at91sam7_protect_check,
.info = get_at91sam7_info,
};

118
src/flash/at91sam7.h Normal file
View File

@@ -0,0 +1,118 @@
/***************************************************************************
* Copyright (C) 2006 by Magnus Lundin *
* lundin@mlu.mine.nu *
* *
* Copyright (C) 2006 by Gheorghe Guran (atlas) *
* *
* 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"
typedef struct at91sam7_flash_bank_s
{
/* chip id register */
uint32_t cidr;
uint16_t cidr_ext;
uint16_t cidr_nvptyp;
uint16_t cidr_arch;
uint16_t cidr_sramsiz;
uint16_t cidr_nvpsiz;
uint16_t cidr_nvpsiz2;
uint16_t cidr_eproc;
uint16_t cidr_version;
char *target_name;
/* flash auto-detection */
uint8_t flash_autodetection;
/* flash geometry */
uint16_t pages_per_sector;
uint16_t pagesize;
uint16_t pages_in_lockregion;
/* nv memory bits */
uint16_t num_lockbits_on;
uint16_t lockbits;
uint16_t num_nvmbits;
uint16_t num_nvmbits_on;
uint16_t nvmbits;
uint8_t securitybit;
/* 0: not init
* 1: fmcn for nvbits (1uS)
* 2: fmcn for flash (1.5uS) */
uint8_t flashmode;
/* main clock status */
uint8_t mck_valid;
uint32_t mck_freq;
/* external clock frequency */
uint32_t ext_freq;
} at91sam7_flash_bank_t;
/* AT91SAM7 control registers */
#define DBGU_CIDR 0xFFFFF240
#define CKGR_MCFR 0xFFFFFC24
#define CKGR_MOR 0xFFFFFC20
#define CKGR_MCFR_MAINRDY 0x10000
#define CKGR_PLLR 0xFFFFFC2c
#define CKGR_PLLR_DIV 0xff
#define CKGR_PLLR_MUL 0x07ff0000
#define PMC_MCKR 0xFFFFFC30
#define PMC_MCKR_CSS 0x03
#define PMC_MCKR_PRES 0x1c
/* 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
/* MC_FSR bit definitions */
#define MC_FSR_FRDY 1
#define MC_FSR_EOL 2
/* AT91SAM7 constants */
#define RC_FREQ 32000
/* Flash timing modes */
#define FMR_TIMING_NONE 0
#define FMR_TIMING_NVBITS 1
#define FMR_TIMING_FLASH 2
/* Flash size constants */
#define FLASH_SIZE_8KB 1
#define FLASH_SIZE_16KB 2
#define FLASH_SIZE_32KB 3
#define FLASH_SIZE_64KB 5
#define FLASH_SIZE_128KB 7
#define FLASH_SIZE_256KB 9
#define FLASH_SIZE_512KB 10
#define FLASH_SIZE_1024KB 12
#define FLASH_SIZE_2048KB 14
#endif /* AT91SAM7_H */

View File

@@ -21,8 +21,9 @@
#include "config.h"
#endif
#include "imp.h"
#include <target/avrt.h>
#include "avrf.h"
#include "avrt.h"
#include "flash.h"
/* AVR_JTAG_Instructions */
@@ -49,33 +50,55 @@
#define AVR_JTAG_REG_ProgrammingCommand_Len 15
#define AVR_JTAG_REG_FlashDataByte_Len 16
struct avrf_type
avrf_type_t avft_chips_info[] =
{
char name[15];
uint16_t chip_id;
int flash_page_size;
int flash_page_num;
int eeprom_page_size;
int eeprom_page_num;
// name, chip_id, flash_page_size, flash_page_num, eeprom_page_size, eeprom_page_num
{"atmega128", 0x9702, 256, 512, 8, 512},
};
struct avrf_flash_bank
{
int ppage_size;
int probed;
};
static int avrf_register_commands(struct command_context_s *cmd_ctx);
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int avrf_erase(struct flash_bank_s *bank, int first, int last);
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last);
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int avrf_probe(struct flash_bank_s *bank);
static int avrf_auto_probe(struct flash_bank_s *bank);
//static int avrf_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
static int avrf_protect_check(struct flash_bank_s *bank);
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size);
static struct avrf_type avft_chips_info[] =
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
extern int avr_jtag_sendinstr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out);
extern int avr_jtag_senddat(jtag_tap_t *tap, uint32_t *dr_in, uint32_t dr_out, int len);
extern int mcu_write_ir(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti);
extern int mcu_write_dr(jtag_tap_t *tap, uint8_t *ir_in, uint8_t *ir_out, int dr_len, int rti);
extern int mcu_write_ir_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti);
extern int mcu_write_dr_u8(jtag_tap_t *tap, uint8_t *ir_in, uint8_t ir_out, int dr_len, int rti);
extern int mcu_write_ir_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int ir_len, int rti);
extern int mcu_write_dr_u16(jtag_tap_t *tap, uint16_t *ir_in, uint16_t ir_out, int dr_len, int rti);
extern int mcu_write_ir_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int ir_len, int rti);
extern int mcu_write_dr_u32(jtag_tap_t *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti);
extern int mcu_execute_queue(void);
flash_driver_t avr_flash =
{
/* name, chip_id, flash_page_size, flash_page_num,
* eeprom_page_size, eeprom_page_num
*/
{"atmega128", 0x9702, 256, 512, 8, 512},
{"at90can128", 0x9781, 256, 512, 8, 512},
.name = "avr",
.register_commands = avrf_register_commands,
.flash_bank_command = avrf_flash_bank_command,
.erase = avrf_erase,
.protect = avrf_protect,
.write = avrf_write,
.probe = avrf_probe,
.auto_probe = avrf_auto_probe,
.erase_check = default_flash_mem_blank_check,
.protect_check = avrf_protect_check,
.info = avrf_info
};
/* avr program functions */
static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
static int avr_jtag_reset(avr_common_t *avr, uint32_t reset)
{
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET);
avr_jtag_senddat(avr->jtag_info.tap, NULL, reset ,AVR_JTAG_REG_Reset_Len);
@@ -83,7 +106,7 @@ static int avr_jtag_reset(struct avr_common *avr, uint32_t reset)
return ERROR_OK;
}
static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id)
static int avr_jtag_read_jtagid(avr_common_t *avr, uint32_t *id)
{
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE);
avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len);
@@ -91,7 +114,7 @@ static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id)
return ERROR_OK;
}
static int avr_jtagprg_enterprogmode(struct avr_common *avr)
static int avr_jtagprg_enterprogmode(avr_common_t *avr)
{
avr_jtag_reset(avr, 1);
@@ -101,7 +124,7 @@ static int avr_jtagprg_enterprogmode(struct avr_common *avr)
return ERROR_OK;
}
static int avr_jtagprg_leaveprogmode(struct avr_common *avr)
static int avr_jtagprg_leaveprogmode(avr_common_t *avr)
{
avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS);
avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len);
@@ -115,7 +138,7 @@ static int avr_jtagprg_leaveprogmode(struct avr_common *avr)
return ERROR_OK;
}
static int avr_jtagprg_chiperase(struct avr_common *avr)
static int avr_jtagprg_chiperase(avr_common_t *avr)
{
uint32_t poll_value;
@@ -138,7 +161,7 @@ static int avr_jtagprg_chiperase(struct avr_common *avr)
return ERROR_OK;
}
static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
static int avr_jtagprg_writeflashpage(avr_common_t *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size)
{
uint32_t i, poll_value;
@@ -185,17 +208,28 @@ static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf,
return ERROR_OK;
}
FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
/* interface command */
static int avrf_register_commands(struct command_context_s *cmd_ctx)
{
struct avrf_flash_bank *avrf_info;
command_t *avr_cmd = register_command(cmd_ctx, NULL, "avr", NULL, COMMAND_ANY, "avr flash specific commands");
if (CMD_ARGC < 6)
register_command(cmd_ctx, avr_cmd, "mass_erase", avrf_handle_mass_erase_command, COMMAND_EXEC,
"mass erase device");
return ERROR_OK;
}
static int avrf_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
avrf_flash_bank_t *avrf_info;
if (argc < 6)
{
LOG_WARNING("incomplete flash_bank avr configuration");
return ERROR_FLASH_BANK_INVALID;
}
avrf_info = malloc(sizeof(struct avrf_flash_bank));
avrf_info = malloc(sizeof(avrf_flash_bank_t));
bank->driver_priv = avrf_info;
avrf_info->probed = 0;
@@ -203,41 +237,22 @@ FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command)
return ERROR_OK;
}
static int avrf_erase(struct flash_bank *bank, int first, int last)
{
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
int status;
LOG_DEBUG("%s", __FUNCTION__);
if (target->state != TARGET_HALTED)
{
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
status = avr_jtagprg_enterprogmode(avr);
if (status != ERROR_OK)
return status;
status = avr_jtagprg_chiperase(avr);
if (status != ERROR_OK)
return status;
return avr_jtagprg_leaveprogmode(avr);
}
static int avrf_protect(struct flash_bank *bank, int set, int first, int last)
static int avrf_erase(struct flash_bank_s *bank, int first, int last)
{
LOG_INFO("%s", __FUNCTION__);
return ERROR_OK;
}
static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int avrf_protect(struct flash_bank_s *bank, int set, int first, int last)
{
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
LOG_INFO("%s", __FUNCTION__);
return ERROR_OK;
}
static int avrf_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
target_t *target = bank->target;
avr_common_t *avr = target->arch_info;
uint32_t cur_size, cur_buffer_size, page_size;
if (bank->target->state != TARGET_HALTED)
@@ -285,12 +300,12 @@ static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset,
#define EXTRACT_MFG(X) (((X) & 0xffe) >> 1)
#define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
#define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28)
static int avrf_probe(struct flash_bank *bank)
static int avrf_probe(struct flash_bank_s *bank)
{
struct target *target = bank->target;
struct avrf_flash_bank *avrf_info = bank->driver_priv;
struct avr_common *avr = target->arch_info;
struct avrf_type *avr_info = NULL;
target_t *target = bank->target;
avrf_flash_bank_t *avrf_info = bank->driver_priv;
avr_common_t *avr = target->arch_info;
avrf_type_t *avr_info = NULL;
int i;
uint32_t device_id;
@@ -314,7 +329,7 @@ static int avrf_probe(struct flash_bank *bank)
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
}
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
{
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
{
@@ -326,17 +341,11 @@ static int avrf_probe(struct flash_bank *bank)
if (avr_info != NULL)
{
if (bank->sectors)
{
free(bank->sectors);
bank->sectors = NULL;
}
// chip found
bank->base = 0x00000000;
bank->size = (avr_info->flash_page_size * avr_info->flash_page_num);
bank->num_sectors = avr_info->flash_page_num;
bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num);
bank->sectors = malloc(sizeof(flash_sector_t) * avr_info->flash_page_num);
for (i = 0; i < avr_info->flash_page_num; i++)
{
@@ -359,25 +368,25 @@ static int avrf_probe(struct flash_bank *bank)
}
}
static int avrf_auto_probe(struct flash_bank *bank)
static int avrf_auto_probe(struct flash_bank_s *bank)
{
struct avrf_flash_bank *avrf_info = bank->driver_priv;
avrf_flash_bank_t *avrf_info = bank->driver_priv;
if (avrf_info->probed)
return ERROR_OK;
return avrf_probe(bank);
}
static int avrf_protect_check(struct flash_bank *bank)
static int avrf_protect_check(struct flash_bank_s *bank)
{
LOG_INFO("%s", __FUNCTION__);
return ERROR_OK;
}
static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
static int avrf_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
struct avrf_type *avr_info = NULL;
target_t *target = bank->target;
avr_common_t *avr = target->arch_info;
avrf_type_t *avr_info = NULL;
int i;
uint32_t device_id;
@@ -399,7 +408,7 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F);
}
for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++)
for (i = 0; i < (int)(sizeof(avft_chips_info) / sizeof(avft_chips_info[0])); i++)
{
if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id))
{
@@ -424,10 +433,10 @@ static int avrf_info(struct flash_bank *bank, char *buf, int buf_size)
}
}
static int avrf_mass_erase(struct flash_bank *bank)
static int avrf_mass_erase(struct flash_bank_s *bank)
{
struct target *target = bank->target;
struct avr_common *avr = target->arch_info;
target_t *target = bank->target;
avr_common_t *avr = target->arch_info;
if (target->state != TARGET_HALTED)
{
@@ -445,20 +454,23 @@ static int avrf_mass_erase(struct flash_bank *bank)
return ERROR_OK;
}
COMMAND_HANDLER(avrf_handle_mass_erase_command)
static int avrf_handle_mass_erase_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
flash_bank_t *bank;
int i;
if (CMD_ARGC < 1)
if (argc < 1)
{
command_print(CMD_CTX, "avr mass_erase <bank>");
command_print(cmd_ctx, "avr mass_erase <bank>");
return ERROR_OK;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
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;
}
if (avrf_mass_erase(bank) == ERROR_OK)
{
@@ -468,47 +480,13 @@ COMMAND_HANDLER(avrf_handle_mass_erase_command)
bank->sectors[i].is_erased = 1;
}
command_print(CMD_CTX, "avr mass erase complete");
command_print(cmd_ctx, "avr mass erase complete");
}
else
{
command_print(CMD_CTX, "avr mass erase failed");
command_print(cmd_ctx, "avr mass erase failed");
}
LOG_DEBUG("%s", __FUNCTION__);
return ERROR_OK;
}
static const struct command_registration avrf_exec_command_handlers[] = {
{
.name = "mass_erase",
.handler = avrf_handle_mass_erase_command,
.mode = COMMAND_EXEC,
.help = "erase entire device",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration avrf_command_handlers[] = {
{
.name = "avrf",
.mode = COMMAND_ANY,
.help = "AVR flash command group",
.chain = avrf_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver avr_flash = {
.name = "avr",
.commands = avrf_command_handlers,
.flash_bank_command = avrf_flash_bank_command,
.erase = avrf_erase,
.protect = avrf_protect,
.write = avrf_write,
.read = default_flash_read,
.probe = avrf_probe,
.auto_probe = avrf_auto_probe,
.erase_check = default_flash_mem_blank_check,
.protect_check = avrf_protect_check,
.info = avrf_info,
};

View File

@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2011 by Broadcom Corporation *
* Evan Hunter - ehunter@broadcom.com *
* Copyright (C) 2009 by Simon Qian *
* SimonQian@SimonQian.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 *
@@ -17,16 +17,25 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef AVRF_H
#define AVRF_H
#ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_
#define INCLUDED_RTOS_STANDARD_STACKINGS_H_
#include "types.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
typedef struct avrf_type_s
{
char name[15];
uint16_t chip_id;
int flash_page_size;
int flash_page_num;
int eeprom_page_size;
int eeprom_page_num;
} avrf_type_t;
#include "rtos.h"
typedef struct avrf_flash_bank_s
{
int ppage_size;
int probed;
} avrf_flash_bank_t;
extern const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking;
#endif //ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_
#endif /* AVRF_H */

2653
src/flash/cfi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -20,12 +20,14 @@
#ifndef CFI_H
#define CFI_H
#include "flash.h"
#define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */
#define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */
struct cfi_flash_bank
typedef struct cfi_flash_bank_s
{
struct working_area *write_algorithm;
working_area_t *write_algorithm;
int x16_as_x8;
int jedec_probe;
@@ -35,7 +37,7 @@ struct cfi_flash_bank
uint16_t manufacturer;
uint16_t device_id;
uint8_t qry[3];
char qry[3];
/* identification string */
uint16_t pri_id;
@@ -68,21 +70,15 @@ struct cfi_flash_bank
void *pri_ext;
void *alt_ext;
/* calculated timeouts */
unsigned word_write_timeout;
unsigned buf_write_timeout;
unsigned block_erase_timeout;
unsigned chip_erase_timeout;
};
} 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)
*/
struct cfi_intel_pri_ext
typedef struct cfi_intel_pri_ext_s
{
uint8_t pri[3];
char pri[3];
uint8_t major_version;
uint8_t minor_version;
uint32_t feature_support;
@@ -95,12 +91,12 @@ struct cfi_intel_pri_ext
uint8_t fact_prot_reg_size;
uint8_t user_prot_reg_size;
uint8_t extra[0];
};
} cfi_intel_pri_ext_t;
/* Spansion primary extended query table as defined for and used by
* the linux kernel cfi driver (as of 2.6.15)
*/
struct cfi_spansion_pri_ext
typedef struct cfi_spansion_pri_ext_s
{
uint8_t pri[3];
uint8_t major_version;
@@ -119,12 +115,12 @@ struct cfi_spansion_pri_ext
int _reversed_geometry;
uint32_t _unlock1;
uint32_t _unlock2;
};
} cfi_spansion_pri_ext_t;
/* Atmel primary extended query table as defined for and used by
* the linux kernel cfi driver (as of 2.6.20+)
*/
struct cfi_atmel_pri_ext
typedef struct cfi_atmel_pri_ext_s
{
uint8_t pri[3];
uint8_t major_version;
@@ -133,26 +129,26 @@ struct cfi_atmel_pri_ext
uint8_t bottom_boot;
uint8_t burst_mode;
uint8_t page_mode;
};
} cfi_atmel_pri_ext_t;
enum {
CFI_UNLOCK_555_2AA,
CFI_UNLOCK_5555_2AAA,
};
struct cfi_unlock_addresses
typedef struct cfi_unlock_addresses_s
{
uint32_t unlock1;
uint32_t unlock2;
};
} cfi_unlock_addresses_t;
struct cfi_fixup
typedef struct cfi_fixup_s
{
uint16_t mfr;
uint16_t id;
void (*fixup)(struct flash_bank *bank, void *param);
void (*fixup)(flash_bank_t *flash, void *param);
void *param;
};
} cfi_fixup_t;
#define CFI_MFR_AMD 0x0001
#define CFI_MFR_FUJITSU 0x0004

View File

@@ -1,48 +0,0 @@
/***************************************************************************
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
* *
* 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 "common.h"
#include <helper/log.h>
unsigned get_flash_name_index(const char *name)
{
const char *name_index = strrchr(name, '.');
if (NULL == name_index)
return 0;
if (name_index[1] < '0' || name_index[1] > '9')
return ~0U;
unsigned requested;
int retval = parse_uint(name_index + 1, &requested);
// detect parsing error by forcing past end of bank list
return (ERROR_OK == retval) ? requested : ~0U;
}
bool flash_driver_name_matches(const char *name, const char *expected)
{
unsigned blen = strlen(name);
// only match up to the length of the driver name...
if (strncmp(name, expected, blen) != 0)
return false;
// ...then check that name terminates at this spot.
return expected[blen] == '.' || expected[blen] == '\0';
}

View File

@@ -1,49 +0,0 @@
/***************************************************************************
* Copyright (C) 2009 by Zachary T Welch <zw@superlucidity.net> *
* *
* 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_COMMON_H
#define FLASH_COMMON_H
#include <helper/log.h>
/**
* Parses the optional '.index' portion of a flash bank identifier.
* @param name The desired driver name, passed by the user.
* @returns The parsed index request, or 0 if not present. If the
* name provides a suffix but it does not parse as an unsigned integer,
* the routine returns ~0U. This will prevent further matching.
*/
unsigned get_flash_name_index(const char *name);
/**
* Attempt to match the @c expected name with the @c name of a driver.
* @param name The name of the driver (from the bank's device structure).
* @param expected The expected driver name, passed by the user.
*/
bool flash_driver_name_matches(const char *name, const char *expected);
#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)
#define ERROR_FLASH_OPER_UNSUPPORTED (-908)
#endif // FLASH_COMMON_H

View File

@@ -28,9 +28,8 @@
#include "config.h"
#endif
#include "imp.h"
#include "arm_io.h"
#include <target/target.h>
#include "arm_nandio.h"
enum ecc {
HWECC1, /* all controllers support 1-bit ECC */
@@ -39,6 +38,8 @@ enum ecc {
};
struct davinci_nand {
target_t *target;
uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */
uint8_t eccmode;
@@ -54,9 +55,9 @@ struct davinci_nand {
struct arm_nand_data io;
/* page i/o for the relevant flavor of hardware ECC */
int (*read_page)(struct nand_device *nand, uint32_t page,
int (*read_page)(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
int (*write_page)(struct nand_device *nand, uint32_t page,
int (*write_page)(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
};
@@ -68,7 +69,7 @@ struct davinci_nand {
#define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */
#define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */
static int halted(struct target *target, const char *label)
static int halted(target_t *target, const char *label)
{
if (target->state == TARGET_HALTED)
return true;
@@ -77,10 +78,15 @@ static int halted(struct target *target, const char *label)
return false;
}
static int davinci_init(struct nand_device *nand)
static int davinci_register_commands(struct command_context_s *cmd_ctx)
{
return ERROR_OK;
}
static int davinci_init(struct nand_device_s *nand)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
uint32_t nandfcr;
if (!halted(target, "init"))
@@ -102,15 +108,15 @@ static int davinci_init(struct nand_device *nand)
return ERROR_OK;
}
static int davinci_reset(struct nand_device *nand)
static int davinci_reset(struct nand_device_s *nand)
{
return ERROR_OK;
}
static int davinci_nand_ready(struct nand_device *nand, int timeout)
static int davinci_nand_ready(struct nand_device_s *nand, int timeout)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
uint32_t nandfsr;
/* NOTE: return code is zero/error, else success; not ERROR_* */
@@ -130,10 +136,10 @@ static int davinci_nand_ready(struct nand_device *nand, int timeout)
return 0;
}
static int davinci_command(struct nand_device *nand, uint8_t command)
static int davinci_command(struct nand_device_s *nand, uint8_t command)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
if (!halted(target, "command"))
return ERROR_NAND_OPERATION_FAILED;
@@ -142,10 +148,10 @@ static int davinci_command(struct nand_device *nand, uint8_t command)
return ERROR_OK;
}
static int davinci_address(struct nand_device *nand, uint8_t address)
static int davinci_address(struct nand_device_s *nand, uint8_t address)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
if (!halted(target, "address"))
return ERROR_NAND_OPERATION_FAILED;
@@ -154,10 +160,10 @@ static int davinci_address(struct nand_device *nand, uint8_t address)
return ERROR_OK;
}
static int davinci_write_data(struct nand_device *nand, uint16_t data)
static int davinci_write_data(struct nand_device_s *nand, uint16_t data)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
if (!halted(target, "write_data"))
return ERROR_NAND_OPERATION_FAILED;
@@ -166,10 +172,10 @@ static int davinci_write_data(struct nand_device *nand, uint16_t data)
return ERROR_OK;
}
static int davinci_read_data(struct nand_device *nand, void *data)
static int davinci_read_data(struct nand_device_s *nand, void *data)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
if (!halted(target, "read_data"))
return ERROR_NAND_OPERATION_FAILED;
@@ -180,11 +186,11 @@ static int davinci_read_data(struct nand_device *nand, void *data)
/* REVISIT a bit of native code should let block reads be MUCH faster */
static int davinci_read_block_data(struct nand_device *nand,
static int davinci_read_block_data(struct nand_device_s *nand,
uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
uint32_t nfdata = info->data;
uint32_t tmp;
@@ -213,11 +219,11 @@ static int davinci_read_block_data(struct nand_device *nand,
return ERROR_OK;
}
static int davinci_write_block_data(struct nand_device *nand,
static int davinci_write_block_data(struct nand_device_s *nand,
uint8_t *data, int data_size)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
uint32_t nfdata = info->data;
uint32_t tmp;
int status;
@@ -249,7 +255,7 @@ static int davinci_write_block_data(struct nand_device *nand,
return ERROR_OK;
}
static int davinci_write_page(struct nand_device *nand, uint32_t page,
static int davinci_write_page(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
@@ -258,12 +264,12 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (!halted(nand->target, "write_page"))
if (!halted(info->target, "write_page"))
return ERROR_NAND_OPERATION_FAILED;
/* Always write both data and OOB ... we are not "raw" I/O! */
if (!data) {
LOG_ERROR("Missing NAND data; try 'nand raw_access enable'");
LOG_ERROR("Missing NAND data; try 'nand raw_access enable'\n");
return ERROR_NAND_OPERATION_FAILED;
}
@@ -300,23 +306,23 @@ static int davinci_write_page(struct nand_device *nand, uint32_t page,
return status;
}
static int davinci_read_page(struct nand_device *nand, uint32_t page,
static int davinci_read_page(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (!halted(nand->target, "read_page"))
if (!halted(info->target, "read_page"))
return ERROR_NAND_OPERATION_FAILED;
return info->read_page(nand, page, data, data_size, oob, oob_size);
}
static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page)
static void davinci_write_pagecmd(struct nand_device_s *nand, uint8_t cmd, uint32_t page)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
int page3 = nand->address_cycles - (nand->page_size == 512);
/* write command ({page,otp}x{read,program} */
@@ -336,32 +342,11 @@ static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_
target_write_u8(target, info->addr, page >> 24);
}
static int davinci_seek_column(struct nand_device *nand, uint16_t column)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
/* Random read, we must have issued a page read already */
target_write_u8(target, info->cmd, NAND_CMD_RNDOUT);
target_write_u8(target, info->addr, column);
if (nand->page_size > 512) {
target_write_u8(target, info->addr, column >> 8);
target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART);
}
if (!davinci_nand_ready(nand, 100))
return ERROR_NAND_OPERATION_TIMEOUT;
return ERROR_OK;
}
static int davinci_writepage_tail(struct nand_device *nand,
static int davinci_writepage_tail(struct nand_device_s *nand,
uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
uint8_t status;
if (oob_size)
@@ -389,12 +374,12 @@ static int davinci_writepage_tail(struct nand_device *nand,
/*
* All DaVinci family chips support 1-bit ECC on a per-chipselect basis.
*/
static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
static int davinci_write_page_ecc1(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
unsigned oob_offset;
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
const uint32_t fcr_addr = info->aemif + NANDFCR;
const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel);
uint32_t fcr, ecc1;
@@ -456,7 +441,7 @@ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page,
* is read first, so its ECC data can be used incrementally), but the
* manufacturer bad block markers are safe. Contrast: old "infix" style.
*/
static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
static int davinci_write_page_ecc4(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
static const uint8_t ecc512[] = {
@@ -482,7 +467,7 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
struct davinci_nand *info = nand->controller_priv;
const uint8_t *l;
struct target *target = nand->target;
target_t *target = info->target;
const uint32_t fcr_addr = info->aemif + NANDFCR;
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
uint32_t fcr, ecc4;
@@ -558,11 +543,11 @@ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page,
* older second stage loaders (ABL/U-Boot, etc) or other system software
* (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally.
*/
static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
static int davinci_write_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
struct davinci_nand *info = nand->controller_priv;
struct target *target = nand->target;
target_t *target = info->target;
const uint32_t fcr_addr = info->aemif + NANDFCR;
const uint32_t ecc4_addr = info->aemif + NAND4BITECC;
uint32_t fcr, ecc4;
@@ -615,13 +600,9 @@ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page,
return davinci_writepage_tail(nand, NULL, 0);
}
static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
static int davinci_read_page_ecc4infix(struct nand_device_s *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
int read_size;
int want_col, at_col;
int ret;
davinci_write_pagecmd(nand, NAND_CMD_READ0, page);
/* large page devices need a start command */
@@ -633,52 +614,31 @@ static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page,
/* NOTE: not bothering to compute and use ECC data for now */
want_col = 0;
at_col = 0;
while ((data && data_size) || (oob && oob_size)) {
do {
/* write 512 bytes */
davinci_read_block_data(nand, data, 512);
data += 512;
data_size -= 512;
if (data && data_size) {
if (want_col != at_col) {
/* Reads are slow, so seek past them when we can */
ret = davinci_seek_column(nand, want_col);
if (ret != ERROR_OK)
return ret;
at_col = want_col;
}
/* read 512 bytes or data_size, whichever is smaller*/
read_size = data_size > 512 ? 512 : data_size;
davinci_read_block_data(nand, data, read_size);
data += read_size;
data_size -= read_size;
at_col += read_size;
}
want_col += 512;
/* read this "out-of-band" data -- infix */
davinci_read_block_data(nand, oob, 16);
oob += 16;
oob_size -= 16;
} while (data_size);
if (oob && oob_size) {
if (want_col != at_col) {
ret = davinci_seek_column(nand, want_col);
if (ret != ERROR_OK)
return ret;
at_col = want_col;
}
/* read this "out-of-band" data -- infix */
read_size = oob_size > 16 ? 16 : oob_size;
davinci_read_block_data(nand, oob, read_size);
oob += read_size;
oob_size -= read_size;
at_col += read_size;
}
want_col += 16;
}
return ERROR_OK;
}
NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
static int davinci_nand_device_command(struct command_context_s *cmd_ctx,
char *cmd, char **argv, int argc,
struct nand_device_s *nand)
{
struct davinci_nand *info;
target_t *target;
unsigned long chip, aemif;
enum ecc eccmode;
int chipsel;
char *ep;
/* arguments:
* - "davinci"
@@ -688,33 +648,39 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
* - aemif address
* Plus someday, optionally, ALE and CLE masks.
*/
if (CMD_ARGC < 5) {
if (argc < 5) {
LOG_ERROR("parameters: %s target "
"chip_addr hwecc_mode aemif_addr",
CMD_ARGV[0]);
argv[0]);
goto fail;
}
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
if (chip == 0) {
LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]);
target = get_target(argv[1]);
if (!target) {
LOG_ERROR("invalid target %s", argv[1]);
goto fail;
}
if (strcmp(CMD_ARGV[3], "hwecc1") == 0)
chip = strtoul(argv[2], &ep, 0);
if (*ep || chip == 0 || chip == ULONG_MAX) {
LOG_ERROR("Invalid NAND chip address %s", argv[2]);
goto fail;
}
if (strcmp(argv[3], "hwecc1") == 0)
eccmode = HWECC1;
else if (strcmp(CMD_ARGV[3], "hwecc4") == 0)
else if (strcmp(argv[3], "hwecc4") == 0)
eccmode = HWECC4;
else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0)
else if (strcmp(argv[3], "hwecc4_infix") == 0)
eccmode = HWECC4_INFIX;
else {
LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]);
LOG_ERROR("Invalid ecc mode %s", argv[3]);
goto fail;
}
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif);
if (aemif == 0) {
LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]);
aemif = strtoul(argv[4], &ep, 0);
if (*ep || aemif == 0 || aemif == ULONG_MAX) {
LOG_ERROR("Invalid AEMIF controller address %s", argv[4]);
goto fail;
}
@@ -740,6 +706,7 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
if (info == NULL)
goto fail;
info->target = target;
info->eccmode = eccmode;
info->chipsel = chipsel;
info->aemif = aemif;
@@ -749,9 +716,8 @@ NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command)
nand->controller_priv = info;
info->io.target = nand->target;
info->io.target = target;
info->io.data = info->data;
info->io.op = ARM_NAND_NONE;
/* NOTE: for now we don't do any error correction on read.
* Nothing else in OpenOCD currently corrects read errors,
@@ -781,9 +747,10 @@ fail:
return ERROR_NAND_OPERATION_FAILED;
}
struct nand_flash_controller davinci_nand_controller = {
nand_flash_controller_t davinci_nand_controller = {
.name = "davinci",
.nand_device_command = davinci_nand_device_command,
.register_commands = davinci_register_commands,
.init = davinci_init,
.reset = davinci_reset,
.command = davinci_command,

View File

@@ -21,27 +21,50 @@
#include "config.h"
#endif
#include "imp.h"
#include <target/embeddedice.h>
#include <target/algorithm.h>
#include <target/image.h>
#include "flash.h"
#include "embeddedice.h"
#include "image.h"
static int ecosflash_register_commands(struct command_context_s *cmd_ctx);
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last);
static int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last);
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int ecosflash_probe(struct flash_bank_s *bank);
static int ecosflash_protect_check(struct flash_bank_s *bank);
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size);
#if 0
static uint32_t ecosflash_get_flash_status(struct flash_bank *bank);
static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode);
static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout);
static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc);
static uint32_t ecosflash_get_flash_status(flash_bank_t *bank);
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode);
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout);
static int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
#endif
struct ecosflash_flash_bank
flash_driver_t ecosflash_flash =
{
struct target *target;
struct working_area *write_algorithm;
struct working_area *erase_check_algorithm;
.name = "ecosflash",
.register_commands = ecosflash_register_commands,
.flash_bank_command = ecosflash_flash_bank_command,
.erase = ecosflash_erase,
.protect = ecosflash_protect,
.write = ecosflash_write,
.probe = ecosflash_probe,
.auto_probe = ecosflash_probe,
.erase_check = default_flash_blank_check,
.protect_check = ecosflash_protect_check,
.info = ecosflash_info
};
typedef struct ecosflash_flash_bank_s
{
struct target_s *target;
working_area_t *write_algorithm;
working_area_t *erase_check_algorithm;
char *driverPath;
uint32_t start_address;
};
} ecosflash_flash_bank_t;
static const int sectorSize = 0x10000;
@@ -105,24 +128,24 @@ flash_errmsg(int err)
/* flash bank ecosflash <base> <size> <chip_width> <bus_width> <target#> <driverPath>
*/
FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
static int ecosflash_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct ecosflash_flash_bank *info;
ecosflash_flash_bank_t *info;
if (CMD_ARGC < 7)
if (argc < 7)
{
LOG_WARNING("incomplete flash_bank ecosflash configuration");
return ERROR_FLASH_BANK_INVALID;
}
info = malloc(sizeof(struct ecosflash_flash_bank));
info = malloc(sizeof(ecosflash_flash_bank_t));
if (info == NULL)
{
LOG_ERROR("no memory for flash bank info");
exit(-1);
}
bank->driver_priv = info;
info->driverPath = strdup(CMD_ARGV[6]);
info->driverPath = strdup(args[6]);
/* eCos flash sector sizes are not exposed to OpenOCD, use 0x10000 as
* a way to improve impedance match between OpenOCD and eCos flash
@@ -131,7 +154,7 @@ FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
int i = 0;
uint32_t offset = 0;
bank->num_sectors = bank->size/sectorSize;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
for (i = 0; i < bank->num_sectors; i++)
{
bank->sectors[i].offset = offset;
@@ -141,24 +164,24 @@ FLASH_BANK_COMMAND_HANDLER(ecosflash_flash_bank_command)
bank->sectors[i].is_protected = 0;
}
info->target = get_target(CMD_ARGV[5]);
info->target = get_target(args[5]);
if (info->target == NULL)
{
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
LOG_ERROR("target '%s' not defined", args[5]);
return ERROR_FAIL;
}
return ERROR_OK;
}
static int loadDriver(struct ecosflash_flash_bank *info)
static int loadDriver(ecosflash_flash_bank_t *info)
{
size_t buf_cnt;
size_t image_size;
struct image image;
uint32_t buf_cnt;
uint32_t image_size;
image_t image;
image.base_address_set = 0;
image.start_address_set = 0;
struct target *target = info->target;
target_t *target = info->target;
int retval;
if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK)
@@ -173,6 +196,7 @@ static int loadDriver(struct ecosflash_flash_bank *info)
for (i = 0; i < image.num_sections; i++)
{
void *buffer = malloc(image.sections[i].size);
int retval;
if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
{
free(buffer);
@@ -181,8 +205,7 @@ static int loadDriver(struct ecosflash_flash_bank *info)
}
target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer);
image_size += buf_cnt;
LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "",
buf_cnt, image.sections[i].base_address);
LOG_DEBUG("%" PRIu32 " byte written at address 0x%8.8" PRIx32 "", buf_cnt, image.sections[i].base_address);
free(buffer);
}
@@ -199,19 +222,19 @@ static int const OFFSET_FLASH_SIZE = 0x8;
static int const OFFSET_GET_WORKAREA = 0x18;
static int const OFFSET_GET_WORKAREA_SIZE = 0x4;
static int runCode(struct ecosflash_flash_bank *info,
static int runCode(ecosflash_flash_bank_t *info,
uint32_t codeStart, uint32_t codeStop, uint32_t r0, uint32_t r1, uint32_t r2,
uint32_t *result,
/* timeout in ms */
int timeout)
{
struct target *target = info->target;
target_t *target = info->target;
struct reg_param reg_params[3];
struct arm_algorithm armv4_5_info;
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
armv4_5_info.core_mode = ARM_MODE_SVC;
armv4_5_info.core_state = ARM_STATE_ARM;
reg_param_t reg_params[3];
armv4_5_algorithm_t armv4_5_info;
armv4_5_info.common_magic = ARMV4_5_COMMON_MAGIC;
armv4_5_info.core_mode = ARMV4_5_MODE_SVC;
armv4_5_info.core_state = ARMV4_5_STATE_ARM;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
@@ -240,7 +263,7 @@ static int runCode(struct ecosflash_flash_bank *info,
return ERROR_OK;
}
static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address, uint32_t len)
static int eCosBoard_erase(ecosflash_flash_bank_t *info, uint32_t address, uint32_t len)
{
int retval;
int timeout = (len / 20480 + 1) * 1000; /*asume 20 KB/s*/
@@ -264,16 +287,16 @@ static int eCosBoard_erase(struct ecosflash_flash_bank *info, uint32_t address,
if (flashErr != 0x0)
{
LOG_ERROR("Flash erase failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
LOG_ERROR("Flash erase failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
return ERROR_FAIL;
}
return ERROR_OK;
}
static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32_t address, uint32_t len)
static int eCosBoard_flash(ecosflash_flash_bank_t *info, void *data, uint32_t address, uint32_t len)
{
struct target *target = info->target;
target_t *target = info->target;
const int chunk = 8192;
int retval = ERROR_OK;
int timeout = (chunk / 20480 + 1) * 1000; /*asume 20 KB/s + 1 second*/
@@ -304,6 +327,7 @@ static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32
t = chunk;
}
int retval;
retval = target_write_buffer(target, buffer, t, ((uint8_t *)data) + i);
if (retval != ERROR_OK)
return retval;
@@ -322,22 +346,29 @@ static int eCosBoard_flash(struct ecosflash_flash_bank *info, void *data, uint32
if (flashErr != 0x0)
{
LOG_ERROR("Flash prog failed with %d (%s)", (int)flashErr, flash_errmsg(flashErr));
LOG_ERROR("Flash prog failed with %d (%s)\n", (int)flashErr, flash_errmsg(flashErr));
return ERROR_FAIL;
}
}
return ERROR_OK;
}
static int ecosflash_probe(struct flash_bank *bank)
static int ecosflash_probe(struct flash_bank_s *bank)
{
return ERROR_OK;
}
#if 0
static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
static int ecosflash_register_commands(struct command_context_s *cmd_ctx)
{
struct ecosflash_flash_bank *info = bank->driver_priv;
register_command(cmd_ctx, NULL, "ecosflash", NULL, COMMAND_ANY, NULL);
return ERROR_OK;
}
#if 0
static void command(flash_bank_t *bank, uint8_t cmd, uint8_t *cmd_buf)
{
ecosflash_flash_bank_t *info = bank->driver_priv;
int i;
if (info->target->endianness == TARGET_LITTLE_ENDIAN)
@@ -358,7 +389,7 @@ static void command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf)
#endif
#if 0
static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
static uint32_t ecosflash_address(struct flash_bank_s *bank, uint32_t address)
{
uint32_t retval = 0;
switch (bank->bus_width)
@@ -375,69 +406,55 @@ static uint32_t ecosflash_address(struct flash_bank *bank, uint32_t address)
}
#endif
static int ecosflash_erase(struct flash_bank *bank, int first, int last)
static int ecosflash_erase(struct flash_bank_s *bank, int first, int last)
{
struct flash_bank *c = bank;
struct ecosflash_flash_bank *info = bank->driver_priv;
struct flash_bank_s *c = bank;
ecosflash_flash_bank_t *info = bank->driver_priv;
return eCosBoard_erase(info, c->base + first*sectorSize, sectorSize*(last-first + 1));
}
static int ecosflash_protect(struct flash_bank *bank, int set, int first, int last)
static int ecosflash_protect(struct flash_bank_s *bank, int set, int first, int last)
{
return ERROR_OK;
}
static int ecosflash_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int ecosflash_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct ecosflash_flash_bank *info = bank->driver_priv;
struct flash_bank *c = bank;
ecosflash_flash_bank_t *info = bank->driver_priv;
struct flash_bank_s *c = bank;
return eCosBoard_flash(info, buffer, c->base + offset, count);
}
static int ecosflash_protect_check(struct flash_bank *bank)
static int ecosflash_protect_check(struct flash_bank_s *bank)
{
return ERROR_OK;
}
static int ecosflash_info(struct flash_bank *bank, char *buf, int buf_size)
static int ecosflash_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
struct ecosflash_flash_bank *info = bank->driver_priv;
ecosflash_flash_bank_t *info = bank->driver_priv;
snprintf(buf, buf_size, "eCos flash driver: %s", info->driverPath);
return ERROR_OK;
}
#if 0
static uint32_t ecosflash_get_flash_status(struct flash_bank *bank)
static uint32_t ecosflash_get_flash_status(flash_bank_t *bank)
{
return ERROR_OK;
}
static void ecosflash_set_flash_mode(struct flash_bank *bank,int mode)
static void ecosflash_set_flash_mode(flash_bank_t *bank,int mode)
{
}
static uint32_t ecosflash_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout)
static uint32_t ecosflash_wait_status_busy(flash_bank_t *bank, uint32_t waitbits, int timeout)
{
return ERROR_OK;
}
static int ecosflash_handle_gpnvm_command(struct command_context *cmd_ctx, char *cmd, char **args, int argc)
static int ecosflash_handle_gpnvm_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
return ERROR_OK;
}
#endif
struct flash_driver ecosflash_flash = {
.name = "ecosflash",
.flash_bank_command = ecosflash_flash_bank_command,
.erase = ecosflash_erase,
.protect = ecosflash_protect,
.write = ecosflash_write,
.read = default_flash_read,
.probe = ecosflash_probe,
.auto_probe = ecosflash_probe,
.erase_check = default_flash_blank_check,
.protect_check = ecosflash_protect_check,
.info = ecosflash_info
};

View File

@@ -21,34 +21,57 @@
#include "config.h"
#endif
#include "imp.h"
#include <target/image.h>
#include "hello.h"
#include "flash.h"
#include "image.h"
struct faux_flash_bank
static int faux_register_commands(struct command_context_s *cmd_ctx);
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int faux_erase(struct flash_bank_s *bank, int first, int last);
static int faux_protect(struct flash_bank_s *bank, int set, int first, int last);
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int faux_probe(struct flash_bank_s *bank);
static int faux_protect_check(struct flash_bank_s *bank);
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size);
flash_driver_t faux_flash =
{
struct target *target;
.name = "faux",
.register_commands = faux_register_commands,
.flash_bank_command = faux_flash_bank_command,
.erase = faux_erase,
.protect = faux_protect,
.write = faux_write,
.probe = faux_probe,
.auto_probe = faux_probe,
.erase_check = default_flash_blank_check,
.protect_check = faux_protect_check,
.info = faux_info
};
typedef struct faux_flash_bank_s
{
struct target_s *target;
uint8_t *memory;
uint32_t start_address;
};
} faux_flash_bank_t;
static const int sectorSize = 0x10000;
/* flash bank faux <base> <size> <chip_width> <bus_width> <target#> <driverPath>
*/
FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
static int faux_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct faux_flash_bank *info;
faux_flash_bank_t *info;
if (CMD_ARGC < 6)
if (argc < 6)
{
LOG_WARNING("incomplete flash_bank faux configuration");
return ERROR_FLASH_BANK_INVALID;
}
info = malloc(sizeof(struct faux_flash_bank));
info = malloc(sizeof(faux_flash_bank_t));
if (info == NULL)
{
LOG_ERROR("no memory for flash bank info");
@@ -67,7 +90,7 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
int i = 0;
uint32_t offset = 0;
bank->num_sectors = bank->size/sectorSize;
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
for (i = 0; i < bank->num_sectors; i++)
{
bank->sectors[i].offset = offset;
@@ -77,10 +100,10 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
bank->sectors[i].is_protected = 0;
}
info->target = get_target(CMD_ARGV[5]);
info->target = get_target(args[5]);
if (info->target == NULL)
{
LOG_ERROR("target '%s' not defined", CMD_ARGV[5]);
LOG_ERROR("target '%s' not defined", args[5]);
free(info->memory);
free(info);
return ERROR_FAIL;
@@ -88,63 +111,43 @@ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command)
return ERROR_OK;
}
static int faux_erase(struct flash_bank *bank, int first, int last)
static int faux_register_commands(struct command_context_s *cmd_ctx)
{
struct faux_flash_bank *info = bank->driver_priv;
return ERROR_OK;
}
static int faux_erase(struct flash_bank_s *bank, int first, int last)
{
faux_flash_bank_t *info = bank->driver_priv;
memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1));
return ERROR_OK;
}
static int faux_protect(struct flash_bank *bank, int set, int first, int last)
static int faux_protect(struct flash_bank_s *bank, int set, int first, int last)
{
LOG_USER("set protection sector %d to %d to %s", first, last, set?"on":"off");
return ERROR_OK;
}
static int faux_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int faux_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct faux_flash_bank *info = bank->driver_priv;
faux_flash_bank_t *info = bank->driver_priv;
memcpy(info->memory + offset, buffer, count);
return ERROR_OK;
}
static int faux_protect_check(struct flash_bank *bank)
static int faux_protect_check(struct flash_bank_s *bank)
{
return ERROR_OK;
}
static int faux_info(struct flash_bank *bank, char *buf, int buf_size)
static int faux_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "faux flash driver");
return ERROR_OK;
}
static int faux_probe(struct flash_bank *bank)
static int faux_probe(struct flash_bank_s *bank)
{
return ERROR_OK;
}
static const struct command_registration faux_command_handlers[] = {
{
.name = "faux",
.mode = COMMAND_ANY,
.help = "faux flash command group",
.chain = hello_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver faux_flash = {
.name = "faux",
.commands = faux_command_handlers,
.flash_bank_command = faux_flash_bank_command,
.erase = faux_erase,
.protect = faux_protect,
.write = faux_write,
.read = default_flash_read,
.probe = faux_probe,
.auto_probe = faux_probe,
.erase_check = default_flash_blank_check,
.protect_check = faux_protect_check,
.info = faux_info
};

1330
src/flash/flash.c Normal file

File diff suppressed because it is too large Load Diff

339
src/flash/flash.h Normal file
View File

@@ -0,0 +1,339 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* 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"
#include "log.h"
struct image_s;
#define FLASH_MAX_ERROR_STR (128)
/**
* Describes the geometry and status of a single flash sector
* within a flash bank. A single bank typically consists of multiple
* sectors, each of which can be erased and protected independently.
*/
typedef struct flash_sector_s
{
/// Bus offset from start of the flash chip (in bytes).
uint32_t offset;
/// Number of bytes in this flash sector.
uint32_t size;
/**
* Indication of erasure status: 0 = not erased, 1 = erased,
* other = unknown. Set by @c flash_driver_s::erase_check.
*/
int is_erased;
/**
* Indication of protection status: 0 = unprotected/unlocked,
* 1 = protected/locked, other = unknown. Set by
* @c flash_driver_s::protect_check.
*/
int is_protected;
} flash_sector_t;
struct flash_bank_s;
/**
* @brief Provides the implementation-independent structure that defines
* all of the callbacks required by OpenOCD flash drivers.
*
* Driver authors must implement the routines defined here, providing an
* instance with the fields filled out. After that, the instance must
* be registered in flash.c, so it can be used by the driver lookup system.
*
* Specifically, the user can issue the command: @par
* @code
* flash bank DRIVERNAME ...parameters...
* @endcode
*
* OpenOCD will search for the driver with a @c flash_driver_s::name
* that matches @c DRIVERNAME.
*
* The flash subsystem calls some of the other drivers routines a using
* corresponding static <code>flash_driver_<i>callback</i>()</code>
* routine in flash.c.
*/
typedef struct flash_driver_s
{
/**
* Gives a human-readable name of this flash driver,
* This field is used to select and initialize the driver.
*/
char *name;
/**
* Registers driver-specific commands. When called (during the
* "flash bank" command), the driver may register addition
* commands to support new flash chip functions.
*
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*register_commands)(struct command_context_s *cmd_ctx);
/**
* Finish the "flash bank" command for @a bank. The
* @a bank parameter will have been filled in by the core flash
* layer when this routine is called, and the driver can store
* additional information in its flash_bank_t::driver_priv field.
*
* @param cmd_ctx - the command context
* @param cmd - the command, in this case 'flash'
* @param args - parameters, see below
* @param argc - number of parameters on command line
* @param bank - new filled in flash bank.
*
* The args are: @par
* @code
* args[0] = bank
* args[1] = drivername {name above}
* args[2] = baseaddress
* args[3] = lengthbytes
* args[4] = chip_width_in bytes
* args[5] = bus_width_bytes
* args[6] = driver-specific parameters
* @endcode
*
* For example, args[4] = 16 bit flash, args[5] = 32bit bus.
*
* If extra arguments are provided (@a argc > 6), they will
* start in @a args[6]. These can be used to implement
* driver-specific extensions.
*
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*flash_bank_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
/**
* Bank/sector erase routine (target-specific). When
* called, the flash driver should erase the specified sectors
* using whatever means are at its disposal.
*
* @param bank The bank of flash to be erased.
* @param first The number of the first sector to erase, typically 0.
* @param last The number of the last sector to erase, typically N-1.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*erase)(struct flash_bank_s *bank, int first, int last);
/**
* Bank/sector protection routine (target-specific).
* When called, the driver should disable 'flash write' bits (or
* enable 'erase protection' bits) for the given @a bank and @a
* sectors.
*
* @param bank The bank to protect or unprotect.
* @param set If non-zero, enable protection; if 0, disable it.
* @param first The first sector to (un)protect, typicaly 0.
* @param last The last sector to (un)project, typically N-1.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*protect)(struct flash_bank_s *bank, int set, int first, int last);
/**
* Program data into the flash. Note CPU address will be
* "bank->base + offset", while the physical address is
* dependent upon current target MMU mappings.
*
* @param bank The bank to program
* @param buffer The data bytes to write.
* @param offset The offset into the chip to program.
* @param count The number of bytes to write.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*write)(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
/**
* Probe to determine what kind of flash is present.
* This is invoked by the "probe" script command.
*
* @param bank The bank to probe
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*probe)(struct flash_bank_s *bank);
/**
* Check the erasure status of a flash bank.
* When called, the driver routine must perform the required
* checks and then set the @c flash_sector_s::is_erased field
* for each of the flash banks's sectors.
*
* @param bank The bank to check
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*erase_check)(struct flash_bank_s *bank);
/**
* Determine if the specific bank is "protected" or not.
* When called, the driver routine must must perform the
* required protection check(s) and then set the @c
* flash_sector_s::is_protected field for each of the flash
* bank's sectors.
*
* @param bank - the bank to check
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*protect_check)(struct flash_bank_s *bank);
/**
* Display human-readable information about the flash
* bank into the given buffer. Drivers must be careful to avoid
* overflowing the buffer.
*
* @param bank - the bank to get info about
* @param char - where to put the text for the human to read
* @param buf_size - the size of the human buffer.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*info)(struct flash_bank_s *bank, char *buf, int buf_size);
/**
* A more gentle flavor of filash_driver_s::probe, performing
* setup with less noise. Generally, driver routines should test
* to seee if the bank has already been probed; if it has, the
* driver probably should not perform its probe a second time.
*
* This callback is often called from the inside of other
* routines (e.g. GDB flash downloads) to autoprobe the flash as
* it is programing the flash.
*
* @param bank - the bank to probe
* @returns ERROR_OK if successful; otherwise, an error code.
*/
int (*auto_probe)(struct flash_bank_s *bank);
} flash_driver_t;
/**
* Provides details of a flash bank, available either on-chip or through
* a major interface.
*
* This structure will be passed as a parameter to the callbacks in the
* flash_driver_s structure, some of which may modify the contents of
* this structure of the area of flash that it defines. Driver writers
* may use the @c driver_priv member to store additional data on a
* per-bank basis, if required.
*/
typedef struct flash_bank_s
{
struct target_s *target; /**< Target to which this bank belongs. */
flash_driver_t *driver; /**< Driver for this bank. */
void *driver_priv; /**< Private driver storage pointer */
int bank_number; /**< The 'bank' (or chip number) of this instance. */
uint32_t base; /**< The base address of this bank */
uint32_t size; /**< The size of this chip bank, in bytes */
int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */
int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */
/**
* The number of sectors on this chip. This value will
* be set intially to 0, and the flash driver must set this to
* some non-zero value during "probe()" or "auto_probe()".
*/
int num_sectors;
/// Array of sectors, allocated and initilized by the flash driver
flash_sector_t *sectors;
struct flash_bank_s *next; /**< The next flash bank on this chip */
} flash_bank_t;
/// Registers the 'flash' subsystem commands
extern int flash_register_commands(struct command_context_s *cmd_ctx);
/// Initializes the 'flash' subsystem drivers
extern int flash_init_drivers(struct command_context_s *cmd_ctx);
/**
* Erases @a length bytes in the @a target flash, starting at @a addr.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
extern int flash_erase_address_range(struct target_s *target, uint32_t addr, uint32_t length);
/**
* Writes @a image into the @a target flash. The @a written parameter
* will contain the
* @param target The target with the flash to be programmed.
* @param image The image that will be programmed to flash.
* @param written On return, contains the number of bytes written.
* @param erase If non-zero, indicates the flash driver should first
* erase the corresponding banks or sectors before programming.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
extern int flash_write(struct target_s *target, struct image_s *image, uint32_t *written, int erase);
/**
* Forces targets to re-examine their erase/protection state.
* This routine must be called when the system may modify the status.
*/
extern void flash_set_dirty(void);
/// @returns The number of flash banks currently defined.
extern int flash_get_bank_count(void);
/**
* Provides default erased-bank check handling. Checks to see if
* the flash driver knows they are erased; if things look uncertain,
* this routine will call default_flash_mem_blank_check() to confirm.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
extern int default_flash_blank_check(struct flash_bank_s *bank);
/**
* Provides a default blank flash memory check. Ensures the contents
* of the given bank have truly been erased.
* @param bank The flash bank.
* @returns ERROR_OK if successful; otherwise, an error code.
*/
extern int default_flash_mem_blank_check(struct flash_bank_s *bank);
/**
* Returns a flash bank by the specified flash_bank_s bank_number, @a num.
* @param num The flash bank number.
* @returns A flash_bank_t for flash bank @a num, or NULL
*/
extern flash_bank_t *get_flash_bank_by_num(int num);
/**
* Returns the flash bank like get_flash_bank_by_num(), without probing.
* @param num The flash bank number.
* @returns A flash_bank_t for flash bank @a num, or NULL.
*/
extern flash_bank_t *get_flash_bank_by_num_noprobe(int num);
/**
* Returns the flash bank located at a specified address.
* @param target The target, presumed to contain one or more banks.
* @param addr An address that is within the range of the bank.
* @returns The flash_bank_t located at @a addr, or NULL.
*/
extern flash_bank_t *get_flash_bank_by_addr(struct target_s *target, uint32_t addr);
#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 */

View File

@@ -25,22 +25,13 @@
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/arm_opcodes.h>
#include <target/armv7m.h>
#include "lpc2000.h"
#include "armv4_5.h"
#include "armv7m.h"
#include "binarybuffer.h"
/**
* @file
* flash programming support for NXP LPC17xx and LPC2xxx devices.
*
* @todo Provide a way to update CCLK after declaring the flash bank.
* The value which is correct after chip reset will rarely still work
* right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz).
*/
/*
/* flash programming support for NXP LPC17xx and LPC2xxx devices
* currently supported devices:
* variant 1 (lpc2000_v1):
* - 2104 | 5 | 6
@@ -62,54 +53,46 @@
* - 176x (tested with LPC1768)
*/
typedef enum
{
lpc2000_v1,
lpc2000_v2,
lpc1700
} lpc2000_variant;
static int lpc2000_register_commands(struct command_context_s *cmd_ctx);
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last);
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last);
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int lpc2000_probe(struct flash_bank_s *bank);
static int lpc2000_erase_check(struct flash_bank_s *bank);
static int lpc2000_protect_check(struct flash_bank_s *bank);
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size);
struct lpc2000_flash_bank
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
flash_driver_t lpc2000_flash =
{
lpc2000_variant variant;
struct working_area *iap_working_area;
uint32_t cclk;
int cmd51_dst_boundary;
int cmd51_can_256b;
int cmd51_can_8192b;
int calc_checksum;
uint32_t cmd51_max_buffer;
int checksum_vector;
.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,
.auto_probe = lpc2000_probe,
.erase_check = lpc2000_erase_check,
.protect_check = lpc2000_protect_check,
.info = lpc2000_info
};
enum lpc2000_status_codes
static int lpc2000_register_commands(struct command_context_s *cmd_ctx)
{
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,
LPC2000_PARAM_ERROR = 12,
LPC2000_ADDR_ERROR = 13,
LPC2000_ADDR_NOT_MAPPED = 14,
LPC2000_CMD_NOT_LOCKED = 15,
LPC2000_INVALID_CODE = 16,
LPC2000_INVALID_BAUD_RATE = 17,
LPC2000_INVALID_STOP_BIT = 18,
LPC2000_CRP_ENABLED = 19
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>");
static int lpc2000_build_sector_list(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc2000_build_sector_list(struct flash_bank_s *bank)
{
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
int i;
uint32_t offset = 0;
@@ -122,7 +105,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
if (bank->size == 128 * 1024)
{
bank->num_sectors = 16;
bank->sectors = malloc(sizeof(struct flash_sector) * 16);
bank->sectors = malloc(sizeof(flash_sector_t) * 16);
for (i = 0; i < 16; i++)
{
bank->sectors[i].offset = offset;
@@ -135,7 +118,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
else if (bank->size == 256 * 1024)
{
bank->num_sectors = 18;
bank->sectors = malloc(sizeof(struct flash_sector) * 18);
bank->sectors = malloc(sizeof(flash_sector_t) * 18);
for (i = 0; i < 8; i++)
{
@@ -196,24 +179,21 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
case 256 * 1024:
bank->num_sectors = 15;
break;
case 512 * 1024:
case 500 * 1024:
bank->num_sectors = 27;
break;
case 512 * 1024:
case 504 * 1024:
bank->num_sectors = 28;
break;
default:
LOG_ERROR("BUG: unknown bank->size encountered");
exit(-1);
break;
}
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
for (i = 0; i < bank->num_sectors; i++)
{
if (i < 8)
if ((i >= 0) && (i < 8))
{
bank->sectors[i].offset = offset;
bank->sectors[i].size = 4 * 1024;
@@ -221,7 +201,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
else if (i < 22)
if ((i >= 8) && (i < 22))
{
bank->sectors[i].offset = offset;
bank->sectors[i].size = 32 * 1024;
@@ -229,7 +209,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
bank->sectors[i].is_erased = -1;
bank->sectors[i].is_protected = 1;
}
else if (i < 28)
if ((i >= 22) && (i < 27))
{
bank->sectors[i].offset = offset;
bank->sectors[i].size = 4 * 1024;
@@ -263,7 +243,7 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
exit(-1);
}
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
for(i = 0; i < bank->num_sectors; i++)
{
@@ -291,15 +271,15 @@ static int lpc2000_build_sector_list(struct flash_bank *bank)
* 0x20 to 0x33: command result table (1+4 words)
* 0x34 to 0xb3: stack (only 128b needed)
*/
static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
static int lpc2000_iap_call(flash_bank_t *bank, int code, uint32_t param_table[5], uint32_t result_table[4])
{
int retval;
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
struct target *target = bank->target;
struct mem_param mem_params[2];
struct reg_param reg_params[5];
struct arm_algorithm armv4_5_info; /* for LPC2000 */
struct armv7m_algorithm armv7m_info; /* for LPC1700 */
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
target_t *target = bank->target;
mem_param_t mem_params[2];
reg_param_t reg_params[5];
armv4_5_algorithm_t armv4_5_info; /* for LPC2000 */
armv7m_algorithm_t armv7m_info; /* for LPC1700 */
uint32_t status_code;
uint32_t iap_entry_point = 0; /* to make compiler happier */
@@ -319,10 +299,8 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
switch(lpc2000_info->variant)
{
case lpc1700:
target_buffer_set_u32(target, jump_gate,
ARMV4_5_T_BX(12));
target_buffer_set_u32(target, jump_gate + 4,
ARMV5_T_BKPT(0));
target_buffer_set_u32(target, jump_gate, ARMV7M_T_BX(12));
target_buffer_set_u32(target, jump_gate + 4, ARMV7M_T_B(0xfffffe));
break;
case lpc2000_v1:
case lpc2000_v2:
@@ -350,9 +328,9 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
break;
case lpc2000_v1:
case lpc2000_v2:
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
armv4_5_info.core_mode = ARM_MODE_SVC;
armv4_5_info.core_state = ARM_STATE_ARM;
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;
iap_entry_point = 0x7ffffff1;
break;
default:
@@ -393,12 +371,12 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &armv7m_info);
break;
case lpc2000_v1:
case lpc2000_v2:
/* IAP stack */
init_reg_param(&reg_params[3], "sp_svc", 32, PARAM_OUT);
init_reg_param(&reg_params[3], "r13_svc", 32, PARAM_OUT);
buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4);
/* return address */
@@ -434,7 +412,7 @@ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_ta
return status_code;
}
static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
static int lpc2000_iap_blank_check(struct flash_bank_s *bank, int first, int last)
{
uint32_t param_table[5];
uint32_t result_table[4];
@@ -478,20 +456,20 @@ static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last)
/*
* flash bank lpc2000 <base> <size> 0 0 <target#> <lpc_variant> <cclk> [calc_checksum]
*/
FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
static int lpc2000_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct lpc2000_flash_bank *lpc2000_info;
lpc2000_flash_bank_t *lpc2000_info;
if (CMD_ARGC < 8)
if (argc < 8)
{
LOG_WARNING("incomplete flash_bank lpc2000 configuration");
return ERROR_FLASH_BANK_INVALID;
}
lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank));
lpc2000_info = malloc(sizeof(lpc2000_flash_bank_t));
bank->driver_priv = lpc2000_info;
if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0)
if (strcmp(args[6], "lpc2000_v1") == 0)
{
lpc2000_info->variant = lpc2000_v1;
lpc2000_info->cmd51_dst_boundary = 512;
@@ -499,7 +477,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
lpc2000_info->cmd51_can_8192b = 1;
lpc2000_info->checksum_vector = 5;
}
else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0)
else if (strcmp(args[6], "lpc2000_v2") == 0)
{
lpc2000_info->variant = lpc2000_v2;
lpc2000_info->cmd51_dst_boundary = 256;
@@ -507,7 +485,7 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
lpc2000_info->cmd51_can_8192b = 0;
lpc2000_info->checksum_vector = 5;
}
else if (strcmp(CMD_ARGV[6], "lpc1700") == 0)
else if (strcmp(args[6], "lpc1700") == 0)
{
lpc2000_info->variant = lpc1700;
lpc2000_info->cmd51_dst_boundary = 256;
@@ -517,28 +495,28 @@ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command)
}
else
{
LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]);
LOG_ERROR("unknown LPC2000 variant: %s", args[6]);
free(lpc2000_info);
return ERROR_FLASH_BANK_INVALID;
}
lpc2000_info->iap_working_area = NULL;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk);
lpc2000_info->cclk = strtoul(args[7], NULL, 0);
lpc2000_info->calc_checksum = 0;
lpc2000_build_sector_list(bank);
if (CMD_ARGC >= 9)
if (argc >= 9)
{
if (strcmp(CMD_ARGV[8], "calc_checksum") == 0)
if (strcmp(args[8], "calc_checksum") == 0)
lpc2000_info->calc_checksum = 1;
}
return ERROR_OK;
}
static int lpc2000_erase(struct flash_bank *bank, int first, int last)
static int lpc2000_erase(struct flash_bank_s *bank, int first, int last)
{
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
uint32_t param_table[5];
uint32_t result_table[4];
int status_code;
@@ -588,16 +566,16 @@ static int lpc2000_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last)
static int lpc2000_protect(struct flash_bank_s *bank, int set, int first, int last)
{
/* can't protect/unprotect on the lpc2000 */
return ERROR_OK;
}
static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int lpc2000_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
struct target *target = bank->target;
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
target_t *target = bank->target;
uint32_t dst_min_alignment;
uint32_t bytes_remaining = count;
uint32_t bytes_written = 0;
@@ -607,7 +585,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
uint32_t result_table[4];
int status_code;
int i;
struct working_area *download_area;
working_area_t *download_area;
int retval = ERROR_OK;
if (bank->target->state != TARGET_HALTED)
@@ -631,7 +609,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
{
if (offset >= bank->sectors[i].offset)
first_sector = i;
if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
if (offset + CEIL(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset)
last_sector = i;
}
@@ -641,6 +619,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum)
{
uint32_t checksum = 0;
int i;
for (i = 0; i < 8; i++)
{
LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32));
@@ -761,7 +740,7 @@ static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
return retval;
}
static int lpc2000_probe(struct flash_bank *bank)
static 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
@@ -769,7 +748,7 @@ static int lpc2000_probe(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc2000_erase_check(struct flash_bank *bank)
static int lpc2000_erase_check(struct flash_bank_s *bank)
{
if (bank->target->state != TARGET_HALTED)
{
@@ -780,36 +759,39 @@ static int lpc2000_erase_check(struct flash_bank *bank)
return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1);
}
static int lpc2000_protect_check(struct flash_bank *bank)
static int lpc2000_protect_check(struct flash_bank_s *bank)
{
/* sectors are always protected */
return ERROR_OK;
}
static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size)
static int lpc2000_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
lpc2000_flash_bank_t *lpc2000_info = bank->driver_priv;
snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz" , lpc2000_info->variant, lpc2000_info->cclk);
return ERROR_OK;
}
COMMAND_HANDLER(lpc2000_handle_part_id_command)
static int lpc2000_handle_part_id_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
flash_bank_t *bank;
uint32_t param_table[5];
uint32_t result_table[4];
int status_code;
if (CMD_ARGC < 1)
if (argc < 1)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
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;
}
if (bank->target->state != TARGET_HALTED)
{
@@ -821,49 +803,15 @@ COMMAND_HANDLER(lpc2000_handle_part_id_command)
{
if (status_code == ERROR_FLASH_OPERATION_FAILED)
{
command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface");
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);
command_print(cmd_ctx, "lpc2000 IAP returned status code %i", status_code);
}
else
{
command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
command_print(cmd_ctx, "lpc2000 part id: 0x%8.8" PRIx32 , result_table[0]);
}
return ERROR_OK;
}
static const struct command_registration lpc2000_exec_command_handlers[] = {
{
.name = "part_id",
.handler = lpc2000_handle_part_id_command,
.mode = COMMAND_EXEC,
.help = "print part id of lpc2000 flash bank <num>",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration lpc2000_command_handlers[] = {
{
.name = "lpc2000",
.mode = COMMAND_ANY,
.help = "lpc2000 flash command group",
.chain = lpc2000_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
struct flash_driver lpc2000_flash = {
.name = "lpc2000",
.commands = lpc2000_command_handlers,
.flash_bank_command = lpc2000_flash_bank_command,
.erase = lpc2000_erase,
.protect = lpc2000_protect,
.write = lpc2000_write,
.read = default_flash_read,
.probe = lpc2000_probe,
.auto_probe = lpc2000_probe,
.erase_check = lpc2000_erase_check,
.protect_check = lpc2000_protect_check,
.info = get_lpc2000_info,
};

View File

@@ -1,12 +1,9 @@
/***************************************************************************
* Copyright (C) 2006 by Dominic Rath *
* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius *
* didele.deze@gmail.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 *
@@ -23,20 +20,54 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef LPC2000_H
#define LPC2000_H
#include "time_support.h"
#include "flash.h"
/* simple and low overhead fetching of ms counter. Use only
* the difference between ms counters returned from this fn.
*/
int64_t timeval_ms()
typedef enum
{
struct timeval now;
int retval = gettimeofday(&now, NULL);
if (retval < 0)
return retval;
return (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
}
lpc2000_v1,
lpc2000_v2,
lpc1700
} lpc2000_variant;
typedef struct lpc2000_flash_bank_s
{
lpc2000_variant variant;
struct working_area_s *iap_working_area;
uint32_t cclk;
int cmd51_dst_boundary;
int cmd51_can_256b;
int cmd51_can_8192b;
int calc_checksum;
uint32_t cmd51_max_buffer;
int checksum_vector;
} 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,
LPC2000_PARAM_ERROR = 12,
LPC2000_ADDR_ERROR = 13,
LPC2000_ADDR_NOT_MAPPED = 14,
LPC2000_CMD_NOT_LOCKED = 15,
LPC2000_INVALID_CODE = 16,
LPC2000_INVALID_BAUD_RATE = 17,
LPC2000_INVALID_STOP_BIT = 18,
LPC2000_CRP_ENABLED = 19
};
#endif /* LPC2000_H */

View File

@@ -31,8 +31,8 @@
#include "config.h"
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include "lpc288x.h"
#include "binarybuffer.h"
#define LOAD_TIMER_ERASE 0
@@ -84,28 +84,44 @@
/* F_CLK_TIME */
#define FCT_CLK_DIV_MASK 0x0FFF
struct lpc288x_flash_bank
static int lpc288x_register_commands(struct command_context_s *cmd_ctx);
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank);
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last);
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last);
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count);
static int lpc288x_probe(struct flash_bank_s *bank);
static int lpc288x_erase_check(struct flash_bank_s *bank);
static int lpc288x_protect_check(struct flash_bank_s *bank);
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size);
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout);
static void lpc288x_load_timer(int erase, struct target_s *target);
static void lpc288x_set_flash_clk(struct flash_bank_s *bank);
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank);
flash_driver_t lpc288x_flash =
{
uint32_t working_area;
uint32_t working_area_size;
/* chip id register */
uint32_t cidr;
const char * target_name;
uint32_t cclk;
uint32_t sector_size_break;
.name = "lpc288x",
.register_commands = lpc288x_register_commands,
.flash_bank_command = lpc288x_flash_bank_command,
.erase = lpc288x_erase,
.protect = lpc288x_protect,
.write = lpc288x_write,
.probe = lpc288x_probe,
.auto_probe = lpc288x_probe,
.erase_check = lpc288x_erase_check,
.protect_check = lpc288x_protect_check,
.info = lpc288x_info
};
static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout);
static void lpc288x_load_timer(int erase, struct target *target);
static void lpc288x_set_flash_clk(struct flash_bank *bank);
static uint32_t lpc288x_system_ready(struct flash_bank *bank);
static int lpc288x_register_commands(struct command_context_s *cmd_ctx)
{
return ERROR_OK;
}
static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
static uint32_t lpc288x_wait_status_busy(flash_bank_t *bank, int timeout)
{
uint32_t status;
struct target *target = bank->target;
target_t *target = bank->target;
do
{
alive_sleep(1);
@@ -122,10 +138,10 @@ static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout)
}
/* Read device id register and fill in driver info structure */
static int lpc288x_read_part_info(struct flash_bank *bank)
static int lpc288x_read_part_info(struct flash_bank_s *bank)
{
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
struct target *target = bank->target;
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
target_t *target = bank->target;
uint32_t cidr;
int i = 0;
@@ -150,7 +166,7 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
/* setup the sector info... */
offset = bank->base;
bank->num_sectors = 23;
bank->sectors = malloc(sizeof(struct flash_sector) * 23);
bank->sectors = malloc(sizeof(flash_sector_t) * 23);
for (i = 0; i < 15; i++)
{
@@ -172,28 +188,28 @@ static int lpc288x_read_part_info(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc288x_protect_check(struct flash_bank *bank)
static int lpc288x_protect_check(struct flash_bank_s *bank)
{
return ERROR_OK;
}
/* flash_bank LPC288x 0 0 0 0 <target#> <cclk> */
FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
static int lpc288x_flash_bank_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct flash_bank_s *bank)
{
struct lpc288x_flash_bank *lpc288x_info;
lpc288x_flash_bank_t *lpc288x_info;
if (CMD_ARGC < 6)
if (argc < 6)
{
LOG_WARNING("incomplete flash_bank LPC288x configuration");
return ERROR_FLASH_BANK_INVALID;
}
lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank));
lpc288x_info = malloc(sizeof(lpc288x_flash_bank_t));
bank->driver_priv = lpc288x_info;
/* part wasn't probed for info yet */
lpc288x_info->cidr = 0;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk);
lpc288x_info->cclk = strtoul(args[6], NULL, 0);
return ERROR_OK;
}
@@ -203,10 +219,10 @@ FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command)
* AHB = 12 MHz ?
* 12000000/66000 = 182
* CLK_DIV = 60 ? */
static void lpc288x_set_flash_clk(struct flash_bank *bank)
static void lpc288x_set_flash_clk(struct flash_bank_s *bank)
{
uint32_t clk_time;
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
clk_time = (lpc288x_info->cclk / 66000) / 3;
target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN);
target_write_u32(bank->target, F_CLK_TIME, clk_time);
@@ -218,7 +234,7 @@ static void lpc288x_set_flash_clk(struct flash_bank *bank)
* LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512
* = 23 (75) (AN10548 72 - is this wrong?)
* TODO: Sort out timing calcs ;) */
static void lpc288x_load_timer(int erase, struct target *target)
static void lpc288x_load_timer(int erase, struct target_s *target)
{
if (erase == LOAD_TIMER_ERASE)
{
@@ -230,9 +246,9 @@ static void lpc288x_load_timer(int erase, struct target *target)
}
}
static uint32_t lpc288x_system_ready(struct flash_bank *bank)
static uint32_t lpc288x_system_ready(struct flash_bank_s *bank)
{
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
if (lpc288x_info->cidr == 0)
{
return ERROR_FLASH_BANK_NOT_PROBED;
@@ -246,7 +262,7 @@ static uint32_t lpc288x_system_ready(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc288x_erase_check(struct flash_bank *bank)
static int lpc288x_erase_check(struct flash_bank_s *bank)
{
uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */
if (status != ERROR_OK)
@@ -258,11 +274,11 @@ static int lpc288x_erase_check(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc288x_erase(struct flash_bank *bank, int first, int last)
static int lpc288x_erase(struct flash_bank_s *bank, int first, int last)
{
uint32_t status;
int sector;
struct target *target = bank->target;
target_t *target = bank->target;
status = lpc288x_system_ready(bank); /* probed? halted? */
if (status != ERROR_OK)
@@ -299,11 +315,11 @@ static int lpc288x_erase(struct flash_bank *bank, int first, int last)
return ERROR_OK;
}
static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
static int lpc288x_write(struct flash_bank_s *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
uint8_t page_buffer[FLASH_PAGE_SIZE];
uint32_t status, source_offset,dest_offset;
struct target *target = bank->target;
target_t *target = bank->target;
uint32_t bytes_remaining = count;
uint32_t first_sector, last_sector, sector, page;
int i;
@@ -415,10 +431,10 @@ static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offs
return ERROR_OK;
}
static int lpc288x_probe(struct flash_bank *bank)
static int lpc288x_probe(struct flash_bank_s *bank)
{
/* we only deal with LPC2888 so flash config is fixed */
struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv;
lpc288x_flash_bank_t *lpc288x_info = bank->driver_priv;
int retval;
if (lpc288x_info->cidr != 0)
@@ -438,17 +454,17 @@ static int lpc288x_probe(struct flash_bank *bank)
return ERROR_OK;
}
static int lpc288x_info(struct flash_bank *bank, char *buf, int buf_size)
static int lpc288x_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "lpc288x flash driver");
return ERROR_OK;
}
static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last)
static int lpc288x_protect(struct flash_bank_s *bank, int set, int first, int last)
{
int lockregion, status;
uint32_t value;
struct target *target = bank->target;
target_t *target = bank->target;
/* probed? halted? */
status = lpc288x_system_ready(bank);
@@ -483,17 +499,3 @@ static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last
return ERROR_OK;
}
struct flash_driver lpc288x_flash = {
.name = "lpc288x",
.flash_bank_command = lpc288x_flash_bank_command,
.erase = lpc288x_erase,
.protect = lpc288x_protect,
.write = lpc288x_write,
.read = default_flash_read,
.probe = lpc288x_probe,
.auto_probe = lpc288x_probe,
.erase_check = lpc288x_erase_check,
.protect_check = lpc288x_protect_check,
.info = lpc288x_info,
};

View File

@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* Copyright (C) 2008 by *
* Karl RobinSod <karl.robinsod@gmail.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 *
@@ -18,17 +18,22 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef __DELAY_H
#define __DELAY_H
#ifndef lpc288x_H
#define lpc288x_H
#include "shorttypes.h"
#include "flash.h"
#define NOP {__asm nop __endasm;}
typedef struct lpc288x_flash_bank_s
{
uint32_t working_area;
uint32_t working_area_size;
void delay_5us(void);
void delay_1ms(void);
/* chip id register */
uint32_t cidr;
char * target_name;
uint32_t cclk;
void delay_us(u16 delay);
void delay_ms(u16 delay);
uint32_t sector_size_break;
} lpc288x_flash_bank_t;
#endif
#endif /* lpc288x_H */

View File

@@ -23,11 +23,11 @@
#endif
#include "imp.h"
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/arm.h>
#include <target/image.h>
#include "image.h"
#include "lpc2900.h"
#include "binarybuffer.h"
#include "armv4_5.h"
/* 1024 bytes */
@@ -129,13 +129,8 @@
/**
* Private data for \c lpc2900 flash driver.
*/
struct lpc2900_flash_bank
typedef struct lpc2900_flash_bank_s
{
/**
* This flag is set when the device has been successfully probed.
*/
bool is_probed;
/**
* Holds the value read from CHIPID register.
* The driver will not load if the chipid doesn't match the expected
@@ -173,18 +168,33 @@ struct lpc2900_flash_bank
*/
uint32_t max_ram_block;
};
} lpc2900_flash_bank_t;
static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout);
static void lpc2900_setup(struct flash_bank *bank);
static uint32_t lpc2900_is_ready(struct flash_bank *bank);
static uint32_t lpc2900_read_security_status(struct flash_bank *bank);
static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
static int lpc2900_register_commands(struct command_context_s *cmd_ctx);
static int lpc2900_flash_bank_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc,
struct flash_bank_s *bank);
static int lpc2900_erase(struct flash_bank_s *bank, int first, int last);
static int lpc2900_protect(struct flash_bank_s *bank, int set, int first, int last);
static int lpc2900_write(struct flash_bank_s *bank,
uint8_t *buffer, uint32_t offset, uint32_t count);
static int lpc2900_probe(struct flash_bank_s *bank);
static int lpc2900_erase_check(struct flash_bank_s *bank);
static int lpc2900_protect_check(struct flash_bank_s *bank);
static int lpc2900_info(struct flash_bank_s *bank, char *buf, int buf_size);
static uint32_t lpc2900_wait_status(flash_bank_t *bank, uint32_t mask, int timeout);
static void lpc2900_setup(struct flash_bank_s *bank);
static uint32_t lpc2900_is_ready(struct flash_bank_s *bank);
static uint32_t lpc2900_read_security_status(struct flash_bank_s *bank);
static uint32_t lpc2900_run_bist128(struct flash_bank_s *bank,
uint32_t addr_from, uint32_t addr_to,
uint32_t (*signature)[4] );
static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset);
static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var);
static uint32_t lpc2900_address2sector(struct flash_bank_s *bank, uint32_t offset);
static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time );
/*********************** Helper functions **************************/
@@ -199,12 +209,12 @@ static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var);
* @param[in] mask Mask to be used for INT_STATUS
* @param[in] timeout Timeout in ms
*/
static uint32_t lpc2900_wait_status( struct flash_bank *bank,
static uint32_t lpc2900_wait_status( flash_bank_t *bank,
uint32_t mask,
int timeout )
{
uint32_t int_status;
struct target *target = bank->target;
target_t *target = bank->target;
do
@@ -233,10 +243,10 @@ static uint32_t lpc2900_wait_status( struct flash_bank *bank,
*
* @param bank Pointer to the flash bank descriptor
*/
static void lpc2900_setup( struct flash_bank *bank )
static void lpc2900_setup( struct flash_bank_s *bank )
{
uint32_t fcra;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
/* Power up the flash block */
@@ -256,11 +266,11 @@ static void lpc2900_setup( struct flash_bank *bank )
* Must have been successfully probed.
* Must be halted.
*/
static uint32_t lpc2900_is_ready( struct flash_bank *bank )
static uint32_t lpc2900_is_ready( struct flash_bank_s *bank )
{
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
if( !lpc2900_info->is_probed )
if( lpc2900_info->chipid != EXPECTED_CHIPID )
{
return ERROR_FLASH_BANK_NOT_PROBED;
}
@@ -280,7 +290,7 @@ static uint32_t lpc2900_is_ready( struct flash_bank *bank )
*
* @param bank Pointer to the flash bank descriptor
*/
static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
static uint32_t lpc2900_read_security_status( struct flash_bank_s *bank )
{
uint32_t status;
if( (status = lpc2900_is_ready( bank )) != ERROR_OK )
@@ -288,7 +298,7 @@ static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
return status;
}
struct target *target = bank->target;
target_t *target = bank->target;
/* Enable ISS access */
target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS);
@@ -311,39 +321,39 @@ static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
* a protected sector!
*/
int sector;
int index_t;
int index;
for( sector = 0; sector < bank->num_sectors; sector++ )
{
/* Convert logical sector number to physical sector number */
if( sector <= 4 )
{
index_t = sector + 11;
index = sector + 11;
}
else if( sector <= 7 )
{
index_t = sector + 27;
index = sector + 27;
}
else
{
index_t = sector - 8;
index = sector - 8;
}
bank->sectors[sector].is_protected = -1;
if (
(iss_secured_field[index_t][0] == 0x00000000) &&
(iss_secured_field[index_t][1] == 0x00000000) &&
(iss_secured_field[index_t][2] == 0x00000000) &&
(iss_secured_field[index_t][3] == 0x00000000) )
(iss_secured_field[index][0] == 0x00000000) &&
(iss_secured_field[index][1] == 0x00000000) &&
(iss_secured_field[index][2] == 0x00000000) &&
(iss_secured_field[index][3] == 0x00000000) )
{
bank->sectors[sector].is_protected = 1;
}
if (
(iss_secured_field[index_t][0] == 0xFFFFFFFF) &&
(iss_secured_field[index_t][1] == 0xFFFFFFFF) &&
(iss_secured_field[index_t][2] == 0xFFFFFFFF) &&
(iss_secured_field[index_t][3] == 0xFFFFFFFF) )
(iss_secured_field[index][0] == 0xFFFFFFFF) &&
(iss_secured_field[index][1] == 0xFFFFFFFF) &&
(iss_secured_field[index][2] == 0xFFFFFFFF) &&
(iss_secured_field[index][3] == 0xFFFFFFFF) )
{
bank->sectors[sector].is_protected = 0;
}
@@ -361,12 +371,12 @@ static uint32_t lpc2900_read_security_status( struct flash_bank *bank )
* @param addr_to
* @param signature
*/
static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
static uint32_t lpc2900_run_bist128(struct flash_bank_s *bank,
uint32_t addr_from,
uint32_t addr_to,
uint32_t (*signature)[4] )
{
struct target *target = bank->target;
target_t *target = bank->target;
/* Clear END_OF_MISR interrupt status */
target_write_u32( target, INT_CLR_STATUS, INTSRC_END_OF_MISR );
@@ -398,7 +408,7 @@ static uint32_t lpc2900_run_bist128(struct flash_bank *bank,
* @param bank Pointer to the flash bank descriptor
* @param offset Offset address relative to bank start
*/
static uint32_t lpc2900_address2sector( struct flash_bank *bank,
static uint32_t lpc2900_address2sector( struct flash_bank_s *bank,
uint32_t offset )
{
uint32_t address = bank->base + offset;
@@ -429,7 +439,7 @@ static uint32_t lpc2900_address2sector( struct flash_bank *bank,
* @param pagenum Page number (0...7)
* @param page Page array (FLASH_PAGE_SIZE bytes)
*/
static int lpc2900_write_index_page( struct flash_bank *bank,
static int lpc2900_write_index_page( struct flash_bank_s *bank,
int pagenum,
uint8_t (*page)[FLASH_PAGE_SIZE] )
{
@@ -441,7 +451,7 @@ static int lpc2900_write_index_page( struct flash_bank *bank,
}
/* Get target, and check if it's halted */
struct target *target = bank->target;
target_t *target = bank->target;
if( target->state != TARGET_HALTED )
{
LOG_ERROR( "Target not halted" );
@@ -449,7 +459,7 @@ static int lpc2900_write_index_page( struct flash_bank *bank,
}
/* Private info */
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
/* Enable flash block and set the correct CRA clock of 66 kHz */
lpc2900_setup( bank );
@@ -512,14 +522,16 @@ static int lpc2900_write_index_page( struct flash_bank *bank,
* @param clock System clock in Hz
* @param time Program/erase time in µs
*/
static uint32_t lpc2900_calc_tr( uint32_t clock_var, uint32_t time_var )
static uint32_t lpc2900_calc_tr( uint32_t clock, uint32_t time )
{
/* ((time[µs]/1e6) * f[Hz]) + 511
* FPTR.TR = -------------------------------
* 512
*
* The result is the
*/
uint32_t tr_val = (uint32_t)((((time_var / 1e6) * clock_var) + 511.0) / 512.0);
uint32_t tr_val = (uint32_t)((((time / 1e6) * clock) + 511.0) / 512.0);
return tr_val;
}
@@ -533,23 +545,33 @@ static uint32_t lpc2900_calc_tr( uint32_t clock_var, uint32_t time_var )
*
* Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value
* of the flash content.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_signature_command)
static int lpc2900_handle_signature_command( struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc )
{
flash_bank_t *bank;
uint32_t status;
uint32_t signature[4];
if( CMD_ARGC < 1 )
if( argc < 1 )
{
LOG_WARNING( "Too few arguments. Call: lpc2900 signature <bank#>" );
return ERROR_FLASH_BANK_INVALID;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
/* Get the bank descriptor */
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;
}
if( bank->target->state != TARGET_HALTED )
{
@@ -567,7 +589,7 @@ COMMAND_HANDLER(lpc2900_handle_signature_command)
return status;
}
command_print( CMD_CTX, "signature: 0x%8.8" PRIx32
command_print( cmd_ctx, "signature: 0x%8.8" PRIx32
":0x%8.8" PRIx32
":0x%8.8" PRIx32
":0x%8.8" PRIx32,
@@ -583,24 +605,35 @@ COMMAND_HANDLER(lpc2900_handle_signature_command)
*
* Read customer info from index sector, and store that block of data into
* a disk file. The format is binary.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_read_custom_command)
static int lpc2900_handle_read_custom_command( struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc )
{
if( CMD_ARGC < 2 )
flash_bank_t *bank;
if( argc < 2 )
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
/* Get the bank descriptor */
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;
}
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
lpc2900_info->risky = 0;
/* Get target, and check if it's halted */
struct target *target = bank->target;
target_t *target = bank->target;
if( target->state != TARGET_HALTED )
{
LOG_ERROR( "Target not halted" );
@@ -625,8 +658,8 @@ COMMAND_HANDLER(lpc2900_handle_read_custom_command)
target_write_u32( target, FCTR, FCTR_FS_CS | FCTR_FS_WEB );
/* Try and open the file */
struct fileio fileio;
const char *filename = CMD_ARGV[1];
fileio_t fileio;
char *filename = args[1];
int ret = fileio_open( &fileio, filename, FILEIO_WRITE, FILEIO_BINARY );
if( ret != ERROR_OK )
{
@@ -634,7 +667,7 @@ COMMAND_HANDLER(lpc2900_handle_read_custom_command)
return ret;
}
size_t nwritten;
uint32_t nwritten;
ret = fileio_write( &fileio, sizeof(customer),
(const uint8_t *)customer, &nwritten );
if( ret != ERROR_OK )
@@ -654,32 +687,43 @@ COMMAND_HANDLER(lpc2900_handle_read_custom_command)
/**
* Enter password to enable potentially dangerous options.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_password_command)
static int lpc2900_handle_password_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc)
{
if (CMD_ARGC < 2)
flash_bank_t *bank;
if (argc < 2)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
/* Get the bank descriptor */
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;
}
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
#define ISS_PASSWORD "I_know_what_I_am_doing"
lpc2900_info->risky = !strcmp( CMD_ARGV[1], ISS_PASSWORD );
lpc2900_info->risky = !strcmp( args[1], ISS_PASSWORD );
if( !lpc2900_info->risky )
{
command_print(CMD_CTX, "Wrong password (use '%s')", ISS_PASSWORD);
command_print(cmd_ctx, "Wrong password (use '%s')", ISS_PASSWORD);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
command_print(CMD_CTX,
command_print(cmd_ctx,
"Potentially dangerous operation allowed in next command!");
return ERROR_OK;
@@ -689,31 +733,39 @@ COMMAND_HANDLER(lpc2900_handle_password_command)
/**
* Write customer info from file to the index sector.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_write_custom_command)
static int lpc2900_handle_write_custom_command( struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc )
{
if (CMD_ARGC < 2)
if (argc < 2)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
/* Get the bank descriptor */
flash_bank_t *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;
}
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
/* Check if command execution is allowed. */
if( !lpc2900_info->risky )
{
command_print( CMD_CTX, "Command execution not allowed!" );
command_print( cmd_ctx, "Command execution not allowed!" );
return ERROR_COMMAND_ARGUMENT_INVALID;
}
lpc2900_info->risky = 0;
/* Get target, and check if it's halted */
struct target *target = bank->target;
target_t *target = bank->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("Target not halted");
@@ -721,14 +773,14 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command)
}
/* The image will always start at offset 0 */
struct image image;
image_t image;
image.base_address_set = 1;
image.base_address = 0;
image.start_address_set = 0;
const char *filename = CMD_ARGV[1];
const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL;
retval = image_open(&image, filename, type);
char *filename = args[1];
char *type = (argc >= 3) ? args[2] : NULL;
int retval = image_open(&image, filename, type);
if (retval != ERROR_OK)
{
return retval;
@@ -758,7 +810,7 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command)
/* Page 4 */
uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE;
memset( page, 0xff, FLASH_PAGE_SIZE );
size_t size_read;
uint32_t size_read;
retval = image_read_section( &image, 0, 0,
ISS_CUSTOMER_SIZE1, &page[offset], &size_read);
if( retval != ERROR_OK )
@@ -799,45 +851,52 @@ COMMAND_HANDLER(lpc2900_handle_write_custom_command)
/**
* Activate 'sector security' for a range of sectors.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
static int lpc2900_handle_secure_sector_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc)
{
if (CMD_ARGC < 3)
if (argc < 3)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
/* Get the bank descriptor */
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
flash_bank_t *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;
}
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
/* Check if command execution is allowed. */
if( !lpc2900_info->risky )
{
command_print( CMD_CTX, "Command execution not allowed! "
command_print( cmd_ctx, "Command execution not allowed! "
"(use 'password' command first)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
lpc2900_info->risky = 0;
/* Read sector range, and do a sanity check. */
int first, last;
COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first);
COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last);
int first = strtoul(args[1], NULL, 0);
int last = strtoul(args[2], NULL, 0);
if( (first >= bank->num_sectors) ||
(last >= bank->num_sectors) ||
(first > last) )
{
command_print( CMD_CTX, "Illegal sector range" );
command_print( cmd_ctx, "Illegal sector range" );
return ERROR_COMMAND_ARGUMENT_INVALID;
}
uint8_t page[FLASH_PAGE_SIZE];
int sector;
int retval;
/* Sectors in page 6 */
if( (first <= 4) || (last >= 8) )
@@ -881,7 +940,7 @@ COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
}
}
command_print( CMD_CTX,
command_print( cmd_ctx,
"Sectors security will become effective after next power cycle");
/* Update the sector security status */
@@ -898,26 +957,33 @@ COMMAND_HANDLER(lpc2900_handle_secure_sector_command)
/**
* Activate JTAG protection.
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
*/
COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
static int lpc2900_handle_secure_jtag_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc)
{
if (CMD_ARGC < 1)
if (argc < 1)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
/* Get the bank descriptor */
struct flash_bank *bank;
int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
if (ERROR_OK != retval)
return retval;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
flash_bank_t *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;
}
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
/* Check if command execution is allowed. */
if( !lpc2900_info->risky )
{
command_print( CMD_CTX, "Command execution not allowed! "
command_print( cmd_ctx, "Command execution not allowed! "
"(use 'password' command first)");
return ERROR_COMMAND_ARGUMENT_INVALID;
}
@@ -935,6 +1001,7 @@ COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
page[0x30 + 3] = 0x7F;
/* Write to page 5 */
int retval;
if( (retval = lpc2900_write_index_page( bank, 5, &page ))
!= ERROR_OK )
{
@@ -951,86 +1018,106 @@ COMMAND_HANDLER(lpc2900_handle_secure_jtag_command)
/*********************** Flash interface functions **************************/
static const struct command_registration lpc2900_exec_command_handlers[] = {
{
.name = "signature",
.handler = lpc2900_handle_signature_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Calculate and display signature of flash bank.",
},
{
.name = "read_custom",
.handler = lpc2900_handle_read_custom_command,
.mode = COMMAND_EXEC,
.usage = "bank_id filename",
.help = "Copies 912 bytes of customer information "
"from index sector into file.",
},
{
.name = "password",
.handler = lpc2900_handle_password_command,
.mode = COMMAND_EXEC,
.usage = "bank_id password",
.help = "Enter fixed password to enable 'dangerous' options.",
},
{
.name = "write_custom",
.handler = lpc2900_handle_write_custom_command,
.mode = COMMAND_EXEC,
.usage = "bank_id filename ('bin'|'ihex'|'elf'|'s19')",
.help = "Copies 912 bytes of customer info from file "
"to index sector.",
},
{
.name = "secure_sector",
.handler = lpc2900_handle_secure_sector_command,
.mode = COMMAND_EXEC,
.usage = "bank_id first_sector last_sector",
.help = "Activate sector security for a range of sectors. "
"It will be effective after a power cycle.",
},
{
.name = "secure_jtag",
.handler = lpc2900_handle_secure_jtag_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
.help = "Disable the JTAG port. "
"It will be effective after a power cycle.",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration lpc2900_command_handlers[] = {
{
.name = "lpc2900",
.mode = COMMAND_ANY,
.help = "LPC2900 flash command group",
.chain = lpc2900_exec_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/// Evaluate flash bank command.
FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
/**
* Register private command handlers.
*
* @param cmd_ctx
*/
static int lpc2900_register_commands(struct command_context_s *cmd_ctx)
{
struct lpc2900_flash_bank *lpc2900_info;
command_t *lpc2900_cmd = register_command(cmd_ctx, NULL, "lpc2900",
NULL, COMMAND_ANY, NULL);
if (CMD_ARGC < 6)
register_command(
cmd_ctx,
lpc2900_cmd,
"signature",
lpc2900_handle_signature_command,
COMMAND_EXEC,
"<bank> | "
"print device signature of flash bank");
register_command(
cmd_ctx,
lpc2900_cmd,
"read_custom",
lpc2900_handle_read_custom_command,
COMMAND_EXEC,
"<bank> <filename> | "
"read customer information from index sector to file");
register_command(
cmd_ctx,
lpc2900_cmd,
"password",
lpc2900_handle_password_command,
COMMAND_EXEC,
"<bank> <password> | "
"enter password to enable 'dangerous' options");
register_command(
cmd_ctx,
lpc2900_cmd,
"write_custom",
lpc2900_handle_write_custom_command,
COMMAND_EXEC,
"<bank> <filename> [<type>] | "
"write customer info from file to index sector");
register_command(
cmd_ctx,
lpc2900_cmd,
"secure_sector",
lpc2900_handle_secure_sector_command,
COMMAND_EXEC,
"<bank> <first> <last> | "
"activate sector security for a range of sectors");
register_command(
cmd_ctx,
lpc2900_cmd,
"secure_jtag",
lpc2900_handle_secure_jtag_command,
COMMAND_EXEC,
"<bank> <level> | "
"activate JTAG security");
return ERROR_OK;
}
/**
* Evaluate flash bank command.
*
* Syntax: flash bank lpc2900 0 0 0 0 target# system_base_clock
*
* @param cmd_ctx
* @param cmd
* @param args
* @param argc
* @param bank Pointer to the flash bank descriptor
*/
static int lpc2900_flash_bank_command(struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc,
struct flash_bank_s *bank)
{
lpc2900_flash_bank_t *lpc2900_info;
if (argc < 6)
{
LOG_WARNING("incomplete flash_bank LPC2900 configuration");
return ERROR_FLASH_BANK_INVALID;
}
lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank));
lpc2900_info = malloc(sizeof(lpc2900_flash_bank_t));
bank->driver_priv = lpc2900_info;
/* Get flash clock.
* Reject it if we can't meet the requirements for program time
* (if clock too slow), or for erase time (clock too fast).
*/
uint32_t clk_sys_fmc;
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc);
lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000;
lpc2900_info->clk_sys_fmc = strtoul(args[6], NULL, 0) * 1000;
uint32_t clock_limit;
/* Check program time limit */
@@ -1053,7 +1140,6 @@ FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
/* Chip ID will be obtained by probing the device later */
lpc2900_info->chipid = 0;
lpc2900_info->is_probed = false;
return ERROR_OK;
}
@@ -1066,13 +1152,13 @@ FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command)
* @param first First sector to be erased
* @param last Last sector (including) to be erased
*/
static int lpc2900_erase(struct flash_bank *bank, int first, int last)
static int lpc2900_erase(struct flash_bank_s *bank, int first, int last)
{
uint32_t status;
int sector;
int last_unsecured_sector;
struct target *target = bank->target;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
target_t *target = bank->target;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
status = lpc2900_is_ready(bank);
@@ -1173,7 +1259,7 @@ static int lpc2900_erase(struct flash_bank *bank, int first, int last)
static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last)
static int lpc2900_protect(struct flash_bank_s *bank, int set, int first, int last)
{
/* This command is not supported.
* "Protection" in LPC2900 terms is handled transparently. Sectors will
@@ -1195,14 +1281,14 @@ static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last
* @param offset Start address (relative to bank start)
* @param count Number of bytes to be programmed
*/
static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
static int lpc2900_write(struct flash_bank_s *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
uint8_t page[FLASH_PAGE_SIZE];
uint32_t status;
uint32_t num_bytes;
struct target *target = bank->target;
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
target_t *target = bank->target;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
int sector;
int retval;
@@ -1290,9 +1376,9 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
/* Try working area allocation. Start with a large buffer, and try with
reduced size if that fails. */
struct working_area *warea;
working_area_t *warea;
uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB;
while( (retval = target_alloc_working_area_try(target,
while( (retval = target_alloc_working_area(target,
buffer_size + target_code_size,
&warea)) != ERROR_OK )
{
@@ -1309,8 +1395,8 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
if( warea )
{
struct reg_param reg_params[5];
struct arm_algorithm armv4_5_info;
reg_param_t reg_params[5];
armv4_5_algorithm_t armv4_5_info;
/* We can use target mode. Download the algorithm. */
retval = target_write_buffer( target,
@@ -1369,7 +1455,7 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
this_buffer = buffer;
/* Make sure we stop at the next secured sector */
sector = start_sector + 1;
int sector = start_sector + 1;
while( sector < bank->num_sectors )
{
/* Secured? */
@@ -1431,9 +1517,9 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time);
/* Execute algorithm, assume breakpoint for last instruction */
armv4_5_info.common_magic = ARM_COMMON_MAGIC;
armv4_5_info.core_mode = ARM_MODE_SVC;
armv4_5_info.core_state = ARM_STATE_ARM;
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;
retval = target_run_algorithm(target, 0, NULL, 5, reg_params,
(warea->address) + buffer_size,
@@ -1544,10 +1630,10 @@ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer,
*
* @param bank Pointer to the flash bank descriptor
*/
static int lpc2900_probe(struct flash_bank *bank)
static int lpc2900_probe(struct flash_bank_s *bank)
{
struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv;
struct target *target = bank->target;
lpc2900_flash_bank_t *lpc2900_info = bank->driver_priv;
target_t *target = bank->target;
int i = 0;
uint32_t offset;
@@ -1558,8 +1644,10 @@ static int lpc2900_probe(struct flash_bank *bank)
return ERROR_TARGET_NOT_HALTED;
}
/* We want to do this only once. */
if (lpc2900_info->is_probed)
/* We want to do this only once. Check if we already have a valid CHIPID,
* because then we will have already successfully probed the device.
*/
if (lpc2900_info->chipid == EXPECTED_CHIPID)
{
return ERROR_OK;
}
@@ -1638,11 +1726,7 @@ static int lpc2900_probe(struct flash_bank *bank)
else if ( package_code == 4 )
{
/* 144-pin package */
if ( (bank->size == 256*KiB) && (feat3 == 0xFFFFFFE9) )
{
lpc2900_info->target_name = "LPC2926";
}
else if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
if ( (bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0) )
{
lpc2900_info->target_name = "LPC2917/01";
}
@@ -1676,11 +1760,7 @@ static int lpc2900_probe(struct flash_bank *bank)
if ( !found )
{
LOG_WARNING("Unknown LPC29xx derivative"
" (FEATx="
"%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ")",
feat0, feat1, feat2, feat3
);
LOG_WARNING("Unknown LPC29xx derivative");
return ERROR_FLASH_OPERATION_FAILED;
}
@@ -1704,7 +1784,7 @@ static int lpc2900_probe(struct flash_bank *bank)
* the logical flash number are translated into the physical flash numbers
* of the device.
*/
bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
bank->sectors = malloc(sizeof(flash_sector_t) * bank->num_sectors);
offset = 0;
for (i = 0; i < bank->num_sectors; i++)
@@ -1733,8 +1813,6 @@ static int lpc2900_probe(struct flash_bank *bank)
offset += bank->sectors[i].size;
}
lpc2900_info->is_probed = true;
/* Read sector security status */
if ( lpc2900_read_security_status(bank) != ERROR_OK )
{
@@ -1755,7 +1833,7 @@ static int lpc2900_probe(struct flash_bank *bank)
*
* @param bank Pointer to the flash bank descriptor
*/
static int lpc2900_erase_check(struct flash_bank *bank)
static int lpc2900_erase_check(struct flash_bank_s *bank)
{
uint32_t status = lpc2900_is_ready(bank);
if (status != ERROR_OK)
@@ -1813,7 +1891,7 @@ static int lpc2900_erase_check(struct flash_bank *bank)
*
* @param bank Pointer to the flash bank descriptor
*/
static int lpc2900_protect_check(struct flash_bank *bank)
static int lpc2900_protect_check(struct flash_bank_s *bank)
{
return lpc2900_read_security_status(bank);
}
@@ -1826,7 +1904,7 @@ static int lpc2900_protect_check(struct flash_bank *bank)
* @param buf Buffer to take the string
* @param buf_size Maximum number of characters that the buffer can take
*/
static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size)
static int lpc2900_info(struct flash_bank_s *bank, char *buf, int buf_size)
{
snprintf(buf, buf_size, "lpc2900 flash driver");
@@ -1834,15 +1912,14 @@ static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size)
}
struct flash_driver lpc2900_flash =
flash_driver_t lpc2900_flash =
{
.name = "lpc2900",
.commands = lpc2900_command_handlers,
.register_commands = lpc2900_register_commands,
.flash_bank_command = lpc2900_flash_bank_command,
.erase = lpc2900_erase,
.protect = lpc2900_protect,
.write = lpc2900_write,
.read = default_flash_read,
.probe = lpc2900_probe,
.auto_probe = lpc2900_probe,
.erase_check = lpc2900_erase_check,

View File

@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
* Copyright (C) 2009 by *
* Rolf Meeser <rolfm_9dq@yahoo.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 *
@@ -18,9 +18,10 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef __MAIN_H
#define __MAIN_H
#ifndef lpc2900_H
#define lpc2900_H
void io_init(void);
#include "flash.h"
#endif
#endif /* lpc2900_H */

View File

@@ -0,0 +1,907 @@
/***************************************************************************
* Copyright (C) 2007 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 "lpc3180_nand_controller.h"
#include "nand.h"
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
static int lpc3180_register_commands(struct command_context_s *cmd_ctx);
static int lpc3180_init(struct nand_device_s *device);
static int lpc3180_reset(struct nand_device_s *device);
static int lpc3180_command(struct nand_device_s *device, uint8_t command);
static int lpc3180_address(struct nand_device_s *device, uint8_t address);
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data);
static int lpc3180_read_data(struct nand_device_s *device, void *data);
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout);
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout);
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
nand_flash_controller_t lpc3180_nand_controller =
{
.name = "lpc3180",
.nand_device_command = lpc3180_nand_device_command,
.register_commands = lpc3180_register_commands,
.init = lpc3180_init,
.reset = lpc3180_reset,
.command = lpc3180_command,
.address = lpc3180_address,
.write_data = lpc3180_write_data,
.read_data = lpc3180_read_data,
.write_page = lpc3180_write_page,
.read_page = lpc3180_read_page,
.controller_ready = lpc3180_controller_ready,
.nand_ready = lpc3180_nand_ready,
};
/* nand device lpc3180 <target#> <oscillator_frequency>
*/
static int lpc3180_nand_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device)
{
lpc3180_nand_controller_t *lpc3180_info;
if (argc < 3)
{
LOG_WARNING("incomplete 'lpc3180' nand flash configuration");
return ERROR_FLASH_BANK_INVALID;
}
lpc3180_info = malloc(sizeof(lpc3180_nand_controller_t));
device->controller_priv = lpc3180_info;
lpc3180_info->target = get_target(args[1]);
if (!lpc3180_info->target)
{
LOG_ERROR("target '%s' not defined", args[1]);
return ERROR_NAND_DEVICE_INVALID;
}
lpc3180_info->osc_freq = strtoul(args[2], NULL, 0);
if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000))
{
LOG_WARNING("LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq);
}
lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER;
lpc3180_info->sw_write_protection = 0;
lpc3180_info->sw_wp_lower_bound = 0x0;
lpc3180_info->sw_wp_upper_bound = 0x0;
return ERROR_OK;
}
static int lpc3180_register_commands(struct command_context_s *cmd_ctx)
{
command_t *lpc3180_cmd = register_command(cmd_ctx, NULL, "lpc3180", NULL, COMMAND_ANY, "commands specific to the LPC3180 NAND flash controllers");
register_command(cmd_ctx, lpc3180_cmd, "select", handle_lpc3180_select_command, COMMAND_EXEC, "select <'mlc'|'slc'> controller (default is mlc)");
return ERROR_OK;
}
static int lpc3180_pll(int fclkin, uint32_t pll_ctrl)
{
int bypass = (pll_ctrl & 0x8000) >> 15;
int direct = (pll_ctrl & 0x4000) >> 14;
int feedback = (pll_ctrl & 0x2000) >> 13;
int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2);
int n = ((pll_ctrl & 0x0600) >> 9) + 1;
int m = ((pll_ctrl & 0x01fe) >> 1) + 1;
int lock = (pll_ctrl & 0x1);
if (!lock)
LOG_WARNING("PLL is not locked");
if (!bypass && direct) /* direct mode */
return (m * fclkin) / n;
if (bypass && !direct) /* bypass mode */
return fclkin / (2 * p);
if (bypass & direct) /* direct bypass mode */
return fclkin;
if (feedback) /* integer mode */
return m * (fclkin / n);
else /* non-integer mode */
return (m / (2 * p)) * (fclkin / n);
}
static float lpc3180_cycle_time(lpc3180_nand_controller_t *lpc3180_info)
{
target_t *target = lpc3180_info->target;
uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl;
int sysclk;
int hclk;
int hclk_pll;
float cycle;
/* calculate timings */
/* determine current SYSCLK (13'MHz or main oscillator) */
target_read_u32(target, 0x40004050, &sysclk_ctrl);
if ((sysclk_ctrl & 1) == 0)
sysclk = lpc3180_info->osc_freq;
else
sysclk = 13000;
/* determine selected HCLK source */
target_read_u32(target, 0x40004044, &pwr_ctrl);
if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */
{
hclk = sysclk;
}
else
{
target_read_u32(target, 0x40004058, &hclkpll_ctrl);
hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl);
target_read_u32(target, 0x40004040, &hclkdiv_ctrl);
if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */
{
hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1);
}
else /* HCLK uses HCLK_PLL */
{
hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3));
}
}
LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk);
cycle = (1.0 / hclk) * 1000000.0;
return cycle;
}
static int lpc3180_init(struct nand_device_s *device)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
int bus_width = (device->bus_width) ? (device->bus_width) : 8;
int address_cycles = (device->address_cycles) ? (device->address_cycles) : 3;
int page_size = (device->page_size) ? (device->page_size) : 512;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
/* sanitize arguments */
if ((bus_width != 8) && (bus_width != 16))
{
LOG_ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width);
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
/* The LPC3180 only brings out 8 bit NAND data bus, but the controller
* would support 16 bit, too, so we just warn about this for now
*/
if (bus_width == 16)
{
LOG_WARNING("LPC3180 only supports 8 bit bus width");
}
/* inform calling code about selected bus width */
device->bus_width = bus_width;
if ((address_cycles != 3) && (address_cycles != 4))
{
LOG_ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles);
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
if ((page_size != 512) && (page_size != 2048))
{
LOG_ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size);
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
/* select MLC controller if none is currently selected */
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'");
lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
}
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
uint32_t mlc_icr_value = 0x0;
float cycle;
int twp, twh, trp, treh, trhz, trbwb, tcea;
/* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */
target_write_u32(target, 0x400040c8, 0x22);
/* MLC_CEH = 0x0 (Force nCE assert) */
target_write_u32(target, 0x200b804c, 0x0);
/* MLC_LOCK = 0xa25e (unlock protected registers) */
target_write_u32(target, 0x200b8044, 0xa25e);
/* MLC_ICR = configuration */
if (lpc3180_info->sw_write_protection)
mlc_icr_value |= 0x8;
if (page_size == 2048)
mlc_icr_value |= 0x4;
if (address_cycles == 4)
mlc_icr_value |= 0x2;
if (bus_width == 16)
mlc_icr_value |= 0x1;
target_write_u32(target, 0x200b8030, mlc_icr_value);
/* calculate NAND controller timings */
cycle = lpc3180_cycle_time(lpc3180_info);
twp = ((40 / cycle) + 1);
twh = ((20 / cycle) + 1);
trp = ((30 / cycle) + 1);
treh = ((15 / cycle) + 1);
trhz = ((30 / cycle) + 1);
trbwb = ((100 / cycle) + 1);
tcea = ((45 / cycle) + 1);
/* MLC_LOCK = 0xa25e (unlock protected registers) */
target_write_u32(target, 0x200b8044, 0xa25e);
/* MLC_TIME_REG */
target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) |
((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) |
((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24));
lpc3180_reset(device);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
float cycle;
int r_setup, r_hold, r_width, r_rdy;
int w_setup, w_hold, w_width, w_rdy;
/* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */
target_write_u32(target, 0x400040c8, 0x05);
/* SLC_CFG = 0x (Force nCE assert, ECC enabled, WIDTH = bus_width) */
target_write_u32(target, 0x20020014, 0x28 | (bus_width == 16) ? 1 : 0);
/* calculate NAND controller timings */
cycle = lpc3180_cycle_time(lpc3180_info);
r_setup = w_setup = 0;
r_hold = w_hold = 10 / cycle;
r_width = 30 / cycle;
w_width = 40 / cycle;
r_rdy = w_rdy = 100 / cycle;
/* SLC_TAC: SLC timing arcs register */
target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) |
((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) |
((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28));
lpc3180_reset(device);
}
return ERROR_OK;
}
static int lpc3180_reset(struct nand_device_s *device)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* MLC_CMD = 0xff (reset controller and NAND device) */
target_write_u32(target, 0x200b8000, 0xff);
if (!lpc3180_controller_ready(device, 100))
{
LOG_ERROR("LPC3180 NAND controller timed out after reset");
return ERROR_NAND_OPERATION_TIMEOUT;
}
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
/* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */
target_write_u32(target, 0x20020010, 0x6);
if (!lpc3180_controller_ready(device, 100))
{
LOG_ERROR("LPC3180 NAND controller timed out after reset");
return ERROR_NAND_OPERATION_TIMEOUT;
}
}
return ERROR_OK;
}
static int lpc3180_command(struct nand_device_s *device, uint8_t command)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* MLC_CMD = command */
target_write_u32(target, 0x200b8000, command);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
/* SLC_CMD = command */
target_write_u32(target, 0x20020008, command);
}
return ERROR_OK;
}
static int lpc3180_address(struct nand_device_s *device, uint8_t address)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* MLC_ADDR = address */
target_write_u32(target, 0x200b8004, address);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
/* SLC_ADDR = address */
target_write_u32(target, 0x20020004, address);
}
return ERROR_OK;
}
static int lpc3180_write_data(struct nand_device_s *device, uint16_t data)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* MLC_DATA = data */
target_write_u32(target, 0x200b0000, data);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
/* SLC_DATA = data */
target_write_u32(target, 0x20020000, data);
}
return ERROR_OK;
}
static int lpc3180_read_data(struct nand_device_s *device, void *data)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* data = MLC_DATA, use sized access */
if (device->bus_width == 8)
{
uint8_t *data8 = data;
target_read_u8(target, 0x200b0000, data8);
}
else if (device->bus_width == 16)
{
uint16_t *data16 = data;
target_read_u16(target, 0x200b0000, data16);
}
else
{
LOG_ERROR("BUG: bus_width neither 8 nor 16 bit");
return ERROR_NAND_OPERATION_FAILED;
}
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
uint32_t data32;
/* data = SLC_DATA, must use 32-bit access */
target_read_u32(target, 0x20020000, &data32);
if (device->bus_width == 8)
{
uint8_t *data8 = data;
*data8 = data32 & 0xff;
}
else if (device->bus_width == 16)
{
uint16_t *data16 = data;
*data16 = data32 & 0xffff;
}
else
{
LOG_ERROR("BUG: bus_width neither 8 nor 16 bit");
return ERROR_NAND_OPERATION_FAILED;
}
}
return ERROR_OK;
}
static int lpc3180_write_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
int retval;
uint8_t status;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
uint8_t *page_buffer;
uint8_t *oob_buffer;
int quarter, num_quarters;
if (!data && oob)
{
LOG_ERROR("LPC3180 MLC controller can't write OOB data only");
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
if (oob && (oob_size > 6))
{
LOG_ERROR("LPC3180 MLC controller can't write more than 6 bytes of OOB data");
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
if (data_size > (uint32_t)device->page_size)
{
LOG_ERROR("data size exceeds page size");
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
/* MLC_CMD = sequential input */
target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN);
page_buffer = malloc(512);
oob_buffer = malloc(6);
if (device->page_size == 512)
{
/* MLC_ADDR = 0x0 (one column cycle) */
target_write_u32(target, 0x200b8004, 0x0);
/* MLC_ADDR = row */
target_write_u32(target, 0x200b8004, page & 0xff);
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
if (device->address_cycles == 4)
target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
}
else
{
/* MLC_ADDR = 0x0 (two column cycles) */
target_write_u32(target, 0x200b8004, 0x0);
target_write_u32(target, 0x200b8004, 0x0);
/* MLC_ADDR = row */
target_write_u32(target, 0x200b8004, page & 0xff);
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
}
/* when using the MLC controller, we have to treat a large page device
* as being made out of four quarters, each the size of a small page device
*/
num_quarters = (device->page_size == 2048) ? 4 : 1;
for (quarter = 0; quarter < num_quarters; quarter++)
{
int thisrun_data_size = (data_size > 512) ? 512 : data_size;
int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size;
memset(page_buffer, 0xff, 512);
if (data)
{
memcpy(page_buffer, data, thisrun_data_size);
data_size -= thisrun_data_size;
data += thisrun_data_size;
}
memset(oob_buffer, 0xff, (device->page_size == 512) ? 6 : 24);
if (oob)
{
memcpy(page_buffer, oob, thisrun_oob_size);
oob_size -= thisrun_oob_size;
oob += thisrun_oob_size;
}
/* write MLC_ECC_ENC_REG to start encode cycle */
target_write_u32(target, 0x200b8008, 0x0);
target_write_memory(target, 0x200a8000, 4, 128, page_buffer + (quarter * 512));
target_write_memory(target, 0x200a8000, 1, 6, oob_buffer + (quarter * 6));
/* write MLC_ECC_AUTO_ENC_REG to start auto encode */
target_write_u32(target, 0x200b8010, 0x0);
if (!lpc3180_controller_ready(device, 1000))
{
LOG_ERROR("timeout while waiting for completion of auto encode cycle");
return ERROR_NAND_OPERATION_FAILED;
}
}
/* MLC_CMD = auto program command */
target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG);
if ((retval = nand_read_status(device, &status)) != ERROR_OK)
{
LOG_ERROR("couldn't read status");
return ERROR_NAND_OPERATION_FAILED;
}
if (status & NAND_STATUS_FAIL)
{
LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status);
return ERROR_NAND_OPERATION_FAILED;
}
free(page_buffer);
free(oob_buffer);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
return nand_write_page_raw(device, page, data, data_size, oob, oob_size);
}
return ERROR_OK;
}
static int lpc3180_read_page(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER)
{
LOG_ERROR("BUG: no LPC3180 NAND flash controller selected");
return ERROR_NAND_OPERATION_FAILED;
}
else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
uint8_t *page_buffer;
uint8_t *oob_buffer;
uint32_t page_bytes_done = 0;
uint32_t oob_bytes_done = 0;
uint32_t mlc_isr;
#if 0
if (oob && (oob_size > 6))
{
LOG_ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data");
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
#endif
if (data_size > (uint32_t)device->page_size)
{
LOG_ERROR("data size exceeds page size");
return ERROR_NAND_OPERATION_NOT_SUPPORTED;
}
if (device->page_size == 2048)
{
page_buffer = malloc(2048);
oob_buffer = malloc(64);
}
else
{
page_buffer = malloc(512);
oob_buffer = malloc(16);
}
if (!data && oob)
{
/* MLC_CMD = Read OOB
* we can use the READOOB command on both small and large page devices,
* as the controller translates the 0x50 command to a 0x0 with appropriate
* positioning of the serial buffer read pointer
*/
target_write_u32(target, 0x200b8000, NAND_CMD_READOOB);
}
else
{
/* MLC_CMD = Read0 */
target_write_u32(target, 0x200b8000, NAND_CMD_READ0);
}
if (device->page_size == 512)
{
/* small page device */
/* MLC_ADDR = 0x0 (one column cycle) */
target_write_u32(target, 0x200b8004, 0x0);
/* MLC_ADDR = row */
target_write_u32(target, 0x200b8004, page & 0xff);
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
if (device->address_cycles == 4)
target_write_u32(target, 0x200b8004, (page >> 16) & 0xff);
}
else
{
/* large page device */
/* MLC_ADDR = 0x0 (two column cycles) */
target_write_u32(target, 0x200b8004, 0x0);
target_write_u32(target, 0x200b8004, 0x0);
/* MLC_ADDR = row */
target_write_u32(target, 0x200b8004, page & 0xff);
target_write_u32(target, 0x200b8004, (page >> 8) & 0xff);
/* MLC_CMD = Read Start */
target_write_u32(target, 0x200b8000, NAND_CMD_READSTART);
}
while (page_bytes_done < (uint32_t)device->page_size)
{
/* MLC_ECC_AUTO_DEC_REG = dummy */
target_write_u32(target, 0x200b8014, 0xaa55aa55);
if (!lpc3180_controller_ready(device, 1000))
{
LOG_ERROR("timeout while waiting for completion of auto decode cycle");
return ERROR_NAND_OPERATION_FAILED;
}
target_read_u32(target, 0x200b8048, &mlc_isr);
if (mlc_isr & 0x8)
{
if (mlc_isr & 0x40)
{
LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr);
return ERROR_NAND_OPERATION_FAILED;
}
LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1)));
}
if (data)
{
target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done);
}
if (oob)
{
target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done);
}
page_bytes_done += 512;
oob_bytes_done += 16;
}
if (data)
memcpy(data, page_buffer, data_size);
if (oob)
memcpy(oob, oob_buffer, oob_size);
free(page_buffer);
free(oob_buffer);
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
return nand_read_page_raw(device, page, data, data_size, oob, oob_size);
}
return ERROR_OK;
}
static int lpc3180_controller_ready(struct nand_device_s *device, int timeout)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
uint8_t status = 0x0;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
do
{
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
/* Read MLC_ISR, wait for controller to become ready */
target_read_u8(target, 0x200b8048, &status);
if (status & 2)
return 1;
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
/* we pretend that the SLC controller is always ready */
return 1;
}
alive_sleep(1);
} while (timeout-- > 0);
return 0;
}
static int lpc3180_nand_ready(struct nand_device_s *device, int timeout)
{
lpc3180_nand_controller_t *lpc3180_info = device->controller_priv;
target_t *target = lpc3180_info->target;
if (target->state != TARGET_HALTED)
{
LOG_ERROR("target must be halted to use LPC3180 NAND flash controller");
return ERROR_NAND_OPERATION_FAILED;
}
do
{
if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER)
{
uint8_t status = 0x0;
/* Read MLC_ISR, wait for NAND flash device to become ready */
target_read_u8(target, 0x200b8048, &status);
if (status & 1)
return 1;
}
else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER)
{
uint32_t status = 0x0;
/* Read SLC_STAT and check READY bit */
target_read_u32(target, 0x20020018, &status);
if (status & 1)
return 1;
}
alive_sleep(1);
} while (timeout-- > 0);
return 0;
}
static int handle_lpc3180_select_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
nand_device_t *device = NULL;
lpc3180_nand_controller_t *lpc3180_info = NULL;
char *selected[] =
{
"no", "mlc", "slc"
};
if ((argc < 1) || (argc > 2))
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
device = get_nand_device_by_num(strtoul(args[0], NULL, 0));
if (!device)
{
command_print(cmd_ctx, "nand device '#%s' is out of bounds", args[0]);
return ERROR_OK;
}
lpc3180_info = device->controller_priv;
if (argc == 2)
{
if (strcmp(args[1], "mlc") == 0)
{
lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER;
}
else if (strcmp(args[1], "slc") == 0)
{
lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER;
}
else
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
command_print(cmd_ctx, "%s controller selected", selected[lpc3180_info->selected_controller]);
return ERROR_OK;
}

View File

@@ -20,6 +20,8 @@
#ifndef LPC3180_NAND_CONTROLLER_H
#define LPC3180_NAND_CONTROLLER_H
#include "target.h"
enum lpc3180_selected_controller
{
LPC3180_NO_CONTROLLER,
@@ -27,14 +29,14 @@ enum lpc3180_selected_controller
LPC3180_SLC_CONTROLLER,
};
struct lpc3180_nand_controller
typedef struct lpc3180_nand_controller_s
{
struct target_s *target;
int osc_freq;
enum lpc3180_selected_controller selected_controller;
int is_bulk;
int sw_write_protection;
uint32_t sw_wp_lower_bound;
uint32_t sw_wp_upper_bound;
};
} lpc3180_nand_controller_t;
#endif /*LPC3180_NAND_CONTROLLER_H */

View File

@@ -22,32 +22,33 @@
#endif
#include "mflash.h"
#include <target/target.h>
#include <helper/time_support.h>
#include <helper/fileio.h>
#include <helper/log.h>
#include "time_support.h"
#include "fileio.h"
#include "log.h"
static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio);
static int s3c2440_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val);
static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio);
static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val);
static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio);
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio);
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val);
static struct mflash_bank *mflash_bank;
static command_t *mflash_cmd;
static struct mflash_gpio_drv pxa270_gpio = {
static mflash_bank_t *mflash_bank;
static mflash_gpio_drv_t pxa270_gpio = {
.name = "pxa270",
.set_gpio_to_output = pxa270_set_gpio_to_output,
.set_gpio_output_val = pxa270_set_gpio_output_val
};
static struct mflash_gpio_drv s3c2440_gpio = {
static mflash_gpio_drv_t s3c2440_gpio = {
.name = "s3c2440",
.set_gpio_to_output = s3c2440_set_gpio_to_output,
.set_gpio_output_val = s3c2440_set_gpio_output_val
};
static struct mflash_gpio_drv *mflash_gpio[] =
static mflash_gpio_drv_t *mflash_gpio[] =
{
&pxa270_gpio,
&s3c2440_gpio,
@@ -63,10 +64,10 @@ static struct mflash_gpio_drv *mflash_gpio[] =
#define PXA270_GPSR0 0x40E00018
#define PXA270_GPCR0 0x40E00024
static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio)
static int pxa270_set_gpio_to_output (mflash_gpio_num_t gpio)
{
uint32_t addr, value, mask;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
int ret;
/* remove alternate function. */
@@ -100,10 +101,10 @@ static int pxa270_set_gpio_to_output (struct mflash_gpio_num gpio)
return ret;
}
static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
static int pxa270_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
{
uint32_t addr, value, mask;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
int ret;
mask = 0x1u << (gpio.num & 0x1F);
@@ -129,10 +130,10 @@ static int pxa270_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
#define S3C2440_GPJCON 0x560000d0
#define S3C2440_GPJDAT 0x560000d4
static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio)
static int s3c2440_set_gpio_to_output (mflash_gpio_num_t gpio)
{
uint32_t data, mask, gpio_con;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
int ret;
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
@@ -161,10 +162,10 @@ static int s3c2440_set_gpio_to_output (struct mflash_gpio_num gpio)
return ret;
}
static int s3c2440_set_gpio_output_val (struct mflash_gpio_num gpio, uint8_t val)
static int s3c2440_set_gpio_output_val (mflash_gpio_num_t gpio, uint8_t val)
{
uint32_t data, mask, gpio_dat;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
int ret;
if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') {
@@ -198,7 +199,7 @@ static int mg_hdrst(uint8_t level)
static int mg_init_gpio (void)
{
int ret;
struct mflash_gpio_drv *gpio_drv = mflash_bank->gpio_drv;
mflash_gpio_drv_t *gpio_drv = mflash_bank->gpio_drv;
ret = gpio_drv->set_gpio_to_output(mflash_bank->rst_pin);
if (ret != ERROR_OK)
@@ -209,18 +210,18 @@ static int mg_init_gpio (void)
return ret;
}
static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
static int mg_dsk_wait(mg_io_type_wait wait, uint32_t time)
{
uint8_t status, error;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
duration_t duration;
int ret;
long long t = 0;
struct duration bench;
duration_start(&bench);
duration_start_measure(&duration);
while (time_var) {
while (time) {
ret = target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status);
if (ret != ERROR_OK)
@@ -228,10 +229,10 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
if (status & mg_io_rbit_status_busy)
{
if (wait_local == mg_io_wait_bsy)
if (wait == mg_io_wait_bsy)
return ERROR_OK;
} else {
switch (wait_local)
switch (wait)
{
case mg_io_wait_not_bsy:
return ERROR_OK;
@@ -259,7 +260,7 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
return ERROR_MG_IO;
}
switch (wait_local)
switch (wait)
{
case mg_io_wait_rdy:
if (status & mg_io_rbit_status_ready)
@@ -274,13 +275,12 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
}
}
ret = duration_measure(&bench);
if (ERROR_OK == ret)
t = duration_elapsed(&bench) * 1000.0;
else
LOG_ERROR("mflash: duration measurement failed: %d", ret);
duration_stop_measure(&duration, NULL);
if (t > time_var)
t = duration.duration.tv_usec/1000;
t += duration.duration.tv_sec*1000;
if (t > time)
break;
}
@@ -290,7 +290,7 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var)
static int mg_dsk_srst(uint8_t on)
{
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
uint8_t value;
int ret;
@@ -310,7 +310,7 @@ static int mg_dsk_srst(uint8_t on)
static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd)
{
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
uint8_t value;
int ret;
@@ -335,24 +335,22 @@ static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd)
static int mg_dsk_drv_info(void)
{
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET;
int ret;
if ((ret = mg_dsk_io_cmd(0, 1, mg_io_cmd_identify)) != ERROR_OK)
return ret;
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
if (ret != ERROR_OK)
if ((ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL)) != ERROR_OK)
return ret;
LOG_INFO("mflash: read drive info");
if (! mflash_bank->drv_info)
mflash_bank->drv_info = malloc(sizeof(struct mg_drv_info));
mflash_bank->drv_info = malloc(sizeof(mg_drv_info_t));
ret = target_read_memory(target, mg_buff, 2,
sizeof(mg_io_type_drv_info) >> 1,
target_read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1,
(uint8_t *)&mflash_bank->drv_info->drv_id);
if (ret != ERROR_OK)
return ret;
@@ -409,14 +407,14 @@ static int mg_mflash_probe(void)
return mg_dsk_drv_info();
}
COMMAND_HANDLER(mg_probe_cmd)
static int mg_probe_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
int ret;
ret = mg_mflash_probe();
if (ret == ERROR_OK) {
command_print(CMD_CTX, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
command_print(cmd_ctx, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "",
mflash_bank->drv_info->tot_sects, mflash_bank->base);
}
@@ -427,16 +425,16 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
{
uint32_t i, address;
int ret;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint8_t *buff_ptr = buff;
duration_t duration;
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read)) != ERROR_OK)
return ret;
address = mflash_bank->base + MG_BUFFER_OFFSET;
struct duration bench;
duration_start(&bench);
duration_start_measure(&duration);
for (i = 0; i < sect_cnt; i++) {
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
@@ -455,10 +453,11 @@ static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
ret = duration_measure(&bench);
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
duration_stop_measure(&duration, NULL);
if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
LOG_INFO("mflash: read %" PRIu32 "'th sectors", sect_num + i);
duration_start(&bench);
duration_start_measure(&duration);
}
}
@@ -499,16 +498,16 @@ static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect
{
uint32_t i, address;
int ret;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint8_t *buff_ptr = buff;
duration_t duration;
if ((ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd)) != ERROR_OK)
return ret;
address = mflash_bank->base + MG_BUFFER_OFFSET;
struct duration bench;
duration_start(&bench);
duration_start_measure(&duration);
for (i = 0; i < sect_cnt; i++) {
ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL);
@@ -527,10 +526,11 @@ static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect
LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE);
ret = duration_measure(&bench);
if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) {
duration_stop_measure(&duration, NULL);
if ((duration.duration.tv_sec * 1000 + duration.duration.tv_usec / 1000) > 3000) {
LOG_INFO("mflash: wrote %" PRIu32 "'th sectors", sect_num + i);
duration_start(&bench);
duration_start_measure(&duration);
}
}
@@ -703,42 +703,36 @@ static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len)
return ret;
}
COMMAND_HANDLER(mg_write_cmd)
static int mg_write_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
uint32_t address, cnt, res, i;
uint32_t address, buf_cnt, cnt, res, i;
uint8_t *buffer;
struct fileio fileio;
fileio_t fileio;
duration_t duration;
char *duration_text;
int ret;
if (CMD_ARGC != 3) {
if (argc != 3) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
address = strtoul(args[2], NULL, 0);
ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY);
ret = fileio_open(&fileio, args[1], FILEIO_READ, FILEIO_BINARY);
if (ret != ERROR_OK)
return ret;
int filesize;
buffer = malloc(MG_FILEIO_CHUNK);
if (!buffer) {
fileio_close(&fileio);
return ERROR_FAIL;
}
int retval = fileio_size(&fileio, &filesize);
if (retval != ERROR_OK) {
fileio_close(&fileio);
return retval;
}
cnt = filesize / MG_FILEIO_CHUNK;
res = filesize % MG_FILEIO_CHUNK;
cnt = fileio.size / MG_FILEIO_CHUNK;
res = fileio.size % MG_FILEIO_CHUNK;
struct duration bench;
duration_start(&bench);
duration_start_measure(&duration);
size_t buf_cnt;
for (i = 0; i < cnt; i++) {
if ((ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt)) !=
ERROR_OK)
@@ -755,40 +749,44 @@ COMMAND_HANDLER(mg_write_cmd)
goto mg_write_cmd_err;
}
if (duration_measure(&bench) == ERROR_OK)
{
command_print(CMD_CTX, "wrote %ld bytes from file %s "
"in %fs (%0.3f kB/s)", (long)filesize, CMD_ARGV[1],
duration_elapsed(&bench), duration_kbps(&bench, filesize));
}
duration_stop_measure(&duration, &duration_text);
command_print(cmd_ctx, "wrote %lli byte from file %s in %s (%f kB/s)",
fileio.size, args[1], duration_text,
(float)fileio.size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
free(duration_text);
free(buffer);
fileio_close(&fileio);
return ERROR_OK;
mg_write_cmd_err:
free(buffer);
duration_stop_measure(&duration, &duration_text);
free(duration_text);
free(buffer);
fileio_close(&fileio);
return ret;
}
COMMAND_HANDLER(mg_dump_cmd)
static int mg_dump_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
uint32_t address, size, cnt, res, i;
uint32_t address, size_written, size, cnt, res, i;
uint8_t *buffer;
struct fileio fileio;
fileio_t fileio;
duration_t duration;
char *duration_text;
int ret;
if (CMD_ARGC != 4) {
if (argc != 4) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], size);
address = strtoul(args[2], NULL, 0);
size = strtoul(args[3], NULL, 0);
ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY);
ret = fileio_open(&fileio, args[1], FILEIO_WRITE, FILEIO_BINARY);
if (ret != ERROR_OK)
return ret;
@@ -801,10 +799,8 @@ COMMAND_HANDLER(mg_dump_cmd)
cnt = size / MG_FILEIO_CHUNK;
res = size % MG_FILEIO_CHUNK;
struct duration bench;
duration_start(&bench);
duration_start_measure(&duration);
size_t size_written;
for (i = 0; i < cnt; i++) {
if ((ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK)) != ERROR_OK)
goto mg_dump_cmd_err;
@@ -821,21 +817,22 @@ COMMAND_HANDLER(mg_dump_cmd)
goto mg_dump_cmd_err;
}
if (duration_measure(&bench) == ERROR_OK)
{
command_print(CMD_CTX, "dump image (address 0x%8.8" PRIx32 " "
"size %" PRIu32 ") to file %s in %fs (%0.3f kB/s)",
address, size, CMD_ARGV[1],
duration_elapsed(&bench), duration_kbps(&bench, size));
}
duration_stop_measure(&duration, &duration_text);
command_print(cmd_ctx, "dump image (address 0x%8.8" PRIx32 " size %" PRIu32 ") to file %s in %s (%f kB/s)",
address, size, args[1], duration_text,
(float)size / 1024.0 / ((float)duration.duration.tv_sec + ((float)duration.duration.tv_usec / 1000000.0)));
free(duration_text);
free(buffer);
fileio_close(&fileio);
return ERROR_OK;
mg_dump_cmd_err:
free(buffer);
duration_stop_measure(&duration, &duration_text);
free(duration_text);
free(buffer);
fileio_close(&fileio);
return ret;
@@ -843,7 +840,7 @@ mg_dump_cmd_err:
static int mg_set_feature(mg_feature_id feature, mg_feature_val config)
{
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET;
int ret;
@@ -962,7 +959,7 @@ static int mg_verify_interface(void)
uint16_t buff[MG_MFLASH_SECTOR_SIZE >> 1];
uint16_t i, j;
uint32_t address = mflash_bank->base + MG_BUFFER_OFFSET;
struct target *target = mflash_bank->target;
target_t *target = mflash_bank->target;
int ret;
for (j = 0; j < 10; j++) {
@@ -1127,7 +1124,7 @@ static int mg_storage_config(void)
!= ERROR_OK)
return ret;
mg_gen_ataid((mg_io_type_drv_info *)(void *)buff);
mg_gen_ataid((mg_io_type_drv_info *)buff);
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo))
!= ERROR_OK)
@@ -1155,7 +1152,7 @@ static int mg_boot_config(void)
buff[0] = mg_op_mode_snd; /* operation mode */
buff[1] = MG_UNLOCK_OTP_AREA;
buff[2] = 4; /* boot size */
*((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */
*((uint32_t *)(buff + 4)) = 0; /* XIP size */
if ((ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo))
!= ERROR_OK)
@@ -1217,7 +1214,8 @@ static int mg_erase_nand(void)
return ret;
}
COMMAND_HANDLER(mg_config_cmd)
int mg_config_cmd(struct command_context_s *cmd_ctx, char *cmd,
char **args, int argc)
{
double fin, fout;
mg_pll_t pll;
@@ -1229,20 +1227,18 @@ COMMAND_HANDLER(mg_config_cmd)
if ((ret = mg_mflash_rst()) != ERROR_OK)
return ret;
switch (CMD_ARGC) {
switch (argc) {
case 2:
if (!strcmp(CMD_ARGV[1], "boot"))
if (!strcmp(args[1], "boot"))
return mg_boot_config();
else if (!strcmp(CMD_ARGV[1], "storage"))
else if (!strcmp(args[1], "storage"))
return mg_storage_config();
else
return ERROR_COMMAND_NOTFOUND;
break;
case 3:
if (!strcmp(CMD_ARGV[1], "pll")) {
unsigned long freq;
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], freq);
fin = freq;
if (!strcmp(args[1], "pll")) {
fin = strtoul(args[2], NULL, 0);
if (fin > MG_PLL_CLK_OUT) {
LOG_ERROR("mflash: input freq. is too large");
@@ -1274,131 +1270,64 @@ COMMAND_HANDLER(mg_config_cmd)
}
}
static const struct command_registration mflash_exec_command_handlers[] = {
{
.name = "probe",
.handler = mg_probe_cmd,
.mode = COMMAND_EXEC,
.help = "Detect bank configuration information",
},
{
.name = "write",
.handler = mg_write_cmd,
.mode = COMMAND_EXEC,
/* FIXME bank_num is unused */
.usage = "bank_num filename address",
.help = "Write binary file at the specified address.",
},
{
.name = "dump",
.handler = mg_dump_cmd,
.mode = COMMAND_EXEC,
/* FIXME bank_num is unused */
.usage = "bank_num filename address size",
.help = "Write specified number of bytes from a binary file "
"to the specified, address.",
},
{
.name = "config",
.handler = mg_config_cmd,
.mode = COMMAND_EXEC,
.help = "Configure MFLASH options.",
.usage = "('boot'|'storage'|'pll' frequency)",
},
COMMAND_REGISTRATION_DONE
};
static int mflash_init_drivers(struct command_context *cmd_ctx)
int mflash_init_drivers(struct command_context_s *cmd_ctx)
{
if (!mflash_bank)
return ERROR_OK;
return register_commands(cmd_ctx, NULL, mflash_exec_command_handlers);
}
COMMAND_HANDLER(handle_mflash_init_command)
{
if (CMD_ARGC != 0)
return ERROR_COMMAND_SYNTAX_ERROR;
static bool mflash_initialized = false;
if (mflash_initialized)
{
LOG_INFO("'mflash init' has already been called");
return ERROR_OK;
if (mflash_bank) {
register_command(cmd_ctx, mflash_cmd, "probe", mg_probe_cmd, COMMAND_EXEC, NULL);
register_command(cmd_ctx, mflash_cmd, "write", mg_write_cmd, COMMAND_EXEC,
"mflash write <num> <file> <address>");
register_command(cmd_ctx, mflash_cmd, "dump", mg_dump_cmd, COMMAND_EXEC,
"mflash dump <num> <file> <address> <size>");
register_command(cmd_ctx, mflash_cmd, "config", mg_config_cmd,
COMMAND_EXEC, "mflash config <num> <stage>");
}
mflash_initialized = true;
LOG_DEBUG("Initializing mflash devices...");
return mflash_init_drivers(CMD_CTX);
return ERROR_OK;
}
COMMAND_HANDLER(mg_bank_cmd)
static int mg_bank_cmd(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
struct target *target;
target_t *target;
char *str;
int i;
if (CMD_ARGC < 4)
if (argc < 4)
{
return ERROR_COMMAND_SYNTAX_ERROR;
}
if ((target = get_target(CMD_ARGV[3])) == NULL)
if ((target = get_target(args[3])) == NULL)
{
LOG_ERROR("target '%s' not defined", CMD_ARGV[3]);
LOG_ERROR("target '%s' not defined", args[3]);
return ERROR_FAIL;
}
mflash_bank = calloc(sizeof(struct mflash_bank), 1);
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mflash_bank->base);
/// @todo Verify how this parsing should work, then document it.
char *str;
mflash_bank->rst_pin.num = strtoul(CMD_ARGV[2], &str, 0);
mflash_bank = calloc(sizeof(mflash_bank_t), 1);
mflash_bank->base = strtoul(args[1], NULL, 0);
mflash_bank->rst_pin.num = strtoul(args[2], &str, 0);
if (*str)
mflash_bank->rst_pin.port[0] = (uint16_t)
tolower((unsigned)str[0]);
mflash_bank->rst_pin.port[0] = (uint16_t)tolower(str[0]);
mflash_bank->target = target;
for (i = 0; mflash_gpio[i] ; i++) {
if (! strcmp(mflash_gpio[i]->name, CMD_ARGV[0])) {
if (! strcmp(mflash_gpio[i]->name, args[0])) {
mflash_bank->gpio_drv = mflash_gpio[i];
}
}
if (! mflash_bank->gpio_drv) {
LOG_ERROR("%s is unsupported soc", CMD_ARGV[0]);
LOG_ERROR("%s is unsupported soc", args[0]);
return ERROR_MG_UNSUPPORTED_SOC;
}
return ERROR_OK;
}
static const struct command_registration mflash_config_command_handlers[] = {
{
.name = "bank",
.handler = mg_bank_cmd,
.mode = COMMAND_CONFIG,
.help = "configure a mflash device bank",
.usage = "soc_type base_addr pin_id target",
},
{
.name = "init",
.mode = COMMAND_CONFIG,
.handler = handle_mflash_init_command,
.help = "initialize mflash devices",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration mflash_command_handler[] = {
{
.name = "mflash",
.mode = COMMAND_ANY,
.help = "mflash command group",
.chain = mflash_config_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
int mflash_register_commands(struct command_context *cmd_ctx)
int mflash_register_commands(struct command_context_s *cmd_ctx)
{
return register_commands(cmd_ctx, NULL, mflash_command_handler);
mflash_cmd = register_command(cmd_ctx, NULL, "mflash", NULL, COMMAND_ANY, NULL);
register_command(cmd_ctx, mflash_cmd, "bank", mg_bank_cmd, COMMAND_CONFIG,
"mflash bank <soc> <base> <RST pin> <target #>");
return ERROR_OK;
}

View File

@@ -20,24 +20,24 @@
#ifndef _MFLASH_H
#define _MFLASH_H
struct command_context;
#include "target.h"
typedef unsigned long mg_io_uint32;
typedef unsigned short mg_io_uint16;
typedef unsigned char mg_io_uint8;
struct mflash_gpio_num
typedef struct mflash_gpio_num_s
{
char port[2];
signed short num;
};
} mflash_gpio_num_t;
struct mflash_gpio_drv
typedef struct mflash_gpio_drv_s
{
const char *name;
int (*set_gpio_to_output) (struct mflash_gpio_num gpio);
int (*set_gpio_output_val) (struct mflash_gpio_num gpio, uint8_t val);
};
char *name;
int (*set_gpio_to_output) (mflash_gpio_num_t gpio);
int (*set_gpio_output_val) (mflash_gpio_num_t gpio, uint8_t val);
} mflash_gpio_drv_t;
typedef struct _mg_io_type_drv_info {
@@ -125,23 +125,24 @@ typedef struct _mg_pll_t
unsigned char output_div; /* 2bit divider */
} mg_pll_t;
struct mg_drv_info {
typedef struct mg_drv_info_s {
mg_io_type_drv_info drv_id;
uint32_t tot_sects;
};
} mg_drv_info_t;
struct mflash_bank
typedef struct mflash_bank_s
{
uint32_t base;
struct mflash_gpio_num rst_pin;
mflash_gpio_num_t rst_pin;
struct mflash_gpio_drv *gpio_drv;
struct target *target;
struct mg_drv_info *drv_info;
};
mflash_gpio_drv_t *gpio_drv;
target_t *target;
mg_drv_info_t *drv_info;
} mflash_bank_t;
int mflash_register_commands(struct command_context *cmd_ctx);
extern int mflash_register_commands(struct command_context_s *cmd_ctx);
extern int mflash_init_drivers(struct command_context_s *cmd_ctx);
#define MG_MFLASH_SECTOR_SIZE (0x200) /* 512Bytes = 2^9 */
#define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1)

View File

@@ -35,9 +35,7 @@ get_next_halfword_from_sram_buffer() not tested
#include "config.h"
#endif
#include "imp.h"
#include "mx3.h"
#include <target/target.h>
#include "mx3_nand.h"
static const char target_not_halted_err_msg[] =
"target must be halted to use mx3 NAND flash controller";
@@ -47,34 +45,74 @@ static const char sram_buffer_bounds_err_msg[] =
"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
static const char get_status_register_err_msg[] = "can't get NAND status";
static uint32_t in_sram_address;
static unsigned char sign_of_sequental_byte_read;
unsigned char sign_of_sequental_byte_read;
static int test_iomux_settings (struct target * target, uint32_t value,
static int test_iomux_settings (target_t * target, uint32_t value,
uint32_t mask, const char *text);
static int initialize_nf_controller (struct nand_device *nand);
static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value);
static int get_next_halfword_from_sram_buffer (struct target * target,
static int initialize_nf_controller (struct nand_device_s *device);
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value);
static int get_next_halfword_from_sram_buffer (target_t * target,
uint16_t * value);
static int poll_for_complete_op (struct target * target, const char *text);
static int validate_target_state (struct nand_device *nand);
static int do_data_output (struct nand_device *nand);
static int poll_for_complete_op (target_t * target, const char *text);
static int validate_target_state (struct nand_device_s *device);
static int do_data_output (struct nand_device_s *device);
static int imx31_command (struct nand_device *nand, uint8_t command);
static int imx31_address (struct nand_device *nand, uint8_t address);
static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc,
struct nand_device_s *device);
static int imx31_init (struct nand_device_s *device);
static int imx31_read_data (struct nand_device_s *device, void *data);
static int imx31_write_data (struct nand_device_s *device, uint16_t data);
static int imx31_nand_ready (struct nand_device_s *device, int timeout);
static int imx31_register_commands (struct command_context_s *cmd_ctx);
static int imx31_reset (struct nand_device_s *device);
static int imx31_command (struct nand_device_s *device, uint8_t command);
static int imx31_address (struct nand_device_s *device, uint8_t address);
static int imx31_controller_ready (struct nand_device_s *device, int tout);
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
uint8_t * data, uint32_t data_size, uint8_t * oob,
uint32_t oob_size);
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
uint8_t * data, uint32_t data_size, uint8_t * oob,
uint32_t oob_size);
NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
nand_flash_controller_t imx31_nand_flash_controller = {
.name = "imx31",
.nand_device_command = imx31_nand_device_command,
.register_commands = imx31_register_commands,
.init = imx31_init,
.reset = imx31_reset,
.command = imx31_command,
.address = imx31_address,
.write_data = imx31_write_data,
.read_data = imx31_read_data,
.write_page = imx31_write_page,
.read_page = imx31_read_page,
.controller_ready = imx31_controller_ready,
.nand_ready = imx31_nand_ready,
};
static int imx31_nand_device_command (struct command_context_s *cmd_ctx,
char *cmd, char **args, int argc,
struct nand_device_s *device)
{
struct mx3_nf_controller *mx3_nf_info;
mx3_nf_info = malloc (sizeof (struct mx3_nf_controller));
mx3_nf_controller_t *mx3_nf_info;
mx3_nf_info = malloc (sizeof (mx3_nf_controller_t));
if (mx3_nf_info == NULL)
{
LOG_ERROR ("no memory for nand controller");
return ERROR_FAIL;
}
nand->controller_priv = mx3_nf_info;
device->controller_priv = mx3_nf_info;
if (CMD_ARGC < 3)
mx3_nf_info->target = get_target (args[1]);
if (mx3_nf_info->target == NULL)
{
LOG_ERROR ("target '%s' not defined", args[1]);
return ERROR_FAIL;
}
if (argc < 3)
{
LOG_ERROR ("use \"nand device imx31 target noecc|hwecc\"");
return ERROR_FAIL;
@@ -84,7 +122,7 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
*/
{
int hwecc_needed;
hwecc_needed = strcmp (CMD_ARGV[2], "hwecc");
hwecc_needed = strcmp (args[2], "hwecc");
if (hwecc_needed == 0)
{
mx3_nf_info->flags.hw_ecc_enabled = 1;
@@ -98,9 +136,9 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE;
mx3_nf_info->fin = MX3_NF_FIN_NONE;
mx3_nf_info->flags.target_little_endian =
(nand->target->endianness == TARGET_LITTLE_ENDIAN);
(mx3_nf_info->target->endianness == TARGET_LITTLE_ENDIAN);
/*
* testing host endianness
* testing host endianess
*/
{
int x = 1;
@@ -116,17 +154,17 @@ NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command)
return ERROR_OK;
}
static int imx31_init (struct nand_device *nand)
static int imx31_init (struct nand_device_s *device)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state(nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
@@ -142,30 +180,30 @@ static int imx31_init (struct nand_device *nand)
{
uint32_t pcsr_register_content;
target_read_u32 (target, MX3_PCSR, &pcsr_register_content);
if (!nand->bus_width)
if (!device->bus_width)
{
nand->bus_width =
device->bus_width =
(pcsr_register_content & 0x80000000) ? 16 : 8;
}
else
{
pcsr_register_content |=
((nand->bus_width == 16) ? 0x80000000 : 0x00000000);
((device->bus_width == 16) ? 0x80000000 : 0x00000000);
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
}
if (!nand->page_size)
if (!device->page_size)
{
nand->page_size =
device->page_size =
(pcsr_register_content & 0x40000000) ? 2048 : 512;
}
else
{
pcsr_register_content |=
((nand->page_size == 2048) ? 0x40000000 : 0x00000000);
((device->page_size == 2048) ? 0x40000000 : 0x00000000);
target_write_u32 (target, MX3_PCSR, pcsr_register_content);
}
if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048))
if (mx3_nf_info->flags.one_kb_sram && (device->page_size == 2048))
{
LOG_ERROR
("NAND controller have only 1 kb SRAM, so pagesize 2048 is incompatible with it");
@@ -205,7 +243,7 @@ static int imx31_init (struct nand_device *nand)
test_iomux_settings (target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6");
test_iomux |=
test_iomux_settings (target, 0x43fac0c8, 0x0000007f, "d7");
if (nand->bus_width == 16)
if (device->bus_width == 16)
{
test_iomux |=
test_iomux_settings (target, 0x43fac0c8, 0x7f7f7f00,
@@ -228,15 +266,15 @@ static int imx31_init (struct nand_device *nand)
}
}
initialize_nf_controller (nand);
initialize_nf_controller (device);
{
int retval;
uint16_t nand_status_content;
retval = ERROR_OK;
retval |= imx31_command (nand, NAND_CMD_STATUS);
retval |= imx31_address (nand, 0x00);
retval |= do_data_output (nand);
retval |= imx31_command (device, NAND_CMD_STATUS);
retval |= imx31_address (device, 0x00);
retval |= do_data_output (device);
if (retval != ERROR_OK)
{
LOG_ERROR (get_status_register_err_msg);
@@ -259,15 +297,16 @@ static int imx31_init (struct nand_device *nand)
return ERROR_OK;
}
static int imx31_read_data (struct nand_device *nand, void *data)
static int imx31_read_data (struct nand_device_s *device, void *data)
{
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state (nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
@@ -279,14 +318,14 @@ static int imx31_read_data (struct nand_device *nand, void *data)
* get data from nand chip
*/
int try_data_output_from_nand_chip;
try_data_output_from_nand_chip = do_data_output (nand);
try_data_output_from_nand_chip = do_data_output (device);
if (try_data_output_from_nand_chip != ERROR_OK)
{
return try_data_output_from_nand_chip;
}
}
if (nand->bus_width == 16)
if (device->bus_width == 16)
{
get_next_halfword_from_sram_buffer (target, data);
}
@@ -298,37 +337,47 @@ static int imx31_read_data (struct nand_device *nand, void *data)
return ERROR_OK;
}
static int imx31_write_data (struct nand_device *nand, uint16_t data)
static int imx31_write_data (struct nand_device_s *device, uint16_t data)
{
LOG_ERROR ("write_data() not implemented");
return ERROR_NAND_OPERATION_FAILED;
}
static int imx31_reset (struct nand_device *nand)
static int imx31_nand_ready (struct nand_device_s *device, int timeout)
{
return imx31_controller_ready (device, timeout);
}
static int imx31_register_commands (struct command_context_s *cmd_ctx)
{
return ERROR_OK;
}
static int imx31_reset (struct nand_device_s *device)
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state (nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
}
initialize_nf_controller (nand);
initialize_nf_controller (device);
return ERROR_OK;
}
static int imx31_command (struct nand_device *nand, uint8_t command)
static int imx31_command (struct nand_device_s *device, uint8_t command)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state (nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
@@ -351,7 +400,7 @@ static int imx31_command (struct nand_device *nand, uint8_t command)
* offset == one half of page size
*/
in_sram_address =
MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
MX3_NF_MAIN_BUFFER0 + (device->page_size >> 1);
default:
in_sram_address = MX3_NF_MAIN_BUFFER0;
}
@@ -393,15 +442,16 @@ static int imx31_command (struct nand_device *nand, uint8_t command)
return ERROR_OK;
}
static int imx31_address (struct nand_device *nand, uint8_t address)
static int imx31_address (struct nand_device_s *device, uint8_t address)
{
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state (nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
@@ -424,17 +474,18 @@ static int imx31_address (struct nand_device *nand, uint8_t address)
return ERROR_OK;
}
static int imx31_nand_ready (struct nand_device *nand, int tout)
static int imx31_controller_ready (struct nand_device_s *device, int tout)
{
uint16_t poll_complete_status;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
{
/*
* validate target state
*/
int validate_target_result;
validate_target_result = validate_target_state (nand);
validate_target_result = validate_target_state (device);
if (validate_target_result != ERROR_OK)
{
return validate_target_result;
@@ -454,12 +505,12 @@ static int imx31_nand_ready (struct nand_device *nand, int tout)
return tout;
}
static int imx31_write_page (struct nand_device *nand, uint32_t page,
static int imx31_write_page (struct nand_device_s *device, uint32_t page,
uint8_t * data, uint32_t data_size, uint8_t * oob,
uint32_t oob_size)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
if (data_size % 2)
{
@@ -481,7 +532,7 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
* validate target state
*/
int retval;
retval = validate_target_state (nand);
retval = validate_target_state (device);
if (retval != ERROR_OK)
{
return retval;
@@ -489,16 +540,16 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
}
{
int retval = ERROR_OK;
retval |= imx31_command(nand, NAND_CMD_SEQIN);
retval |= imx31_address(nand, 0x00);
retval |= imx31_address(nand, page & 0xff);
retval |= imx31_address(nand, (page >> 8) & 0xff);
if (nand->address_cycles >= 4)
retval |= imx31_command (device, NAND_CMD_SEQIN);
retval |= imx31_address (device, 0x00);
retval |= imx31_address (device, page & 0xff);
retval |= imx31_address (device, (page >> 8) & 0xff);
if (device->address_cycles >= 4)
{
retval |= imx31_address (nand, (page >> 16) & 0xff);
if (nand->address_cycles >= 5)
retval |= imx31_address (device, (page >> 16) & 0xff);
if (device->address_cycles >= 5)
{
retval |= imx31_address (nand, (page >> 24) & 0xff);
retval |= imx31_address (device, (page >> 24) & 0xff);
}
}
target_write_buffer (target, MX3_NF_MAIN_BUFFER0, data_size, data);
@@ -528,7 +579,7 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
return poll_result;
}
}
retval |= imx31_command (nand, NAND_CMD_PAGEPROG);
retval |= imx31_command (device, NAND_CMD_PAGEPROG);
if (retval != ERROR_OK)
{
return retval;
@@ -540,9 +591,9 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
{
uint16_t nand_status_content;
retval = ERROR_OK;
retval |= imx31_command(nand, NAND_CMD_STATUS);
retval |= imx31_address(nand, 0x00);
retval |= do_data_output(nand);
retval |= imx31_command (device, NAND_CMD_STATUS);
retval |= imx31_address (device, 0x00);
retval |= do_data_output (device);
if (retval != ERROR_OK)
{
LOG_ERROR (get_status_register_err_msg);
@@ -561,11 +612,12 @@ static int imx31_write_page (struct nand_device *nand, uint32_t page,
return ERROR_OK;
}
static int imx31_read_page (struct nand_device *nand, uint32_t page,
static int imx31_read_page (struct nand_device_s *device, uint32_t page,
uint8_t * data, uint32_t data_size, uint8_t * oob,
uint32_t oob_size)
{
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
if (data_size % 2)
{
@@ -583,7 +635,7 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
* validate target state
*/
int retval;
retval = validate_target_state(nand);
retval = validate_target_state (device);
if (retval != ERROR_OK)
{
return retval;
@@ -591,20 +643,20 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
}
{
int retval = ERROR_OK;
retval |= imx31_command(nand, NAND_CMD_READ0);
retval |= imx31_address(nand, 0x00);
retval |= imx31_address(nand, page & 0xff);
retval |= imx31_address(nand, (page >> 8) & 0xff);
if (nand->address_cycles >= 4)
retval |= imx31_command (device, NAND_CMD_READ0);
retval |= imx31_address (device, 0x00);
retval |= imx31_address (device, page & 0xff);
retval |= imx31_address (device, (page >> 8) & 0xff);
if (device->address_cycles >= 4)
{
retval |= imx31_address(nand, (page >> 16) & 0xff);
if (nand->address_cycles >= 5)
retval |= imx31_address (device, (page >> 16) & 0xff);
if (device->address_cycles >= 5)
{
retval |= imx31_address(nand, (page >> 24) & 0xff);
retval |= imx31_command(nand, NAND_CMD_READSTART);
retval |= imx31_address (device, (page >> 24) & 0xff);
retval |= imx31_command (device, NAND_CMD_READSTART);
}
}
retval |= do_data_output (nand);
retval |= do_data_output (device);
if (retval != ERROR_OK)
{
return retval;
@@ -624,7 +676,7 @@ static int imx31_read_page (struct nand_device *nand, uint32_t page,
return ERROR_OK;
}
static int test_iomux_settings (struct target * target, uint32_t address,
static int test_iomux_settings (target_t * target, uint32_t address,
uint32_t mask, const char *text)
{
uint32_t register_content;
@@ -637,10 +689,10 @@ static int test_iomux_settings (struct target * target, uint32_t address,
return ERROR_OK;
}
static int initialize_nf_controller (struct nand_device *nand)
static int initialize_nf_controller (struct nand_device_s *device)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
/*
* resets NAND flash controller in zero time ? I dont know.
*/
@@ -690,7 +742,7 @@ static int initialize_nf_controller (struct nand_device *nand)
return ERROR_OK;
}
static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * value)
static int get_next_byte_from_sram_buffer (target_t * target, uint8_t * value)
{
static uint8_t even_byte = 0;
/*
@@ -728,7 +780,7 @@ static int get_next_byte_from_sram_buffer (struct target * target, uint8_t * val
return ERROR_OK;
}
static int get_next_halfword_from_sram_buffer (struct target * target,
static int get_next_halfword_from_sram_buffer (target_t * target,
uint16_t * value)
{
if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR)
@@ -745,7 +797,7 @@ static int get_next_halfword_from_sram_buffer (struct target * target,
return ERROR_OK;
}
static int poll_for_complete_op (struct target * target, const char *text)
static int poll_for_complete_op (target_t * target, const char *text)
{
uint16_t poll_complete_status;
for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++)
@@ -765,10 +817,10 @@ static int poll_for_complete_op (struct target * target, const char *text)
return ERROR_OK;
}
static int validate_target_state (struct nand_device *nand)
static int validate_target_state (struct nand_device_s *device)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
if (target->state != TARGET_HALTED)
{
@@ -787,10 +839,10 @@ static int validate_target_state (struct nand_device *nand)
return ERROR_OK;
}
static int do_data_output (struct nand_device *nand)
static int do_data_output (struct nand_device_s *device)
{
struct mx3_nf_controller *mx3_nf_info = nand->controller_priv;
struct target *target = nand->target;
mx3_nf_controller_t *mx3_nf_info = device->controller_priv;
target_t *target = mx3_nf_info->target;
switch (mx3_nf_info->fin)
{
case MX3_NF_FIN_DATAOUT:
@@ -848,17 +900,3 @@ static int do_data_output (struct nand_device *nand)
}
return ERROR_OK;
}
struct nand_flash_controller imx31_nand_flash_controller = {
.name = "imx31",
.nand_device_command = &imx31_nand_device_command,
.init = &imx31_init,
.reset = &imx31_reset,
.command = &imx31_command,
.address = &imx31_address,
.write_data = &imx31_write_data,
.read_data = &imx31_read_data,
.write_page = &imx31_write_page,
.read_page = &imx31_read_page,
.nand_ready = &imx31_nand_ready,
};

View File

@@ -25,6 +25,7 @@
*
* Many thanks to Ben Dooks for writing s3c24xx driver.
*/
#include <nand.h>
#define MX3_NF_BASE_ADDR 0xb8000000
#define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00)
@@ -107,9 +108,10 @@ struct mx3_nf_flags
unsigned hw_ecc_enabled:1;
};
struct mx3_nf_controller
typedef struct mx3_nf_controller_s
{
struct target_s *target;
enum mx_dataout_type optype;
enum mx_nf_finalize_action fin;
struct mx3_nf_flags flags;
};
} mx3_nf_controller_t;

1672
src/flash/nand.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* Copyright (C) 2007 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
* Partially based on linux/include/linux/mtd/nand.h *
* Copyright (C) 2000 David Woodhouse <dwmw2@mvhi.com> *
@@ -22,58 +22,67 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef FLASH_NAND_CORE_H
#define FLASH_NAND_CORE_H
#ifndef NAND_H
#define NAND_H
#include <flash/common.h>
#include "flash.h"
/**
* Representation of a single NAND block in a NAND device.
*/
struct nand_block
struct nand_device_s;
typedef struct nand_flash_controller_s
{
char *name;
int (*nand_device_command)(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc, struct nand_device_s *device);
int (*register_commands)(struct command_context_s *cmd_ctx);
int (*init)(struct nand_device_s *device);
int (*reset)(struct nand_device_s *device);
int (*command)(struct nand_device_s *device, uint8_t command);
int (*address)(struct nand_device_s *device, uint8_t address);
int (*write_data)(struct nand_device_s *device, uint16_t data);
int (*read_data)(struct nand_device_s *device, void *data);
int (*write_block_data)(struct nand_device_s *device, uint8_t *data, int size);
int (*read_block_data)(struct nand_device_s *device, uint8_t *data, int size);
int (*write_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
int (*read_page)(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
int (*controller_ready)(struct nand_device_s *device, int timeout);
int (*nand_ready)(struct nand_device_s *device, int timeout);
} nand_flash_controller_t;
typedef struct nand_block_s
{
/** Offset to the block. */
uint32_t offset;
/** Size of the block. */
uint32_t size;
/** True if the block has been erased. */
int is_erased;
/** True if the block is bad. */
int is_bad;
};
} nand_block_t;
struct nand_oobfree {
int offset;
int length;
};
struct nand_ecclayout {
typedef struct nand_ecclayout_s {
int eccbytes;
int eccpos[64];
int oobavail;
struct nand_oobfree oobfree[2];
};
} nand_ecclayout_t;
struct nand_device
typedef struct nand_device_s
{
const char *name;
struct target *target;
struct nand_flash_controller *controller;
nand_flash_controller_t *controller;
void *controller_priv;
struct nand_manufacturer *manufacturer;
struct nand_info *device;
struct nand_manufacturer_s *manufacturer;
struct nand_info_s *device;
int bus_width;
int address_cycles;
int page_size;
int erase_size;
int use_raw;
int num_blocks;
struct nand_block *blocks;
struct nand_device *next;
};
nand_block_t *blocks;
struct nand_device_s *next;
} nand_device_t;
/* NAND Flash Manufacturer ID Codes
*/
@@ -89,22 +98,21 @@ enum
NAND_MFR_MICRON = 0x2c,
};
struct nand_manufacturer
typedef struct nand_manufacturer_s
{
int id;
const char *name;
};
char *name;
} nand_manufacturer_t;
struct nand_info
typedef struct nand_info_s
{
int mfr_id;
char *name;
int id;
int page_size;
int chip_size;
int erase_size;
int options;
const char *name;
};
} nand_info_t;
/* Option constants for bizarre disfunctionality and real features
*/
@@ -198,36 +206,16 @@ enum oob_formats
NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */
};
/* Function prototypes */
extern nand_device_t *get_nand_device_by_num(int num);
extern int nand_read_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
extern int nand_write_page_raw(struct nand_device_s *device, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
extern int nand_read_status(struct nand_device_s *device, uint8_t *status);
extern int nand_calculate_ecc(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
extern int nand_calculate_ecc_kw(struct nand_device_s *device, const uint8_t *dat, uint8_t *ecc_code);
struct nand_device *get_nand_device_by_num(int num);
int nand_page_command(struct nand_device *nand, uint32_t page,
uint8_t cmd, bool oob_only);
int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size);
int nand_write_data_page(struct nand_device *nand,
uint8_t *data, uint32_t size);
int nand_write_finish(struct nand_device *nand);
int nand_read_page_raw(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
int nand_write_page_raw(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
int nand_read_status(struct nand_device *nand, uint8_t *status);
int nand_calculate_ecc(struct nand_device *nand,
const uint8_t *dat, uint8_t *ecc_code);
int nand_calculate_ecc_kw(struct nand_device *nand,
const uint8_t *dat, uint8_t *ecc_code);
int nand_register_commands(struct command_context *cmd_ctx);
/// helper for parsing a nand device command argument string
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
struct nand_device **nand);
extern int nand_register_commands(struct command_context_s *cmd_ctx);
extern int nand_init(struct command_context_s *cmd_ctx);
#define ERROR_NAND_DEVICE_INVALID (-1100)
#define ERROR_NAND_OPERATION_FAILED (-1101)
@@ -237,5 +225,4 @@ COMMAND_HELPER(nand_command_get_device, unsigned name_index,
#define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105)
#define ERROR_NAND_NO_BUFFER (-1106)
#endif // FLASH_NAND_CORE_H
#endif /* NAND_H */

View File

@@ -1,46 +0,0 @@
include $(top_srcdir)/common.mk
noinst_LTLIBRARIES = libocdflashnand.la
libocdflashnand_la_SOURCES = \
ecc.c \
ecc_kw.c \
core.c \
fileio.c \
tcl.c \
arm_io.c \
$(NAND_DRIVERS) \
driver.c
NAND_DRIVERS = \
nonce.c \
davinci.c \
lpc3180.c \
lpc32xx.c \
mx2.c \
mx3.c \
orion.c \
s3c24xx.c \
s3c2410.c \
s3c2412.c \
s3c2440.c \
s3c2443.c \
s3c6400.c \
at91sam9.c \
nuc910.c
noinst_HEADERS = \
arm_io.h \
core.h \
driver.h \
fileio.h \
imp.h \
lpc3180.h \
lpc32xx.h \
mx2.h \
mx3.h \
s3c24xx.h \
s3c24xx_regs.h \
nuc910.h
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in

View File

@@ -1,249 +0,0 @@
/*
* Copyright (C) 2009 by Marvell Semiconductors, Inc.
* Written by Nicolas Pitre <nico at marvell.com>
*
* Copyright (C) 2009 by David Brownell
*
* 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 "core.h"
#include "arm_io.h"
#include <helper/binarybuffer.h>
#include <target/arm.h>
#include <target/algorithm.h>
/**
* Copies code to a working area. This will allocate room for the code plus the
* additional amount requested if the working area pointer is null.
*
* @param target Pointer to the target to copy code to
* @param code Pointer to the code area to be copied
* @param code_size Size of the code being copied
* @param additional Size of the additional area to be allocated in addition to
* code
* @param area Pointer to a pointer to a working area to copy code to
* @return Success or failure of the operation
*/
static int arm_code_to_working_area(struct target *target,
const uint32_t *code, unsigned code_size,
unsigned additional, struct working_area **area)
{
uint8_t code_buf[code_size];
unsigned i;
int retval;
unsigned size = code_size + additional;
/* REVISIT this assumes size doesn't ever change.
* That's usually correct; but there are boards with
* both large and small page chips, where it won't be...
*/
/* make sure we have a working area */
if (NULL == *area) {
retval = target_alloc_working_area(target, size, area);
if (retval != ERROR_OK) {
LOG_DEBUG("%s: no %d byte buffer", __FUNCTION__, (int) size);
return ERROR_NAND_NO_BUFFER;
}
}
/* buffer code in target endianness */
for (i = 0; i < code_size / 4; i++)
target_buffer_set_u32(target, code_buf + i * 4, code[i]);
/* copy code to work area */
retval = target_write_memory(target, (*area)->address,
4, code_size / 4, code_buf);
return retval;
}
/**
* ARM-specific bulk write from buffer to address of 8-bit wide NAND.
* For now this only supports ARMv4 and ARMv5 cores.
*
* Enhancements to target_run_algorithm() could enable:
* - ARMv6 and ARMv7 cores in ARM mode
*
* Different code fragments could handle:
* - Thumb2 cores like Cortex-M (needs different byteswapping)
* - 16-bit wide data (needs different setup too)
*
* @param nand Pointer to the arm_nand_data struct that defines the I/O
* @param data Pointer to the data to be copied to flash
* @param size Size of the data being copied
* @return Success or failure of the operation
*/
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
{
struct target *target = nand->target;
struct arm_algorithm algo;
struct arm *armv4_5 = target->arch_info;
struct reg_param reg_params[3];
uint32_t target_buf;
uint32_t exit_var = 0;
int retval;
/* Inputs:
* r0 NAND data address (byte wide)
* r1 buffer address
* r2 buffer length
*/
static const uint32_t code[] = {
0xe4d13001, /* s: ldrb r3, [r1], #1 */
0xe5c03000, /* strb r3, [r0] */
0xe2522001, /* subs r2, r2, #1 */
0x1afffffb, /* bne s */
/* exit: ARMv4 needs hardware breakpoint */
0xe1200070, /* e: bkpt #0 */
};
if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
retval = arm_code_to_working_area(target, code, sizeof(code),
nand->chunk_size, &nand->copy_area);
if (retval != ERROR_OK) {
return retval;
}
}
nand->op = ARM_NAND_WRITE;
/* copy data to work area */
target_buf = nand->copy_area->address + sizeof(code);
retval = target_bulk_write_memory(target, target_buf, size / 4, data);
if (retval == ERROR_OK && (size & 3) != 0)
retval = target_write_memory(target,
target_buf + (size & ~3),
1, size & 3, data + (size & ~3));
if (retval != ERROR_OK)
return retval;
/* set up algorithm and parameters */
algo.common_magic = ARM_COMMON_MAGIC;
algo.core_mode = ARM_MODE_SVC;
algo.core_state = ARM_STATE_ARM;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
buf_set_u32(reg_params[0].value, 0, 32, nand->data);
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
buf_set_u32(reg_params[2].value, 0, 32, size);
/* armv4 must exit using a hardware breakpoint */
if (armv4_5->is_armv4)
exit_var = nand->copy_area->address + sizeof(code) - 4;
/* use alg to write data from work area to NAND chip */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
nand->copy_area->address, exit_var, 1000, &algo);
if (retval != ERROR_OK)
LOG_ERROR("error executing hosted NAND write");
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
return retval;
}
/**
* Uses an on-chip algorithm for an ARM device to read from a NAND device and
* store the data into the host machine's memory.
*
* @param nand Pointer to the arm_nand_data struct that defines the I/O
* @param data Pointer to the data buffer to store the read data
* @param size Amount of data to be stored to the buffer.
* @return Success or failure of the operation
*/
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
{
struct target *target = nand->target;
struct arm_algorithm algo;
struct arm *armv4_5 = target->arch_info;
struct reg_param reg_params[3];
uint32_t target_buf;
uint32_t exit_var = 0;
int retval;
/* Inputs:
* r0 buffer address
* r1 NAND data address (byte wide)
* r2 buffer length
*/
static const uint32_t code[] = {
0xe5d13000, /* s: ldrb r3, [r1] */
0xe4c03001, /* strb r3, [r0], #1 */
0xe2522001, /* subs r2, r2, #1 */
0x1afffffb, /* bne s */
/* exit: ARMv4 needs hardware breakpoint */
0xe1200070, /* e: bkpt #0 */
};
/* create the copy area if not yet available */
if (nand->op != ARM_NAND_READ || !nand->copy_area) {
retval = arm_code_to_working_area(target, code, sizeof(code),
nand->chunk_size, &nand->copy_area);
if (retval != ERROR_OK) {
return retval;
}
}
nand->op = ARM_NAND_READ;
target_buf = nand->copy_area->address + sizeof(code);
/* set up algorithm and parameters */
algo.common_magic = ARM_COMMON_MAGIC;
algo.core_mode = ARM_MODE_SVC;
algo.core_state = ARM_STATE_ARM;
init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
buf_set_u32(reg_params[0].value, 0, 32, target_buf);
buf_set_u32(reg_params[1].value, 0, 32, nand->data);
buf_set_u32(reg_params[2].value, 0, 32, size);
/* armv4 must exit using a hardware breakpoint */
if (armv4_5->is_armv4)
exit_var = nand->copy_area->address + sizeof(code) - 4;
/* use alg to write data from NAND chip to work area */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
nand->copy_area->address, exit_var, 1000, &algo);
if (retval != ERROR_OK)
LOG_ERROR("error executing hosted NAND read");
destroy_reg_param(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_params[2]);
/* read from work area to the host's memory */
retval = target_read_buffer(target, target_buf, size, data);
return retval;
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright (C) 2009 by David Brownell
*
* 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 __ARM_NANDIO_H
#define __ARM_NANDIO_H
/**
* Available operational states the arm_nand_data struct can be in.
*/
enum arm_nand_op {
ARM_NAND_NONE, /**< No operation performed. */
ARM_NAND_READ, /**< Read operation performed. */
ARM_NAND_WRITE, /**< Write operation performed. */
};
/**
* The arm_nand_data struct is used for defining NAND I/O operations on an ARM
* core.
*/
struct arm_nand_data {
/** Target is proxy for some ARM core. */
struct target *target;
/** The copy area holds code loop and data for I/O operations. */
struct working_area *copy_area;
/** The chunk size is the page size or ECC chunk. */
unsigned chunk_size;
/** Where data is read from or written to. */
uint32_t data;
/** Last operation executed using this struct. */
enum arm_nand_op op;
/* currently implicit: data width == 8 bits (not 16) */
};
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size);
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size);
#endif /* __ARM_NANDIO_H */

View File

@@ -1,741 +0,0 @@
/*
* Copyright (C) 2009 by Dean Glazeski
* dnglaze@gmail.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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <target/arm.h>
#include <helper/log.h>
#include "imp.h"
#include "arm_io.h"
#define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */
#define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */
#define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */
#define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */
#define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */
#define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */
#define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */
/**
* Representation of a pin on an AT91SAM9 chip.
*/
struct at91sam9_pin {
/** Address of the PIO controller. */
uint32_t pioc;
/** Pin number. */
uint32_t num;
};
/**
* Private data for the controller that is stored in the NAND device structure.
*/
struct at91sam9_nand {
/** Address of the ECC controller for NAND. */
uint32_t ecc;
/** Address data is written to. */
uint32_t data;
/** Address commands are written to. */
uint32_t cmd;
/** Address addresses are written to. */
uint32_t addr;
/** I/O structure for hosted reads/writes. */
struct arm_nand_data io;
/** Pin representing the ready/~busy line. */
struct at91sam9_pin busy;
/** Pin representing the chip enable. */
struct at91sam9_pin ce;
};
/**
* Checks if the target is halted and prints an error message if it isn't.
*
* @param target Target to be checked.
* @param label String label for where function is called from.
* @return True if the target is halted.
*/
static int at91sam9_halted(struct target *target, const char *label)
{
if (target->state == TARGET_HALTED)
return true;
LOG_ERROR("Target must be halted to use NAND controller (%s)", label);
return false;
}
/**
* Initialize the AT91SAM9 NAND controller.
*
* @param nand NAND device the controller is attached to.
* @return Success or failure of initialization.
*/
static int at91sam9_init(struct nand_device *nand)
{
struct target *target = nand->target;
if (!at91sam9_halted(target, "init")) {
return ERROR_NAND_OPERATION_FAILED;
}
return ERROR_OK;
}
/**
* Enable NAND device attached to a controller.
*
* @param info NAND controller information for controlling NAND device.
* @return Success or failure of the enabling.
*/
static int at91sam9_enable(struct nand_device *nand)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num);
}
/**
* Disable NAND device attached to a controller.
*
* @param info NAND controller information for controlling NAND device.
* @return Success or failure of the disabling.
*/
static int at91sam9_disable(struct nand_device *nand)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num);
}
/**
* Send a command to the NAND device.
*
* @param nand NAND device to write the command to.
* @param command Command to be written.
* @return Success or failure of writing the command.
*/
static int at91sam9_command(struct nand_device *nand, uint8_t command)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
if (!at91sam9_halted(target, "command")) {
return ERROR_NAND_OPERATION_FAILED;
}
at91sam9_enable(nand);
return target_write_u8(target, info->cmd, command);
}
/**
* Reset the AT91SAM9 NAND controller.
*
* @param nand NAND device to be reset.
* @return Success or failure of reset.
*/
static int at91sam9_reset(struct nand_device *nand)
{
if (!at91sam9_halted(nand->target, "reset")) {
return ERROR_NAND_OPERATION_FAILED;
}
return at91sam9_disable(nand);
}
/**
* Send an address to the NAND device attached to an AT91SAM9 NAND controller.
*
* @param nand NAND device to send the address to.
* @param address Address to be sent.
* @return Success or failure of sending the address.
*/
static int at91sam9_address(struct nand_device *nand, uint8_t address)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
if (!at91sam9_halted(nand->target, "address")) {
return ERROR_NAND_OPERATION_FAILED;
}
return target_write_u8(target, info->addr, address);
}
/**
* Read data directly from the NAND device attached to an AT91SAM9 NAND
* controller.
*
* @param nand NAND device to read from.
* @param data Pointer to where the data should be put.
* @return Success or failure of reading the data.
*/
static int at91sam9_read_data(struct nand_device *nand, void *data)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
if (!at91sam9_halted(nand->target, "read data")) {
return ERROR_NAND_OPERATION_FAILED;
}
return target_read_u8(target, info->data, data);
}
/**
* Write data directly to the NAND device attached to an AT91SAM9 NAND
* controller.
*
* @param nand NAND device to be written to.
* @param data Data to be written.
* @return Success or failure of the data write.
*/
static int at91sam9_write_data(struct nand_device *nand, uint16_t data)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
if (!at91sam9_halted(target, "write data")) {
return ERROR_NAND_OPERATION_FAILED;
}
return target_write_u8(target, info->data, data);
}
/**
* Determine if the NAND device is ready by looking at the ready/~busy pin.
*
* @param nand NAND device to check.
* @param timeout Time in milliseconds to wait for NAND to be ready.
* @return True if the NAND is ready in the timeout period.
*/
static int at91sam9_nand_ready(struct nand_device *nand, int timeout)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
uint32_t status;
if (!at91sam9_halted(target, "nand ready")) {
return 0;
}
do {
target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status);
if (status & (1 << info->busy.num)) {
return 1;
}
alive_sleep(1);
} while (timeout-- > 0);
return 0;
}
/**
* Read a block of data from the NAND device attached to an AT91SAM9. This
* utilizes the ARM hosted NAND read function.
*
* @param nand NAND device to read from.
* @param data Pointer to where the read data should be placed.
* @param size Size of the data being read.
* @return Success or failure of the hosted read.
*/
static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size)
{
struct at91sam9_nand *info = nand->controller_priv;
struct arm_nand_data *io = &info->io;
int status;
if (!at91sam9_halted(nand->target, "read block")) {
return ERROR_NAND_OPERATION_FAILED;
}
io->chunk_size = nand->page_size;
status = arm_nandread(io, data, size);
return status;
}
/**
* Write a block of data to a NAND device attached to an AT91SAM9. This uses
* the ARM hosted write function to write the data.
*
* @param nand NAND device to write to.
* @param data Data to be written to device.
* @param size Size of the data being written.
* @return Success or failure of the hosted write.
*/
static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size)
{
struct at91sam9_nand *info = nand->controller_priv;
struct arm_nand_data *io = &info->io;
int status;
if (!at91sam9_halted(nand->target, "write block")) {
return ERROR_NAND_OPERATION_FAILED;
}
io->chunk_size = nand->page_size;
status = arm_nandwrite(io, data, size);
return status;
}
/**
* Initialize the ECC controller on the AT91SAM9.
*
* @param target Target to configure ECC on.
* @param info NAND controller information for where the ECC is.
* @return Success or failure of initialization.
*/
static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info)
{
if (!info->ecc) {
LOG_ERROR("ECC controller address must be set when not reading raw NAND data");
return ERROR_NAND_OPERATION_FAILED;
}
// reset ECC parity registers
return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1);
}
/**
* Initialize an area for the OOB based on whether a user is requesting the OOB
* data. This determines the size of the OOB and allocates the space in case
* the user has not requested the OOB data.
*
* @param nand NAND device we are creating an OOB for.
* @param oob Pointer to the user supplied OOB area.
* @param size Size of the OOB.
* @return Pointer to an area to store OOB data.
*/
static uint8_t * at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size)
{
if (!oob) {
// user doesn't want OOB, allocate it
if (nand->page_size == 512) {
*size = 16;
} else if (nand->page_size == 2048) {
*size = 64;
}
oob = malloc(*size);
if (!oob) {
LOG_ERROR("Unable to allocate space for OOB");
}
memset(oob, 0xFF, *size);
}
return oob;
}
/**
* Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC
* controller on chip. This makes an attempt to correct any errors that are
* encountered while reading the page of data.
*
* @param nand NAND device to read from
* @param page Page to be read.
* @param data Pointer to where data should be read to.
* @param data_size Size of the data to be read.
* @param oob Pointer to where OOB data should be read to.
* @param oob_size Size of the OOB data to be read.
* @return Success or failure of reading the NAND page.
*/
static int at91sam9_read_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
int retval;
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
uint8_t *oob_data;
uint32_t status;
retval = at91sam9_ecc_init(target, info);
if (ERROR_OK != retval) {
return retval;
}
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
if (ERROR_OK != retval) {
return retval;
}
if (data) {
retval = nand_read_data_page(nand, data, data_size);
if (ERROR_OK != retval) {
return retval;
}
}
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
retval = nand_read_data_page(nand, oob_data, oob_size);
if (ERROR_OK == retval && data) {
target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status);
if (status & 1) {
LOG_ERROR("Error detected!");
if (status & 4) {
LOG_ERROR("Multiple errors encountered; unrecoverable!");
} else {
// attempt recovery
uint32_t parity;
target_read_u32(target,
info->ecc + AT91C_ECCx_PR,
&parity);
uint32_t word = (parity & 0x0000FFF0) >> 4;
uint32_t bit = parity & 0x0F;
data[word] ^= (0x1) << bit;
LOG_INFO("Data word %d, bit %d corrected.",
(unsigned) word,
(unsigned) bit);
}
}
if (status & 2) {
// we could write back correct ECC data
LOG_ERROR("Error in ECC bytes detected");
}
}
if (!oob) {
// if it wasn't asked for, free it
free(oob_data);
}
return retval;
}
/**
* Write a page of data including 1-bit ECC information to a NAND device
* attached to an AT91SAM9 controller. If there is OOB data to be written,
* this will ignore the computed ECC from the ECC controller.
*
* @param nand NAND device to write to.
* @param page Page to write.
* @param data Pointer to data being written.
* @param data_size Size of the data being written.
* @param oob Pointer to OOB data being written.
* @param oob_size Size of the OOB data.
* @return Success or failure of the page write.
*/
static int at91sam9_write_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size)
{
struct at91sam9_nand *info = nand->controller_priv;
struct target *target = nand->target;
int retval;
uint8_t *oob_data = oob;
uint32_t parity, nparity;
retval = at91sam9_ecc_init(target, info);
if (ERROR_OK != retval) {
return retval;
}
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
if (ERROR_OK != retval) {
return retval;
}
if (data) {
retval = nand_write_data_page(nand, data, data_size);
if (ERROR_OK != retval) {
LOG_ERROR("Unable to write data to NAND device");
return retval;
}
}
oob_data = at91sam9_oob_init(nand, oob, &oob_size);
if (!oob) {
// no OOB given, so read in the ECC parity from the ECC controller
target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity);
target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity);
oob_data[0] = (uint8_t) parity;
oob_data[1] = (uint8_t) (parity >> 8);
oob_data[2] = (uint8_t) nparity;
oob_data[3] = (uint8_t) (nparity >> 8);
}
retval = nand_write_data_page(nand, oob_data, oob_size);
if (!oob) {
free(oob_data);
}
if (ERROR_OK != retval) {
LOG_ERROR("Unable to write OOB data to NAND");
return retval;
}
retval = nand_write_finish(nand);
return retval;
}
/**
* Handle the initial NAND device command for AT91SAM9 controllers. This
* initializes much of the controller information struct to be ready for future
* reads and writes.
*/
NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command)
{
unsigned long chip = 0, ecc = 0;
struct at91sam9_nand *info = NULL;
LOG_DEBUG("AT91SAM9 NAND Device Command");
if (CMD_ARGC < 3 || CMD_ARGC > 4) {
LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]);
return ERROR_NAND_OPERATION_FAILED;
}
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip);
if (chip == 0) {
LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]);
return ERROR_NAND_OPERATION_FAILED;
}
if (CMD_ARGC == 4) {
COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc);
if (ecc == 0) {
LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]);
return ERROR_NAND_OPERATION_FAILED;
}
}
info = calloc(1, sizeof(*info));
if (!info) {
LOG_ERROR("unable to allocate space for controller private data");
return ERROR_NAND_OPERATION_FAILED;
}
info->data = chip;
info->cmd = chip | (1 << 22);
info->addr = chip | (1 << 21);
info->ecc = ecc;
nand->controller_priv = info;
info->io.target = nand->target;
info->io.data = info->data;
info->io.op = ARM_NAND_NONE;
return ERROR_OK;
}
/**
* Handle the AT91SAM9 CLE command for specifying the address line to use for
* writing commands to a NAND device.
*/
COMMAND_HANDLER(handle_at91sam9_cle_command)
{
struct nand_device *nand = NULL;
struct at91sam9_nand *info = NULL;
unsigned num, address_line;
if (CMD_ARGC != 2) {
command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command");
return ERROR_OK;
}
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
nand = get_nand_device_by_num(num);
if (!nand) {
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
return ERROR_OK;
}
info = nand->controller_priv;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
info->cmd = info->data | (1 << address_line);
return ERROR_OK;
}
/**
* Handle the AT91SAM9 ALE command for specifying the address line to use for
* writing addresses to the NAND device.
*/
COMMAND_HANDLER(handle_at91sam9_ale_command)
{
struct nand_device *nand = NULL;
struct at91sam9_nand *info = NULL;
unsigned num, address_line;
if (CMD_ARGC != 2) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
nand = get_nand_device_by_num(num);
if (!nand) {
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
info = nand->controller_priv;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line);
info->addr = info->data | (1 << address_line);
return ERROR_OK;
}
/**
* Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the
* RDY/~BUSY line from the NAND device.
*/
COMMAND_HANDLER(handle_at91sam9_rdy_busy_command)
{
struct nand_device *nand = NULL;
struct at91sam9_nand *info = NULL;
unsigned num, base_pioc, pin_num;
if (CMD_ARGC != 3) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
nand = get_nand_device_by_num(num);
if (!nand) {
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
info = nand->controller_priv;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
info->busy.pioc = base_pioc;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
info->busy.num = pin_num;
return ERROR_OK;
}
/**
* Handle the AT91SAM9 CE command for specifying the pin that is used to enable
* or disable the NAND device.
*/
COMMAND_HANDLER(handle_at91sam9_ce_command)
{
struct nand_device *nand = NULL;
struct at91sam9_nand *info = NULL;
unsigned num, base_pioc, pin_num;
if (CMD_ARGC != 3) {
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num);
nand = get_nand_device_by_num(num);
if (!nand) {
command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]);
return ERROR_COMMAND_ARGUMENT_INVALID;
}
info = nand->controller_priv;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc);
info->ce.pioc = base_pioc;
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num);
info->ce.num = pin_num;
return ERROR_OK;
}
static const struct command_registration at91sam9_sub_command_handlers[] = {
{
.name = "cle",
.handler = handle_at91sam9_cle_command,
.mode = COMMAND_CONFIG,
.help = "set command latch enable address line (default is 22)",
.usage = "bank_id address_line",
},
{
.name = "ale",
.handler = handle_at91sam9_ale_command,
.mode = COMMAND_CONFIG,
.help = "set address latch enable address line (default is 21)",
.usage = "bank_id address_line",
},
{
.name = "rdy_busy",
.handler = handle_at91sam9_rdy_busy_command,
.mode = COMMAND_CONFIG,
.help = "set the GPIO input pin connected to "
"the RDY/~BUSY signal (no default)",
.usage = "bank_id pio_base_addr pin_num",
},
{
.name = "ce",
.handler = handle_at91sam9_ce_command,
.mode = COMMAND_CONFIG,
.help = "set the GPIO output pin connected to "
"the chip enable signal (no default)",
.usage = "bank_id pio_base_addr pin_num",
},
COMMAND_REGISTRATION_DONE
};
static const struct command_registration at91sam9_command_handler[] = {
{
.name = "at91sam9",
.mode = COMMAND_ANY,
.help = "AT91SAM9 NAND flash controller commands",
.chain = at91sam9_sub_command_handlers,
},
COMMAND_REGISTRATION_DONE
};
/**
* Structure representing the AT91SAM9 NAND controller.
*/
struct nand_flash_controller at91sam9_nand_controller = {
.name = "at91sam9",
.nand_device_command = at91sam9_nand_device_command,
.commands = at91sam9_command_handler,
.init = at91sam9_init,
.command = at91sam9_command,
.reset = at91sam9_reset,
.address = at91sam9_address,
.read_data = at91sam9_read_data,
.write_data = at91sam9_write_data,
.nand_ready = at91sam9_nand_ready,
.read_block_data = at91sam9_read_block_data,
.write_block_data = at91sam9_write_block_data,
.read_page = at91sam9_read_page,
.write_page = at91sam9_write_page,
};

View File

@@ -1,920 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* Partially based on drivers/mtd/nand_ids.c from Linux. *
* *
* 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 "imp.h"
/* configured NAND devices and NAND Flash command handler */
struct nand_device *nand_devices = NULL;
void nand_device_add(struct nand_device *c)
{
if (nand_devices) {
struct nand_device *p = nand_devices;
while (p && p->next) p = p->next;
p->next = c;
} else
nand_devices = c;
}
/* Chip ID list
*
* Manufacturer, ID code, pagesize, chipsize in MegaByte, eraseblock size,
* options, name
*
* Pagesize; 0, 256, 512
* 0 get this information from the extended chip ID
* 256 256 Byte page size
* 512 512 Byte page size
*/
static struct nand_info nand_flash_ids[] =
{
/* Vendor Specific Entries */
{ NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"},
{ NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"},
/* start "museum" IDs */
{ 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"},
{ 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"},
{ 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"},
{ 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
{ 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"},
{ 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"},
{ 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
{ 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
{ 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"},
{ 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
{ 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"},
{ 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"},
{ 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"},
{ 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"},
/* end "museum" IDs */
{ 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"},
{ 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"},
{ 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 1.8V 16-bit"},
{ 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16,"NAND 16MiB 3.3V 16-bit"},
{ 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"},
{ 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"},
{ 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 1.8V 16-bit"},
{ 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16,"NAND 32MiB 3.3V 16-bit"},
{ 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"},
{ 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"},
{ 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 1.8V 16-bit"},
{ 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16,"NAND 64MiB 3.3V 16-bit"},
{ 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
{ 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"},
{ 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"},
{ 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
{ 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 1.8V 16-bit"},
{ 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
{ 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16,"NAND 128MiB 3.3V 16-bit"},
{ 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"},
{ 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"},
{ 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"},
{ 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"},
{ 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"},
{ 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"},
{ 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"},
{ 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"},
{ 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"},
{ 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"},
{ 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"},
{ 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"},
{ 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"},
{ 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"},
{ 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"},
{ 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"},
{ 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"},
{ 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"},
{ 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"},
{ 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"},
{ 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"},
{ 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"},
{ 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
{ 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"},
{ 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"},
{ 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"},
{0, 0, 0, 0, 0, 0, NULL}
};
/* Manufacturer ID list
*/
static struct nand_manufacturer nand_manuf_ids[] =
{
{0x0, "unknown"},
{NAND_MFR_TOSHIBA, "Toshiba"},
{NAND_MFR_SAMSUNG, "Samsung"},
{NAND_MFR_FUJITSU, "Fujitsu"},
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
{0x0, NULL},
};
/*
* Define default oob placement schemes for large and small page devices
*/
#if 0
static struct nand_ecclayout nand_oob_8 = {
.eccbytes = 3,
.eccpos = {0, 1, 2},
.oobfree = {
{.offset = 3,
.length = 2},
{.offset = 6,
.length = 2}}
};
#endif
/**
* Returns the flash bank specified by @a name, which matches the
* driver name and a suffix (option) specify the driver-specific
* bank number. The suffix consists of the '.' and the driver-specific
* bank number: when two davinci banks are defined, then 'davinci.1' refers
* to the second (e.g. DM355EVM).
*/
static struct nand_device *get_nand_device_by_name(const char *name)
{
unsigned requested = get_flash_name_index(name);
unsigned found = 0;
struct nand_device *nand;
for (nand = nand_devices; NULL != nand; nand = nand->next)
{
if (strcmp(nand->name, name) == 0)
return nand;
if (!flash_driver_name_matches(nand->controller->name, name))
continue;
if (++found < requested)
continue;
return nand;
}
return NULL;
}
struct nand_device *get_nand_device_by_num(int num)
{
struct nand_device *p;
int i = 0;
for (p = nand_devices; p; p = p->next)
{
if (i++ == num)
{
return p;
}
}
return NULL;
}
COMMAND_HELPER(nand_command_get_device, unsigned name_index,
struct nand_device **nand)
{
const char *str = CMD_ARGV[name_index];
*nand = get_nand_device_by_name(str);
if (*nand)
return ERROR_OK;
unsigned num;
COMMAND_PARSE_NUMBER(uint, str, num);
*nand = get_nand_device_by_num(num);
if (!*nand) {
command_print(CMD_CTX, "NAND flash device '%s' not found", str);
return ERROR_INVALID_ARGUMENTS;
}
return ERROR_OK;
}
int nand_build_bbt(struct nand_device *nand, int first, int last)
{
uint32_t page;
int i;
int pages_per_block = (nand->erase_size / nand->page_size);
uint8_t oob[6];
int ret;
if ((first < 0) || (first >= nand->num_blocks))
first = 0;
if ((last >= nand->num_blocks) || (last == -1))
last = nand->num_blocks - 1;
page = first * pages_per_block;
for (i = first; i <= last; i++)
{
ret = nand_read_page(nand, page, NULL, 0, oob, 6);
if (ret != ERROR_OK)
return ret;
if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff))
|| (((nand->page_size == 512) && (oob[5] != 0xff)) ||
((nand->page_size == 2048) && (oob[0] != 0xff))))
{
LOG_WARNING("bad block: %i", i);
nand->blocks[i].is_bad = 1;
}
else
{
nand->blocks[i].is_bad = 0;
}
page += pages_per_block;
}
return ERROR_OK;
}
int nand_read_status(struct nand_device *nand, uint8_t *status)
{
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
/* Send read status command */
nand->controller->command(nand, NAND_CMD_STATUS);
alive_sleep(1);
/* read status */
if (nand->device->options & NAND_BUSWIDTH_16)
{
uint16_t data;
nand->controller->read_data(nand, &data);
*status = data & 0xff;
}
else
{
nand->controller->read_data(nand, status);
}
return ERROR_OK;
}
static int nand_poll_ready(struct nand_device *nand, int timeout)
{
uint8_t status;
nand->controller->command(nand, NAND_CMD_STATUS);
do {
if (nand->device->options & NAND_BUSWIDTH_16) {
uint16_t data;
nand->controller->read_data(nand, &data);
status = data & 0xff;
} else {
nand->controller->read_data(nand, &status);
}
if (status & NAND_STATUS_READY)
break;
alive_sleep(1);
} while (timeout--);
return (status & NAND_STATUS_READY) != 0;
}
int nand_probe(struct nand_device *nand)
{
uint8_t manufacturer_id, device_id;
uint8_t id_buff[6];
int retval;
int i;
/* clear device data */
nand->device = NULL;
nand->manufacturer = NULL;
/* clear device parameters */
nand->bus_width = 0;
nand->address_cycles = 0;
nand->page_size = 0;
nand->erase_size = 0;
/* initialize controller (device parameters are zero, use controller default) */
if ((retval = nand->controller->init(nand) != ERROR_OK))
{
switch (retval)
{
case ERROR_NAND_OPERATION_FAILED:
LOG_DEBUG("controller initialization failed");
return ERROR_NAND_OPERATION_FAILED;
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
LOG_ERROR("BUG: controller reported that it doesn't support default parameters");
return ERROR_NAND_OPERATION_FAILED;
default:
LOG_ERROR("BUG: unknown controller initialization failure");
return ERROR_NAND_OPERATION_FAILED;
}
}
nand->controller->command(nand, NAND_CMD_RESET);
nand->controller->reset(nand);
nand->controller->command(nand, NAND_CMD_READID);
nand->controller->address(nand, 0x0);
if (nand->bus_width == 8)
{
nand->controller->read_data(nand, &manufacturer_id);
nand->controller->read_data(nand, &device_id);
}
else
{
uint16_t data_buf;
nand->controller->read_data(nand, &data_buf);
manufacturer_id = data_buf & 0xff;
nand->controller->read_data(nand, &data_buf);
device_id = data_buf & 0xff;
}
for (i = 0; nand_flash_ids[i].name; i++)
{
if (nand_flash_ids[i].id == device_id &&
(nand_flash_ids[i].mfr_id == manufacturer_id ||
nand_flash_ids[i].mfr_id == 0 ))
{
nand->device = &nand_flash_ids[i];
break;
}
}
for (i = 0; nand_manuf_ids[i].name; i++)
{
if (nand_manuf_ids[i].id == manufacturer_id)
{
nand->manufacturer = &nand_manuf_ids[i];
break;
}
}
if (!nand->manufacturer)
{
nand->manufacturer = &nand_manuf_ids[0];
nand->manufacturer->id = manufacturer_id;
}
if (!nand->device)
{
LOG_ERROR("unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x",
manufacturer_id, device_id);
return ERROR_NAND_OPERATION_FAILED;
}
LOG_DEBUG("found %s (%s)", nand->device->name, nand->manufacturer->name);
/* initialize device parameters */
/* bus width */
if (nand->device->options & NAND_BUSWIDTH_16)
nand->bus_width = 16;
else
nand->bus_width = 8;
/* Do we need extended device probe information? */
if (nand->device->page_size == 0 ||
nand->device->erase_size == 0)
{
if (nand->bus_width == 8)
{
nand->controller->read_data(nand, id_buff + 3);
nand->controller->read_data(nand, id_buff + 4);
nand->controller->read_data(nand, id_buff + 5);
}
else
{
uint16_t data_buf;
nand->controller->read_data(nand, &data_buf);
id_buff[3] = data_buf;
nand->controller->read_data(nand, &data_buf);
id_buff[4] = data_buf;
nand->controller->read_data(nand, &data_buf);
id_buff[5] = data_buf >> 8;
}
}
/* page size */
if (nand->device->page_size == 0)
{
nand->page_size = 1 << (10 + (id_buff[4] & 3));
}
else if (nand->device->page_size == 256)
{
LOG_ERROR("NAND flashes with 256 byte pagesize are not supported");
return ERROR_NAND_OPERATION_FAILED;
}
else
{
nand->page_size = nand->device->page_size;
}
/* number of address cycles */
if (nand->page_size <= 512)
{
/* small page devices */
if (nand->device->chip_size <= 32)
nand->address_cycles = 3;
else if (nand->device->chip_size <= 8*1024)
nand->address_cycles = 4;
else
{
LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered");
nand->address_cycles = 5;
}
}
else
{
/* large page devices */
if (nand->device->chip_size <= 128)
nand->address_cycles = 4;
else if (nand->device->chip_size <= 32*1024)
nand->address_cycles = 5;
else
{
LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered");
nand->address_cycles = 6;
}
}
/* erase size */
if (nand->device->erase_size == 0)
{
switch ((id_buff[4] >> 4) & 3) {
case 0:
nand->erase_size = 64 << 10;
break;
case 1:
nand->erase_size = 128 << 10;
break;
case 2:
nand->erase_size = 256 << 10;
break;
case 3:
nand->erase_size =512 << 10;
break;
}
}
else
{
nand->erase_size = nand->device->erase_size;
}
/* initialize controller, but leave parameters at the controllers default */
if ((retval = nand->controller->init(nand) != ERROR_OK))
{
switch (retval)
{
case ERROR_NAND_OPERATION_FAILED:
LOG_DEBUG("controller initialization failed");
return ERROR_NAND_OPERATION_FAILED;
case ERROR_NAND_OPERATION_NOT_SUPPORTED:
LOG_ERROR("controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)",
nand->bus_width, nand->address_cycles, nand->page_size);
return ERROR_NAND_OPERATION_FAILED;
default:
LOG_ERROR("BUG: unknown controller initialization failure");
return ERROR_NAND_OPERATION_FAILED;
}
}
nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024);
nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks);
for (i = 0; i < nand->num_blocks; i++)
{
nand->blocks[i].size = nand->erase_size;
nand->blocks[i].offset = i * nand->erase_size;
nand->blocks[i].is_erased = -1;
nand->blocks[i].is_bad = -1;
}
return ERROR_OK;
}
int nand_erase(struct nand_device *nand, int first_block, int last_block)
{
int i;
uint32_t page;
uint8_t status;
int retval;
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if ((first_block < 0) || (last_block >= nand->num_blocks))
return ERROR_INVALID_ARGUMENTS;
/* make sure we know if a block is bad before erasing it */
for (i = first_block; i <= last_block; i++)
{
if (nand->blocks[i].is_bad == -1)
{
nand_build_bbt(nand, i, last_block);
break;
}
}
for (i = first_block; i <= last_block; i++)
{
/* Send erase setup command */
nand->controller->command(nand, NAND_CMD_ERASE1);
page = i * (nand->erase_size / nand->page_size);
/* Send page address */
if (nand->page_size <= 512)
{
/* row */
nand->controller->address(nand, page & 0xff);
nand->controller->address(nand, (page >> 8) & 0xff);
/* 3rd cycle only on devices with more than 32 MiB */
if (nand->address_cycles >= 4)
nand->controller->address(nand, (page >> 16) & 0xff);
/* 4th cycle only on devices with more than 8 GiB */
if (nand->address_cycles >= 5)
nand->controller->address(nand, (page >> 24) & 0xff);
}
else
{
/* row */
nand->controller->address(nand, page & 0xff);
nand->controller->address(nand, (page >> 8) & 0xff);
/* 3rd cycle only on devices with more than 128 MiB */
if (nand->address_cycles >= 5)
nand->controller->address(nand, (page >> 16) & 0xff);
}
/* Send erase confirm command */
nand->controller->command(nand, NAND_CMD_ERASE2);
retval = nand->controller->nand_ready ?
nand->controller->nand_ready(nand, 1000) :
nand_poll_ready(nand, 1000);
if (!retval) {
LOG_ERROR("timeout waiting for NAND flash block erase to complete");
return ERROR_NAND_OPERATION_TIMEOUT;
}
if ((retval = nand_read_status(nand, &status)) != ERROR_OK)
{
LOG_ERROR("couldn't read status");
return ERROR_NAND_OPERATION_FAILED;
}
if (status & 0x1)
{
LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x",
(nand->blocks[i].is_bad == 1)
? "bad " : "",
i, status);
/* continue; other blocks might still be erasable */
}
nand->blocks[i].is_erased = 1;
}
return ERROR_OK;
}
#if 0
static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size)
{
uint8_t *page;
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (address % nand->page_size)
{
LOG_ERROR("reads need to be page aligned");
return ERROR_NAND_OPERATION_FAILED;
}
page = malloc(nand->page_size);
while (data_size > 0)
{
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
uint32_t page_address;
page_address = address / nand->page_size;
nand_read_page(nand, page_address, page, nand->page_size, NULL, 0);
memcpy(data, page, thisrun_size);
address += thisrun_size;
data += thisrun_size;
data_size -= thisrun_size;
}
free(page);
return ERROR_OK;
}
static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size)
{
uint8_t *page;
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (address % nand->page_size)
{
LOG_ERROR("writes need to be page aligned");
return ERROR_NAND_OPERATION_FAILED;
}
page = malloc(nand->page_size);
while (data_size > 0)
{
uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size;
uint32_t page_address;
memset(page, 0xff, nand->page_size);
memcpy(page, data, thisrun_size);
page_address = address / nand->page_size;
nand_write_page(nand, page_address, page, nand->page_size, NULL, 0);
address += thisrun_size;
data += thisrun_size;
data_size -= thisrun_size;
}
free(page);
return ERROR_OK;
}
#endif
int nand_write_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
uint32_t block;
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
block = page / (nand->erase_size / nand->page_size);
if (nand->blocks[block].is_erased == 1)
nand->blocks[block].is_erased = 0;
if (nand->use_raw || nand->controller->write_page == NULL)
return nand_write_page_raw(nand, page, data, data_size, oob, oob_size);
else
return nand->controller->write_page(nand, page, data, data_size, oob, oob_size);
}
int nand_read_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (nand->use_raw || nand->controller->read_page == NULL)
return nand_read_page_raw(nand, page, data, data_size, oob, oob_size);
else
return nand->controller->read_page(nand, page, data, data_size, oob, oob_size);
}
int nand_page_command(struct nand_device *nand, uint32_t page,
uint8_t cmd, bool oob_only)
{
if (!nand->device)
return ERROR_NAND_DEVICE_NOT_PROBED;
if (oob_only && NAND_CMD_READ0 == cmd && nand->page_size <= 512)
cmd = NAND_CMD_READOOB;
nand->controller->command(nand, cmd);
if (nand->page_size <= 512) {
/* small page device */
/* column (always 0, we start at the beginning of a page/OOB area) */
nand->controller->address(nand, 0x0);
/* row */
nand->controller->address(nand, page & 0xff);
nand->controller->address(nand, (page >> 8) & 0xff);
/* 4th cycle only on devices with more than 32 MiB */
if (nand->address_cycles >= 4)
nand->controller->address(nand, (page >> 16) & 0xff);
/* 5th cycle only on devices with more than 8 GiB */
if (nand->address_cycles >= 5)
nand->controller->address(nand, (page >> 24) & 0xff);
} else {
/* large page device */
/* column (0 when we start at the beginning of a page,
* or 2048 for the beginning of OOB area)
*/
nand->controller->address(nand, 0x0);
if (oob_only)
nand->controller->address(nand, 0x8);
else
nand->controller->address(nand, 0x0);
/* row */
nand->controller->address(nand, page & 0xff);
nand->controller->address(nand, (page >> 8) & 0xff);
/* 5th cycle only on devices with more than 128 MiB */
if (nand->address_cycles >= 5)
nand->controller->address(nand, (page >> 16) & 0xff);
/* large page devices need a start command if reading */
if (NAND_CMD_READ0 == cmd)
nand->controller->command(nand, NAND_CMD_READSTART);
}
if (nand->controller->nand_ready) {
if (!nand->controller->nand_ready(nand, 100))
return ERROR_NAND_OPERATION_TIMEOUT;
} else {
/* nand_poll_read() cannot be used during nand read */
alive_sleep(1);
}
return ERROR_OK;
}
int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
{
int retval = ERROR_NAND_NO_BUFFER;
if (nand->controller->read_block_data != NULL)
retval = (nand->controller->read_block_data)(nand, data, size);
if (ERROR_NAND_NO_BUFFER == retval) {
uint32_t i;
int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1;
retval = ERROR_OK;
for (i = 0; retval == ERROR_OK && i < size; i += incr) {
retval = nand->controller->read_data(nand, data);
data += incr;
}
}
return retval;
}
int nand_read_page_raw(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
int retval;
retval = nand_page_command(nand, page, NAND_CMD_READ0, !data);
if (ERROR_OK != retval)
return retval;
if (data)
nand_read_data_page(nand, data, data_size);
if (oob)
nand_read_data_page(nand, oob, oob_size);
return ERROR_OK;
}
int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size)
{
int retval = ERROR_NAND_NO_BUFFER;
if (nand->controller->write_block_data != NULL)
retval = (nand->controller->write_block_data)(nand, data, size);
if (ERROR_NAND_NO_BUFFER == retval) {
bool is16bit = nand->device->options & NAND_BUSWIDTH_16;
uint32_t incr = is16bit ? 2 : 1;
uint16_t write_data;
uint32_t i;
for (i = 0; i < size; i += incr) {
if (is16bit)
write_data = le_to_h_u16(data);
else
write_data = *data;
retval = nand->controller->write_data(nand, write_data);
if (ERROR_OK != retval)
break;
data += incr;
}
}
return retval;
}
int nand_write_finish(struct nand_device *nand)
{
int retval;
uint8_t status;
nand->controller->command(nand, NAND_CMD_PAGEPROG);
retval = nand->controller->nand_ready ?
nand->controller->nand_ready(nand, 100) :
nand_poll_ready(nand, 100);
if (!retval)
return ERROR_NAND_OPERATION_TIMEOUT;
retval = nand_read_status(nand, &status);
if (ERROR_OK != retval) {
LOG_ERROR("couldn't read status");
return ERROR_NAND_OPERATION_FAILED;
}
if (status & NAND_STATUS_FAIL) {
LOG_ERROR("write operation didn't pass, status: 0x%2.2x",
status);
return ERROR_NAND_OPERATION_FAILED;
}
return ERROR_OK;
}
int nand_write_page_raw(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size)
{
int retval;
retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data);
if (ERROR_OK != retval)
return retval;
if (data) {
retval = nand_write_data_page(nand, data, data_size);
if (ERROR_OK != retval) {
LOG_ERROR("Unable to write data to NAND device");
return retval;
}
}
if (oob) {
retval = nand_write_data_page(nand, oob, oob_size);
if (ERROR_OK != retval) {
LOG_ERROR("Unable to write OOB data to NAND device");
return retval;
}
}
return nand_write_finish(nand);
}

View File

@@ -1,89 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* 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 "core.h"
#include "driver.h"
/* NAND flash controller
*/
extern struct nand_flash_controller nonce_nand_controller;
extern struct nand_flash_controller davinci_nand_controller;
extern struct nand_flash_controller lpc3180_nand_controller;
extern struct nand_flash_controller lpc32xx_nand_controller;
extern struct nand_flash_controller orion_nand_controller;
extern struct nand_flash_controller s3c2410_nand_controller;
extern struct nand_flash_controller s3c2412_nand_controller;
extern struct nand_flash_controller s3c2440_nand_controller;
extern struct nand_flash_controller s3c2443_nand_controller;
extern struct nand_flash_controller s3c6400_nand_controller;
extern struct nand_flash_controller imx27_nand_flash_controller;
extern struct nand_flash_controller imx31_nand_flash_controller;
extern struct nand_flash_controller at91sam9_nand_controller;
extern struct nand_flash_controller nuc910_nand_controller;
/* extern struct nand_flash_controller boundary_scan_nand_controller; */
static struct nand_flash_controller *nand_flash_controllers[] =
{
&nonce_nand_controller,
&davinci_nand_controller,
&lpc3180_nand_controller,
&lpc32xx_nand_controller,
&orion_nand_controller,
&s3c2410_nand_controller,
&s3c2412_nand_controller,
&s3c2440_nand_controller,
&s3c2443_nand_controller,
&s3c6400_nand_controller,
&imx27_nand_flash_controller,
&imx31_nand_flash_controller,
&at91sam9_nand_controller,
&nuc910_nand_controller,
/* &boundary_scan_nand_controller, */
NULL
};
struct nand_flash_controller *nand_driver_find_by_name(const char *name)
{
for (unsigned i = 0; nand_flash_controllers[i]; i++)
{
struct nand_flash_controller *controller = nand_flash_controllers[i];
if (strcmp(name, controller->name) == 0)
return controller;
}
return NULL;
}
int nand_driver_walk(nand_driver_walker_t f, void *x)
{
for (unsigned i = 0; nand_flash_controllers[i]; i++)
{
int retval = (*f)(nand_flash_controllers[i], x);
if (ERROR_OK != retval)
return retval;
}
return ERROR_OK;
}

View File

@@ -1,100 +0,0 @@
/***************************************************************************
* Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2007,2008 Øyvind Harboe <oyvind.harboe@zylin.com> *
* Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* 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_NAND_DRIVER_H
#define FLASH_NAND_DRIVER_H
struct nand_device;
#define __NAND_DEVICE_COMMAND(name) \
COMMAND_HELPER(name, struct nand_device *nand)
/**
* Interface for NAND flash controllers. Not all of these functions are
* required for full functionality of the NAND driver, but better performance
* can be achieved by implementing each function.
*/
struct nand_flash_controller
{
/** Driver name that is used to select it from configuration files. */
const char *name;
const struct command_registration *commands;
/** NAND device command called when driver is instantiated during configuration. */
__NAND_DEVICE_COMMAND((*nand_device_command));
/** Initialize the NAND device. */
int (*init)(struct nand_device *nand);
/** Reset the NAND device. */
int (*reset)(struct nand_device *nand);
/** Issue a command to the NAND device. */
int (*command)(struct nand_device *nand, uint8_t command);
/** Write an address to the NAND device. */
int (*address)(struct nand_device *nand, uint8_t address);
/** Write word of data to the NAND device. */
int (*write_data)(struct nand_device *nand, uint16_t data);
/** Read word of data from the NAND device. */
int (*read_data)(struct nand_device *nand, void *data);
/** Write a block of data to the NAND device. */
int (*write_block_data)(struct nand_device *nand, uint8_t *data, int size);
/** Read a block of data from the NAND device. */
int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size);
/** Write a page to the NAND device. */
int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
/** Read a page from the NAND device. */
int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size);
/** Check if the NAND device is ready for more instructions with timeout. */
int (*nand_ready)(struct nand_device *nand, int timeout);
};
#define NAND_DEVICE_COMMAND_HANDLER(name) static __NAND_DEVICE_COMMAND(name)
/**
* Find a NAND flash controller by name.
* @param name Identifies the NAND controller to find.
* @returns The nand_flash_controller named @c name, or NULL if not found.
*/
struct nand_flash_controller *nand_driver_find_by_name(const char *name);
/// Signature for callback functions passed to nand_driver_walk
typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void*);
/**
* Walk the list of drivers, encapsulating the data structure type.
* Application state/context can be passed through the @c x pointer.
* @param f The callback function to invoke for each function.
* @param x For use as private data storate, passed directly to @c f.
* @returns ERROR_OK if successful, or the non-zero return value of @c f.
* This allows a walker to terminate the loop early.
*/
int nand_driver_walk(nand_driver_walker_t f, void *x);
#endif // FLASH_NAND_DRIVER_H

View File

@@ -1,250 +0,0 @@
/***************************************************************************
* Copyright (C) 2007 by Dominic Rath <Dominic.Rath@gmx.de> *
* Copyright (C) 2002 Thomas Gleixner <tglx@linutronix.de> *
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* Partially based on drivers/mtd/nand_ids.c from Linux. *
* *
* 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 "core.h"
#include "fileio.h"
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 6, 7},
.oobfree = {
{.offset = 8,
. length = 8}}
};
static struct nand_ecclayout nand_oob_64 = {
.eccbytes = 24,
.eccpos = {
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63},
.oobfree = {
{.offset = 2,
.length = 38}}
};
void nand_fileio_init(struct nand_fileio_state *state)
{
memset(state, 0, sizeof(*state));
state->oob_format = NAND_OOB_NONE;
}
int nand_fileio_start(struct command_context *cmd_ctx,
struct nand_device *nand, const char *filename, int filemode,
struct nand_fileio_state *state)
{
if (state->address % nand->page_size)
{
command_print(cmd_ctx, "only page-aligned addresses are supported");
return ERROR_COMMAND_SYNTAX_ERROR;
}
duration_start(&state->bench);
if (NULL != filename)
{
int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY);
if (ERROR_OK != retval)
{
const char *msg = (FILEIO_READ == filemode) ? "read" : "write";
command_print(cmd_ctx, "failed to open '%s' for %s access",
filename, msg);
return retval;
}
state->file_opened = true;
}
if (!(state->oob_format & NAND_OOB_ONLY))
{
state->page_size = nand->page_size;
state->page = malloc(nand->page_size);
}
if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW))
{
if (nand->page_size == 512)
{
state->oob_size = 16;
state->eccpos = nand_oob_16.eccpos;
}
else if (nand->page_size == 2048)
{
state->oob_size = 64;
state->eccpos = nand_oob_64.eccpos;
}
state->oob = malloc(state->oob_size);
}
return ERROR_OK;
}
int nand_fileio_cleanup(struct nand_fileio_state *state)
{
if (state->file_opened)
fileio_close(&state->fileio);
if (state->oob)
{
free(state->oob);
state->oob = NULL;
}
if (state->page)
{
free(state->page);
state->page = NULL;
}
return ERROR_OK;
}
int nand_fileio_finish(struct nand_fileio_state *state)
{
nand_fileio_cleanup(state);
return duration_measure(&state->bench);
}
COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
struct nand_device **dev, enum fileio_access filemode,
bool need_size, bool sw_ecc)
{
nand_fileio_init(state);
unsigned minargs = need_size ? 4 : 3;
if (CMD_ARGC < minargs)
return ERROR_COMMAND_SYNTAX_ERROR;
struct nand_device *nand;
int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
if (ERROR_OK != retval)
return retval;
if (NULL == nand->device)
{
command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]);
return ERROR_OK;
}
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address);
if (need_size)
{
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size);
if (state->size % nand->page_size)
{
command_print(CMD_CTX, "only page-aligned sizes are supported");
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
if (CMD_ARGC > minargs)
{
for (unsigned i = minargs; i < CMD_ARGC; i++)
{
if (!strcmp(CMD_ARGV[i], "oob_raw"))
state->oob_format |= NAND_OOB_RAW;
else if (!strcmp(CMD_ARGV[i], "oob_only"))
state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY;
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc"))
state->oob_format |= NAND_OOB_SW_ECC;
else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw"))
state->oob_format |= NAND_OOB_SW_ECC_KW;
else
{
command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
}
}
retval = nand_fileio_start(CMD_CTX, nand, CMD_ARGV[1], filemode, state);
if (ERROR_OK != retval)
return retval;
if (!need_size)
{
int filesize;
retval = fileio_size(&state->fileio, &filesize);
if (retval != ERROR_OK)
return retval;
state->size = filesize;
}
*dev = nand;
return ERROR_OK;
}
/**
* @returns If no error occurred, returns number of bytes consumed;
* otherwise, returns a negative error code.)
*/
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s)
{
size_t total_read = 0;
size_t one_read;
if (NULL != s->page)
{
fileio_read(&s->fileio, s->page_size, s->page, &one_read);
if (one_read < s->page_size)
memset(s->page + one_read, 0xff, s->page_size - one_read);
total_read += one_read;
}
if (s->oob_format & NAND_OOB_SW_ECC)
{
uint8_t ecc[3];
memset(s->oob, 0xff, s->oob_size);
for (uint32_t i = 0, j = 0; i < s->page_size; i += 256)
{
nand_calculate_ecc(nand, s->page + i, ecc);
s->oob[s->eccpos[j++]] = ecc[0];
s->oob[s->eccpos[j++]] = ecc[1];
s->oob[s->eccpos[j++]] = ecc[2];
}
}
else if (s->oob_format & NAND_OOB_SW_ECC_KW)
{
/*
* In this case eccpos is not used as
* the ECC data is always stored contigously
* at the end of the OOB area. It consists
* of 10 bytes per 512-byte data block.
*/
uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10;
memset(s->oob, 0xff, s->oob_size);
for (uint32_t i = 0; i < s->page_size; i += 512)
{
nand_calculate_ecc_kw(nand, s->page + i, ecc);
ecc += 10;
}
}
else if (NULL != s->oob)
{
fileio_read(&s->fileio, s->oob_size, s->oob, &one_read);
if (one_read < s->oob_size)
memset(s->oob + one_read, 0xff, s->oob_size - one_read);
total_read += one_read;
}
return total_read;
}

View File

@@ -1,57 +0,0 @@
/***************************************************************************
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* 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_NAND_FILEIO_H
#define FLASH_NAND_FILEIO_H
#include <helper/time_support.h>
#include <helper/fileio.h>
struct nand_fileio_state {
uint32_t address;
uint32_t size;
uint8_t *page;
uint32_t page_size;
enum oob_formats oob_format;
uint8_t *oob;
uint32_t oob_size;
const int *eccpos;
bool file_opened;
struct fileio fileio;
struct duration bench;
};
void nand_fileio_init(struct nand_fileio_state *state);
int nand_fileio_start(struct command_context *cmd_ctx,
struct nand_device *nand, const char *filename, int filemode,
struct nand_fileio_state *state);
int nand_fileio_cleanup(struct nand_fileio_state *state);
int nand_fileio_finish(struct nand_fileio_state *state);
COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state,
struct nand_device **dev, enum fileio_access filemode,
bool need_size, bool sw_ecc);
int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s);
#endif // FLASH_NAND_FILEIO_H

View File

@@ -1,39 +0,0 @@
/***************************************************************************
* Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net> *
* *
* 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_NAND_IMP_H
#define FLASH_NAND_IMP_H
#include "core.h"
#include "driver.h"
void nand_device_add(struct nand_device *c);
int nand_write_page(struct nand_device *nand,
uint32_t page, uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size);
int nand_read_page(struct nand_device *nand, uint32_t page,
uint8_t *data, uint32_t data_size,
uint8_t *oob, uint32_t oob_size);
int nand_probe(struct nand_device *nand);
int nand_erase(struct nand_device *nand, int first_block, int last_block);
int nand_build_bbt(struct nand_device *nand, int first, int last);
#endif // FLASH_NAND_IMP_H

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More