initial push
This commit is contained in:
4
m68k/flashlib/.cvsignore
Normal file
4
m68k/flashlib/.cvsignore
Normal file
@@ -0,0 +1,4 @@
|
||||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
libbdmflash.a
|
||||
109
m68k/flashlib/Makefile.am
Normal file
109
m68k/flashlib/Makefile.am
Normal file
@@ -0,0 +1,109 @@
|
||||
##
|
||||
## $Id: Makefile.am,v 1.10 2008/09/09 11:48:50 cjohns Exp $
|
||||
##
|
||||
## This file is part of a free BDM package
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
|
||||
AM_CPPFLAGS = -I$(srcdir)/../libelf/lib -I../libelf/lib \
|
||||
-I$(srcdir)/../driver -I$(srcdir)/../lib \
|
||||
-DPREFIX="$(prefix)"
|
||||
|
||||
lib_LIBRARIES = libbdmflash.a
|
||||
|
||||
include_HEADERS = \
|
||||
bdmfilt.h \
|
||||
bdmflash.h \
|
||||
flash_filter.h \
|
||||
flash29.h \
|
||||
flashcfm.h \
|
||||
flashintelc3.h
|
||||
|
||||
libbdmflash_a_SOURCES = \
|
||||
elf-utils.c \
|
||||
bdmfilt.c \
|
||||
bdmflash.c \
|
||||
flash_filter.c \
|
||||
flash29.c \
|
||||
flashcfm.c \
|
||||
flashintelc3.c
|
||||
|
||||
if BUILD_FLASH_PLUGINS
|
||||
#
|
||||
# Flash Plug-In Source
|
||||
#
|
||||
fpi_source = $(1).c $(1).h
|
||||
|
||||
#
|
||||
# Flash Plug-In Target
|
||||
#
|
||||
fpi_target = $(foreach target, $(2), $(1)-$(target).plugin)
|
||||
|
||||
#
|
||||
# Full instruction set range for the Coldfire plus the CPU32.
|
||||
#
|
||||
fpi_multilib = \
|
||||
cpu32 \
|
||||
5206 \
|
||||
5206e \
|
||||
5307 \
|
||||
5407 \
|
||||
54455 \
|
||||
5475
|
||||
|
||||
#
|
||||
# The list of plugins we have.
|
||||
#
|
||||
fpi_flash29 = flash29
|
||||
fpi_flash29_targets = $(fpi_multilib)
|
||||
fpi_flash29_source = $(call fpi_source, flash29)
|
||||
fpi_flash29_plugins = $(call fpi_target, flash29, $(fpi_flash29_targets))
|
||||
|
||||
fpi_flashcfm = flashcfm
|
||||
fpi_flashcfm_targets = \
|
||||
5206 \
|
||||
5206e \
|
||||
54455
|
||||
fpi_flashcfm_source = $(call fpi_source, flashcfm)
|
||||
fpi_flashcfm_plugins = $(call fpi_target, flashcfm, $(fpi_flashcfm_targets))
|
||||
|
||||
fpi_flashintelc3 = flashintelc3
|
||||
fpi_flashintelc3_targets = $(fpi_multilib)
|
||||
fpi_flashintelc3_source = $(call fpi_source, flashintelc3)
|
||||
fpi_flashintelc3_plugins = $(call fpi_target, flashintelc3, $(fpi_flashintelc3_targets))
|
||||
|
||||
fpi_plugins = \
|
||||
$(fpi_flash29_plugins) \
|
||||
$(fpi_flashcfm_plugins) \
|
||||
$(fpi_flashintelc3_plugins)
|
||||
|
||||
all-local: \
|
||||
$(fpi_plugins)
|
||||
|
||||
$(fpi_flash29_plugins): $(fpi_flash29_source)
|
||||
$(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
$(fpi_flashcfm_plugins): $(fpi_flashcfm_source)
|
||||
$(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
$(fpi_flashintelc3_plugins): $(fpi_flashintelc3_source)
|
||||
$(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
install-data-local: \
|
||||
$(fpi_plugins)
|
||||
test -z "$(prefix)/share/m68k-bdm/plugins" || \
|
||||
mkdir -p "$(prefix)/share/m68k-bdm/plugins"; \
|
||||
for f in $^; do \
|
||||
install -m 644 $$f $(prefix)/share/m68k-bdm/plugins/$$f; \
|
||||
done
|
||||
|
||||
clean-local:
|
||||
rm -f *.plugin
|
||||
|
||||
endif
|
||||
|
||||
EXTRA_DIST = README $(fpi_plugins)
|
||||
575
m68k/flashlib/Makefile.in
Normal file
575
m68k/flashlib/Makefile.in
Normal file
@@ -0,0 +1,575 @@
|
||||
# Makefile.in generated by automake 1.10 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = flashlib
|
||||
DIST_COMMON = README $(include_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
|
||||
libLIBRARIES_INSTALL = $(INSTALL_DATA)
|
||||
LIBRARIES = $(lib_LIBRARIES)
|
||||
ARFLAGS = cru
|
||||
libbdmflash_a_AR = $(AR) $(ARFLAGS)
|
||||
libbdmflash_a_LIBADD =
|
||||
am_libbdmflash_a_OBJECTS = elf-utils.$(OBJEXT) bdmfilt.$(OBJEXT) \
|
||||
bdmflash.$(OBJEXT) flash_filter.$(OBJEXT) flash29.$(OBJEXT) \
|
||||
flashcfm.$(OBJEXT) flashintelc3.$(OBJEXT)
|
||||
libbdmflash_a_OBJECTS = $(am_libbdmflash_a_OBJECTS)
|
||||
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
|
||||
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
SOURCES = $(libbdmflash_a_SOURCES)
|
||||
DIST_SOURCES = $(libbdmflash_a_SOURCES)
|
||||
includeHEADERS_INSTALL = $(INSTALL_HEADER)
|
||||
HEADERS = $(include_HEADERS)
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AR = @AR@
|
||||
AS = @AS@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BDM_SUBDIRS = @BDM_SUBDIRS@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FLASH_PLUGIN_GCC = @FLASH_PLUGIN_GCC@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LEX = @LEX@
|
||||
LEXLIB = @LEXLIB@
|
||||
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBUSB_INCLUDE_DIR = @LIBUSB_INCLUDE_DIR@
|
||||
LIBUSB_LIB_DIR = @LIBUSB_LIB_DIR@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
OBJEXT = @OBJEXT@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
RANLIB = @RANLIB@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
flash_plugin_cc = @flash_plugin_cc@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
subdirs = @subdirs@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
AM_CPPFLAGS = -I$(srcdir)/../libelf/lib -I../libelf/lib \
|
||||
-I$(srcdir)/../driver -I$(srcdir)/../lib \
|
||||
-DPREFIX="$(prefix)"
|
||||
|
||||
lib_LIBRARIES = libbdmflash.a
|
||||
include_HEADERS = \
|
||||
bdmfilt.h \
|
||||
bdmflash.h \
|
||||
flash_filter.h \
|
||||
flash29.h \
|
||||
flashcfm.h \
|
||||
flashintelc3.h
|
||||
|
||||
libbdmflash_a_SOURCES = \
|
||||
elf-utils.c \
|
||||
bdmfilt.c \
|
||||
bdmflash.c \
|
||||
flash_filter.c \
|
||||
flash29.c \
|
||||
flashcfm.c \
|
||||
flashintelc3.c
|
||||
|
||||
|
||||
#
|
||||
# Flash Plug-In Source
|
||||
#
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_source = $(1).c $(1).h
|
||||
|
||||
#
|
||||
# Flash Plug-In Target
|
||||
#
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_target = $(foreach target, $(2), $(1)-$(target).plugin)
|
||||
|
||||
#
|
||||
# Full instruction set range for the Coldfire plus the CPU32.
|
||||
#
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_multilib = \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ cpu32 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5206 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5206e \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5307 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5407 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 54455 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5475
|
||||
|
||||
|
||||
#
|
||||
# The list of plugins we have.
|
||||
#
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flash29 = flash29
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flash29_targets = $(fpi_multilib)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flash29_source = $(call fpi_source, flash29)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flash29_plugins = $(call fpi_target, flash29, $(fpi_flash29_targets))
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashcfm = flashcfm
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashcfm_targets = \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5206 \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 5206e \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ 54455
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashcfm_source = $(call fpi_source, flashcfm)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashcfm_plugins = $(call fpi_target, flashcfm, $(fpi_flashcfm_targets))
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashintelc3 = flashintelc3
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashintelc3_targets = $(fpi_multilib)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashintelc3_source = $(call fpi_source, flashintelc3)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_flashintelc3_plugins = $(call fpi_target, flashintelc3, $(fpi_flashintelc3_targets))
|
||||
@BUILD_FLASH_PLUGINS_TRUE@fpi_plugins = \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(fpi_flash29_plugins) \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(fpi_flashcfm_plugins) \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(fpi_flashintelc3_plugins)
|
||||
|
||||
EXTRA_DIST = README $(fpi_plugins)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o .obj
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
|
||||
&& exit 0; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign flashlib/Makefile'; \
|
||||
cd $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign flashlib/Makefile
|
||||
.PRECIOUS: Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
install-libLIBRARIES: $(lib_LIBRARIES)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
|
||||
@list='$(lib_LIBRARIES)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
|
||||
$(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
|
||||
else :; fi; \
|
||||
done
|
||||
@$(POST_INSTALL)
|
||||
@list='$(lib_LIBRARIES)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
p=$(am__strip_dir) \
|
||||
echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \
|
||||
$(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-libLIBRARIES:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(lib_LIBRARIES)'; for p in $$list; do \
|
||||
p=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \
|
||||
rm -f "$(DESTDIR)$(libdir)/$$p"; \
|
||||
done
|
||||
|
||||
clean-libLIBRARIES:
|
||||
-test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES)
|
||||
libbdmflash.a: $(libbdmflash_a_OBJECTS) $(libbdmflash_a_DEPENDENCIES)
|
||||
-rm -f libbdmflash.a
|
||||
$(libbdmflash_a_AR) libbdmflash.a $(libbdmflash_a_OBJECTS) $(libbdmflash_a_LIBADD)
|
||||
$(RANLIB) libbdmflash.a
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bdmfilt.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bdmflash.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elf-utils.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flash29.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flash_filter.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flashcfm.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flashintelc3.Po@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
|
||||
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
install-includeHEADERS: $(include_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
|
||||
@list='$(include_HEADERS)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
|
||||
$(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-includeHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(include_HEADERS)'; for p in $$list; do \
|
||||
f=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(includedir)/$$f"; \
|
||||
done
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$tags $$unique; \
|
||||
fi
|
||||
ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& cd $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) $$here
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
|
||||
fi; \
|
||||
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
@BUILD_FLASH_PLUGINS_FALSE@all-local:
|
||||
all-am: Makefile $(LIBRARIES) $(HEADERS) all-local
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
`test -z '$(STRIP)' || \
|
||||
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
@BUILD_FLASH_PLUGINS_FALSE@install-data-local:
|
||||
@BUILD_FLASH_PLUGINS_FALSE@clean-local:
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libLIBRARIES clean-local mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-data-local install-includeHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-exec-am: install-libLIBRARIES
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-includeHEADERS uninstall-libLIBRARIES
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \
|
||||
clean-generic clean-libLIBRARIES clean-local ctags distclean \
|
||||
distclean-compile distclean-generic distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-data-local install-dvi \
|
||||
install-dvi-am install-exec install-exec-am install-html \
|
||||
install-html-am install-includeHEADERS install-info \
|
||||
install-info-am install-libLIBRARIES install-man install-pdf \
|
||||
install-pdf-am install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
|
||||
uninstall-am uninstall-includeHEADERS uninstall-libLIBRARIES
|
||||
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@all-local: \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(fpi_plugins)
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@$(fpi_flash29_plugins): $(fpi_flash29_source)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@$(fpi_flashcfm_plugins): $(fpi_flashcfm_source)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@$(fpi_flashintelc3_plugins): $(fpi_flashintelc3_source)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(srcdir)/m68k-bdm-compile-plugin @FLASH_PLUGIN_GCC@ $< $@
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@install-data-local: \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ $(fpi_plugins)
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ test -z "$(prefix)/share/m68k-bdm/plugins" || \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ mkdir -p "$(prefix)/share/m68k-bdm/plugins"; \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ for f in $^; do \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ install -m 644 $$f $(prefix)/share/m68k-bdm/plugins/$$f; \
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ done
|
||||
|
||||
@BUILD_FLASH_PLUGINS_TRUE@clean-local:
|
||||
@BUILD_FLASH_PLUGINS_TRUE@ rm -f *.plugin
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
33
m68k/flashlib/PLUGIN-MAPPING
Normal file
33
m68k/flashlib/PLUGIN-MAPPING
Normal file
@@ -0,0 +1,33 @@
|
||||
2008-08-04 Chris Johns <cjohns@users.sourceforge.net>
|
||||
|
||||
Plug-in Multilib Map
|
||||
=========================
|
||||
|
||||
This table provides the mapping table for the plugins for the processors in the
|
||||
Coldfire family. This mapping is based on the instruction set supported by each
|
||||
processor. A reduction could be made is the FPU was not included. It currently
|
||||
is.
|
||||
|
||||
processor in
|
||||
|
||||
5206:
|
||||
5202, 5204, 5206, 5249, 5250, 5230, 5272
|
||||
|
||||
5206e:
|
||||
5206e, 5207, 5208, 5210a, 5211a, 5211, 5212, 5213, 5214, 5216, 52221,
|
||||
52223, 52230, 52231, 52231, 52232, 52233, 52234, 52235, 5224, 5225, 5232,
|
||||
5233, 5234, 5235, 523x, 5270, 5271, 5274, 5274, 5275, 5280, 5281, 5282,
|
||||
528x
|
||||
|
||||
5307:
|
||||
5307, 5327, 5328, 5329, 532x, 5372, 5373, 537x
|
||||
|
||||
5407:
|
||||
5407
|
||||
|
||||
54455:
|
||||
54450, 54451, 54452, 54453, 54454, 54455
|
||||
|
||||
5475:
|
||||
5470, 5471, 5472, 5473, 5474, 5475, 547x, 5480, 5481, 5482, 5483, 5484,
|
||||
5485, 548x
|
||||
113
m68k/flashlib/README
Normal file
113
m68k/flashlib/README
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
README
|
||||
=========================
|
||||
|
||||
2003-12-28 Josef Wolf (jw@raven.inka.de)
|
||||
2008-06-27 Matthew Riek (matthew.riek@ibiscomputer.com.au)
|
||||
|
||||
Flashlib is invoked using bdmctrl. See the *.test script files in
|
||||
bdm/m68k/utils as examples on how to bootstrap a board and invoke flashlib
|
||||
for flashing. See also bdm/m68k/utils/README.bdmctrl
|
||||
|
||||
Overview
|
||||
=========================
|
||||
|
||||
Following is a rough overview of the flashlib architecture:
|
||||
|
||||
filter:
|
||||
|
||||
The filter is the main interface to the application. The application
|
||||
don't really need to know about the flash driver details. Filter's
|
||||
write_memory() function is the flashing aequivalent of the memcpy()
|
||||
function. write_memory can write to flash or ram, depending on
|
||||
the memory region of the write.
|
||||
|
||||
driver:
|
||||
|
||||
A driver is the implementation of a specific flashing algorithm.
|
||||
examples are flash29, flashcfm and flashintelc3. If the algorithm
|
||||
or chip definition for your flash is not supported, you will need
|
||||
to either add a chip to the chip tables (flash29 and flashintelc3)
|
||||
or you will have to write a new driver.
|
||||
|
||||
chip description:
|
||||
|
||||
The chip description describes details of a flash chip. What
|
||||
information needs to be stored in the description is up to
|
||||
the driver. Most drivers will probably want to store at least
|
||||
chip-type and bus-interface. Some flash drivers (such as flashcfm)
|
||||
don't need a chip description table. Instead, you can configure
|
||||
the required bits such as flash register offsets using flash_set_var.
|
||||
|
||||
flash region:
|
||||
|
||||
A flash region describes specific flash chips (depending on the
|
||||
bus interface). The most important information herein is the
|
||||
base-address, the length, the driver and the chip description.
|
||||
|
||||
plugin:
|
||||
|
||||
A driver that can be downloaded and executed on the target.
|
||||
|
||||
Note that you don't _need_ plugins. You can use host only mode,
|
||||
which is very slow, plugins just make flashing much much faster.
|
||||
|
||||
A plugin is simply compiling just the driver '.c' file for your
|
||||
target. For example, If you have a 29 series flash chip on your
|
||||
board, you would compile flash29.c using your cross compiler
|
||||
toolchain. Only a few header files are needed (the associated
|
||||
header file flash29.h, flash_filter.h and stdint.h. note that
|
||||
when you compile the drivers as a plugin, you must define
|
||||
HOST_FLASHING as 0. (-DHOST_FLASHING=0 for gcc). You need to
|
||||
compile with -mpcrel such that the code is relocatable. I have
|
||||
compiled all current drivers successfully using a m68k-elf gnu
|
||||
toolchain (version 4.3.0), and with the m68k-rtems4.9 toolchain.
|
||||
|
||||
m68k-elf-gcc -DHOST_FLASHING=0 -O2 -Wall -fomit-frame-pointer \
|
||||
-mpcrel -m<CPU> -Wcast-align -Wstrict-prototypes \
|
||||
-Wmissing-prototypes -c -o <driver>.plugin <driver>.c
|
||||
|
||||
where <driver> is one of flashcfm, flash29 or flashintelc3.
|
||||
and <CPU> is your 68k arch, such as 5200, 5307, 528x etc.
|
||||
|
||||
There is a script provided which compiles the plugins which
|
||||
takes 2 args, your compiler and your target. eg:
|
||||
>./compile_plugins m68k-elf-gcc 5200
|
||||
or
|
||||
>./compile_plugins m68k-rtems4.9-gcc 5200
|
||||
|
||||
you will need to copy the plugins to the working folder you
|
||||
invoke the bdmctrl scripts from.
|
||||
|
||||
host-only mode:
|
||||
|
||||
All operations are piped through the BDM interface. This is
|
||||
extremely slow but very useful for bootstrapping/debugging.
|
||||
Spend the time to compile plugins for your target
|
||||
|
||||
host-assisted mode:
|
||||
|
||||
Host downloads plugin. The actual flashing operation is executed
|
||||
by the plugin. This is the preferred operation mode for flashing
|
||||
under host-control.
|
||||
|
||||
target-only mode:
|
||||
|
||||
This mode is for operation without a host. compile filter and
|
||||
drivers for the target with HOST_FLASHING = 0. This could be used
|
||||
for boot loaders etc. This option has not been completed, there
|
||||
are a few FIXME's noted in the flash_filter.c where bit's for
|
||||
target-only mode remain unimplemented. uses of malloc, free,
|
||||
strdup may need to be provided with hooks in this mode.
|
||||
|
||||
How to write a new driver
|
||||
=========================
|
||||
|
||||
Best is to start with a copy of flash29.[ch]. You should rename the
|
||||
init_flash29() function and add the new function to the algorithm[] array
|
||||
in flash_filter.c. Next is to give a new value to the driver_magic string.
|
||||
This name should be unique because it is used to identify the driver
|
||||
that belongs to a loaded plugin. Change the download_struct() function to
|
||||
download the chip description structure of the new driver properly to the
|
||||
target. Make sure byte orderings and alignment is not messed up while
|
||||
downloading.
|
||||
58
m68k/flashlib/bdmfilt.c
Normal file
58
m68k/flashlib/bdmfilt.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <bdmfilt.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
int bdmlib_load_use_lma=0;
|
||||
|
||||
bdmlib_bfilt_t * bdmlib_bfilt=NULL;
|
||||
|
||||
int
|
||||
bdmfilt_wrb_filt(bdmlib_bfilt_t * filt, uint32_t in_adr,
|
||||
unsigned int size, unsigned char * bl_ptr)
|
||||
{
|
||||
int ret, part_ret;
|
||||
unsigned int part_size;
|
||||
if (!size) return 0;
|
||||
|
||||
while (filt) {
|
||||
if((in_adr<=filt->end_adr)&&
|
||||
(in_adr+size-1>=filt->begin_adr)) {
|
||||
ret = 0;
|
||||
if(in_adr<filt->begin_adr) {
|
||||
part_size=filt->begin_adr-in_adr;
|
||||
part_ret=bdmlib_wrb_filt(filt->next,in_adr,part_size,bl_ptr);
|
||||
ret+=part_ret;
|
||||
if(part_ret!=part_size) return ret;
|
||||
in_adr+=part_size;
|
||||
bl_ptr+=part_size;
|
||||
size-=part_size;
|
||||
}
|
||||
part_size=filt->end_adr-in_adr+1;
|
||||
if (part_size>=size) {
|
||||
part_size=size;
|
||||
size=0;
|
||||
} else size-=part_size;
|
||||
part_ret=filt->wrb_filt(filt,in_adr,part_size,bl_ptr);
|
||||
ret+=part_ret;
|
||||
if(part_ret!=part_size) {
|
||||
dbprintf("write error on filt write, address 0x%lx size %d acknowledged %d errno %d\n",
|
||||
(long)in_adr, part_size, part_ret, errno);
|
||||
return ret;
|
||||
}
|
||||
in_adr+=part_size;
|
||||
bl_ptr+=part_size;
|
||||
if(!size) return ret;
|
||||
ret+=bdmlib_wrb_filt(filt->next,in_adr,size,bl_ptr);
|
||||
return ret;
|
||||
}
|
||||
filt=filt->next;
|
||||
}
|
||||
/* regular memory block write */
|
||||
if ((ret = bdmlib_write_block(in_adr, size, bl_ptr)) != size) {
|
||||
dbprintf("write error on block write, written %d acknowledged %d errno %d\n",
|
||||
size, ret, errno);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
36
m68k/flashlib/bdmfilt.h
Normal file
36
m68k/flashlib/bdmfilt.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* $Id: bdmfilt.h,v 1.4 2008/06/16 00:01:21 cjohns Exp $
|
||||
*/
|
||||
|
||||
#ifndef BDMFILT_H
|
||||
#define BDMFILT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* support of filtered write for flash programming */
|
||||
|
||||
typedef struct bdmlib_bfilt{
|
||||
struct bdmlib_bfilt *next;
|
||||
uint32_t begin_adr;
|
||||
uint32_t end_adr;
|
||||
int filt_id;
|
||||
unsigned int flags;
|
||||
int (*wrb_filt)(struct bdmlib_bfilt *, uint32_t , unsigned int, unsigned char * );
|
||||
void *info;
|
||||
void *state;
|
||||
}bdmlib_bfilt_t;
|
||||
|
||||
#define BDMLIB_FILT_ERROR 0x08
|
||||
#define BDMLIB_FILT_ERASED 0x10
|
||||
#define BDMLIB_FILT_AUTO 0x20
|
||||
#define BDMLIB_FILT_FLASH 0x40
|
||||
|
||||
int bdmlib_load_use_lma; /* use LMA instead of VMA for load */
|
||||
bdmlib_bfilt_t * bdmlib_bfilt;
|
||||
|
||||
int
|
||||
bdmlib_wrb_filt(bdmlib_bfilt_t * bdmlib_bfilt, uint32_t in_adr,
|
||||
unsigned int size, unsigned char * bl_ptr);
|
||||
|
||||
#endif /* BDMFILT_H */
|
||||
989
m68k/flashlib/bdmflash.c
Normal file
989
m68k/flashlib/bdmflash.c
Normal file
@@ -0,0 +1,989 @@
|
||||
/*******************************************************************
|
||||
Flash programming algorithms for use with BDM flash utility
|
||||
|
||||
bdmflash.c - test driver implementation
|
||||
|
||||
(C) Copyright 2000-2003 by Pavel Pisa <pisa@waltz.felk.cvut.cz>
|
||||
|
||||
This souce is distributed under the Gnu General Public Licence.
|
||||
See file COPYING for details.
|
||||
|
||||
Source could be used under any other license for embeded systems,
|
||||
but in such case enhancements must be sent to original author.
|
||||
If some of contributors does not agree with above two lines,
|
||||
he can delete them and only GPL will apply.
|
||||
*******************************************************************/
|
||||
/*
|
||||
Revision history
|
||||
|
||||
2001-01-16 Added experimental support of single 8 bit flash memory
|
||||
based on Avi Cohen Stuart <astuart@baan.nl> changes
|
||||
|
||||
2001-07-10 Added support for amd_29f010 with x8x2 configuration
|
||||
based on John S. Gwynne <jsg@jsgpc.mrcday.com> changes
|
||||
Trying to solve x8x2 race condition with shortest
|
||||
possible code - needs more tests
|
||||
|
||||
2001-08-30 Added alg-info for at_49f040 with x8x2 configuration
|
||||
x8x2 configuration needs more testing, may be broken
|
||||
|
||||
2003-05-19 Added initial support for x32 memory configurations.
|
||||
The x16x2 and x8x4 should work as well. Changes were
|
||||
motivated by Andrei Smirnov <andrei.s@myrealbox.com>
|
||||
code, but his small update results in deeper code redesign.
|
||||
This could enable to support page writes for modern versions
|
||||
of FLASH memories in future.
|
||||
|
||||
2003-11-09 The first attempt to port into Chris's branch
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <BDMlib.h>
|
||||
#include "bdmfilt.h"
|
||||
#include "bdmflash.h"
|
||||
|
||||
/* predefined flash algorithms metods */
|
||||
|
||||
int bdmflash_check_id_x32(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2]);
|
||||
int bdmflash_prog_x32(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count);
|
||||
int bdmflash_erase_x32(const flash_alg_info_t *alg, uint32_t addr, long size);
|
||||
|
||||
int bdmflash_check_id_x16(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2]);
|
||||
int bdmflash_prog_x16(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count);
|
||||
int bdmflash_erase_x16(const flash_alg_info_t *alg, uint32_t addr, long size);
|
||||
|
||||
int bdmflash_check_id_x8(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2]);
|
||||
int bdmflash_prog_x8(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count);
|
||||
int bdmflash_erase_x8(const flash_alg_info_t *alg, uint32_t addr, long size);
|
||||
|
||||
/* predefined flash types */
|
||||
|
||||
flash_alg_info_t amd_29f800_x16={
|
||||
check_id: bdmflash_check_id_x16,
|
||||
prog: bdmflash_prog_x16,
|
||||
erase: bdmflash_erase_x16,
|
||||
addr_mask: 0xfffff, /* 1MB */
|
||||
reg1_addr: 0x555*2,
|
||||
reg2_addr: 0x2aa*2,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x16,
|
||||
cmd_unlock1:0xaa, /* reg1 */
|
||||
cmd_unlock2:0x55, /* reg2 */
|
||||
cmd_rdid: 0x90, /* reg1 */
|
||||
cmd_prog: 0xa0, /* reg1 */
|
||||
cmd_erase: 0x80, /* reg1 */
|
||||
cmd_reset: 0xf0, /* any */
|
||||
erase_all: 0x10, /* reg1 */
|
||||
erase_sec: 0x30, /* sector */
|
||||
fault_bit: 0x20,
|
||||
manid: 1,
|
||||
devid: 0x2258,
|
||||
alg_name: "amd29f800"
|
||||
};
|
||||
|
||||
flash_alg_info_t amd_29f400_x16={
|
||||
check_id: bdmflash_check_id_x16,
|
||||
prog: bdmflash_prog_x16,
|
||||
erase: bdmflash_erase_x16,
|
||||
addr_mask: 0x7ffff, /* 0.5MB */
|
||||
reg1_addr: 0x555*2,
|
||||
reg2_addr: 0x2aa*2,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x16,
|
||||
cmd_unlock1:0xaa, /* reg1 */
|
||||
cmd_unlock2:0x55, /* reg2 */
|
||||
cmd_rdid: 0x90, /* reg1 */
|
||||
cmd_prog: 0xa0, /* reg1 */
|
||||
cmd_erase: 0x80, /* reg1 */
|
||||
cmd_reset: 0xf0, /* any */
|
||||
erase_all: 0x10, /* reg1 */
|
||||
erase_sec: 0x30, /* sector */
|
||||
fault_bit: 0x20,
|
||||
manid: 1,
|
||||
devid: 0x22ab,
|
||||
alg_name: "amd29f400"
|
||||
};
|
||||
|
||||
flash_alg_info_t amd_29f040_x8={
|
||||
check_id: bdmflash_check_id_x8,
|
||||
prog: bdmflash_prog_x8,
|
||||
erase: bdmflash_erase_x8,
|
||||
addr_mask: 0x7ffff, /* 0.5MB */
|
||||
reg1_addr: 0x555,
|
||||
reg2_addr: 0x2aa,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x8,
|
||||
cmd_unlock1:0xaa, /* reg1 */
|
||||
cmd_unlock2:0x55, /* reg2 */
|
||||
cmd_rdid: 0x90, /* reg1 */
|
||||
cmd_prog: 0xa0, /* reg1 */
|
||||
cmd_erase: 0x80, /* reg1 */
|
||||
cmd_reset: 0xf0, /* any */
|
||||
erase_all: 0x10, /* reg1 */
|
||||
erase_sec: 0x30, /* sector */
|
||||
fault_bit: 0x20,
|
||||
manid: 1,
|
||||
devid: 0xa4,
|
||||
alg_name: "amd29f040"
|
||||
};
|
||||
|
||||
flash_alg_info_t amd_29f010_x8x2={
|
||||
check_id: bdmflash_check_id_x16,
|
||||
prog: bdmflash_prog_x16,
|
||||
erase: bdmflash_erase_x16,
|
||||
addr_mask: 0x3ffff, /* 2x128kB = 256kB */
|
||||
reg1_addr: 0x5555*2,
|
||||
reg2_addr: 0x2aaa*2,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x8x2,
|
||||
cmd_unlock1:0xaaaa, /* reg1 */
|
||||
cmd_unlock2:0x5555, /* reg2 */
|
||||
cmd_rdid: 0x9090, /* reg1 */
|
||||
cmd_prog: 0xa0a0, /* reg1 */
|
||||
cmd_erase: 0x8080, /* reg1 */
|
||||
cmd_reset: 0xf0f0, /* any */
|
||||
erase_all: 0x1010, /* reg1 */
|
||||
erase_sec: 0x3030, /* sector */
|
||||
fault_bit: 0x2020,
|
||||
manid: 0x0101,
|
||||
devid: 0x2020,
|
||||
alg_name: "amd29f010x2"
|
||||
};
|
||||
|
||||
flash_alg_info_t at_49f040_x8x2={
|
||||
check_id: bdmflash_check_id_x16,
|
||||
prog: bdmflash_prog_x16,
|
||||
erase: bdmflash_erase_x16,
|
||||
addr_mask: 0xfffff, /* 2x0.5MB = 1MB */
|
||||
reg1_addr: 0x5555*2,
|
||||
reg2_addr: 0x2aaa*2,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x8x2,
|
||||
cmd_unlock1:0xaaaa, /* reg1 */
|
||||
cmd_unlock2:0x5555, /* reg2 */
|
||||
cmd_rdid: 0x9090, /* reg1 */
|
||||
cmd_prog: 0xa0a0, /* reg1 */
|
||||
cmd_erase: 0x8080, /* reg1 */
|
||||
cmd_reset: 0xf0f0, /* any */
|
||||
erase_all: 0x1010, /* reg1 */
|
||||
erase_sec: 0x3030, /* sector */
|
||||
fault_bit: 0x2020,
|
||||
manid: 0x1F1F,
|
||||
devid: 0x1313,
|
||||
alg_name: "at49f040x2"
|
||||
};
|
||||
|
||||
#ifdef WITH_TARGET_BUS32
|
||||
|
||||
flash_alg_info_t amd_29f080_x8x4={
|
||||
check_id: bdmflash_check_id_x32,
|
||||
prog: bdmflash_prog_x32,
|
||||
erase: bdmflash_erase_x32,
|
||||
addr_mask: 0x3fffff, /* 4x1MB */
|
||||
reg1_addr: 0x555*4,
|
||||
reg2_addr: 0x2aa*4,
|
||||
sec_size: 0x10000,
|
||||
width: FLASH_ALG_BITS_x8x4,
|
||||
cmd_unlock1:0xaaaaaaaa, /* reg1 */
|
||||
cmd_unlock2:0x55555555, /* reg2 */
|
||||
cmd_rdid: 0x90909090, /* reg1 */
|
||||
cmd_prog: 0xa0a0a0a0, /* reg1 */
|
||||
cmd_erase: 0x80808080, /* reg1 */
|
||||
cmd_reset: 0xf0f0f0f0, /* any */
|
||||
erase_all: 0x10101010, /* reg1 */
|
||||
erase_sec: 0x30303030, /* sector */
|
||||
fault_bit: 0x20202020,
|
||||
manid: 0x01010101,
|
||||
devid: 0xd5d5d5d5,
|
||||
alg_name: "amd29f080x4"
|
||||
};
|
||||
|
||||
#endif /* WITH_TARGET_BUS32 */
|
||||
|
||||
/* please keep sorted by flash sizes, smallest first */
|
||||
flash_alg_info_t *flash_alg_infos_def[]={
|
||||
&amd_29f010_x8x2, /* 256 kB */
|
||||
&amd_29f040_x8, /* 512 kB */
|
||||
&amd_29f400_x16, /* 512 kB */
|
||||
&amd_29f800_x16, /* 1 MB */
|
||||
&at_49f040_x8x2, /* 1 MB */
|
||||
#ifdef WITH_TARGET_BUS32
|
||||
&amd_29f080_x8x4, /* 4 MB */
|
||||
#endif /* WITH_TARGET_BUS32 */
|
||||
NULL
|
||||
};
|
||||
|
||||
flash_alg_info_t **flash_alg_infos=flash_alg_infos_def;
|
||||
|
||||
#if 0
|
||||
#define FLASH_WR32(adr,val) (*(volatile uint32_t*)(adr)=(val))
|
||||
#define FLASH_RD32(adr) (*(volatile uint32_t*)(adr))
|
||||
#define FLASH_WR16(adr,val) (*(volatile uint16_t*)(adr)=(val))
|
||||
#define FLASH_RD16(adr) (*(volatile uint16_t*)(adr))
|
||||
#define FLASH_WR8(adr,val) (*(volatile unsigned int8_t*)(adr)=(val))
|
||||
#define FLASH_RD8(adr) (*(volatile unsigned int8_t*)(adr))
|
||||
#elif 0
|
||||
#define FLASH_WR32(adr,val) \
|
||||
({ \
|
||||
if(bdmlib_write_var(adr,BDM_SIZE_LONG,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD32(adr) \
|
||||
({ uint32_t temp_val; \
|
||||
if(bdmlib_read_var(adr,BDM_SIZE_LONG,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#define FLASH_WR16(adr,val) \
|
||||
({ \
|
||||
if(bdmlib_write_var(adr,BDM_SIZE_WORD,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD16(adr) \
|
||||
({ uint16_t temp_val; \
|
||||
if(bdmlib_read_var(adr,BDM_SIZE_WORD,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#define FLASH_WR8(adr,val) \
|
||||
({ \
|
||||
if(bdmlib_write_var(adr,BDM_SIZE_BYTE,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD8(adr) \
|
||||
({ unsigned int8_t temp_val; \
|
||||
if(bdmlib_read_var(adr,BDM_SIZE_BYTE,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#else
|
||||
#define FLASH_WR32(adr,val) \
|
||||
({ \
|
||||
if(bdmWriteLongWord((unsigned long)adr,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD32(adr) \
|
||||
({ unsigned long temp_val; \
|
||||
if(bdmReadLongWord((unsigned long)adr,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#define FLASH_WR16(adr,val) \
|
||||
({ \
|
||||
if(bdmWriteWord((unsigned long)adr,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD16(adr) \
|
||||
({ unsigned short temp_val; \
|
||||
if(bdmReadWord((unsigned long)adr,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#define FLASH_WR8(adr,val) \
|
||||
({ \
|
||||
if(bdmWriteByte((unsigned long)adr,val)<0) \
|
||||
goto mem_op_error; \
|
||||
val; \
|
||||
})
|
||||
#define FLASH_RD8(adr) \
|
||||
({ unsigned char temp_val; \
|
||||
if(bdmReadByte((unsigned long)adr,&temp_val)<0) \
|
||||
goto mem_op_error; \
|
||||
temp_val; \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static
|
||||
int bdmflash_prepval_x16(uint16_t *pval, uint32_t addr, const void *data, long count)
|
||||
{
|
||||
if(!((long)addr&1) && (count>=2)){
|
||||
*pval=(((unsigned char*)data)[0]<<8)|(((unsigned char*)data)[1]);
|
||||
return 2;
|
||||
}
|
||||
if(!count) return count;
|
||||
if(!((long)addr&1)){
|
||||
*pval=(((unsigned char*)data)[0]<<8) | FLASH_RD8(addr+1);
|
||||
}else{
|
||||
*pval=(FLASH_RD8(addr-1)<<8) | (((unsigned char*)data)[0]);
|
||||
}
|
||||
return 1;
|
||||
|
||||
mem_op_error:
|
||||
return -4;
|
||||
}
|
||||
|
||||
#ifdef WITH_TARGET_BUS32
|
||||
static
|
||||
int bdmflash_prepval_x32(uint32_t *pval, uint32_t addr, const void *data, long count)
|
||||
{
|
||||
int offs=(long)addr&3;
|
||||
int rest=4-offs;
|
||||
uint32_t val=0;
|
||||
if(!offs && (count>=4)){
|
||||
*pval=((uint32_t)((unsigned char*)data)[0]<<24)|((uint32_t)((unsigned char*)data)[1]<<16)|
|
||||
(((unsigned char*)data)[2]<<8)|(((unsigned char*)data)[3]);
|
||||
return 4;
|
||||
}
|
||||
if(!count) return count;
|
||||
if(count>rest) count=rest;
|
||||
while(offs){
|
||||
val<<=8;
|
||||
val|=FLASH_RD8(addr-offs);
|
||||
offs--;
|
||||
}
|
||||
while(offs<count){
|
||||
val<<=8;
|
||||
val|=((unsigned char*)data)[offs];
|
||||
offs++;
|
||||
}
|
||||
while(offs<rest){
|
||||
val<<=8;
|
||||
val|=FLASH_RD8(addr+offs);
|
||||
offs++;
|
||||
}
|
||||
*pval=val;
|
||||
return count;
|
||||
|
||||
mem_op_error:
|
||||
return -4;
|
||||
}
|
||||
#endif /* WITH_TARGET_BUS32 */
|
||||
|
||||
/*******************************************************************/
|
||||
/* routines for 16 bit wide Intel or AMD flash or two interleaved
|
||||
8 bit flashes */
|
||||
|
||||
int bdmflash_check_id_x16(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2])
|
||||
{
|
||||
int ret=0;
|
||||
uint16_t devid, manid;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR16(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read manufacturer ID */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
manid=FLASH_RD16(a+0);
|
||||
if(manid!=alg->manid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR16(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read device ID */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
devid=FLASH_RD16(a+2);
|
||||
if(devid!=alg->devid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
if(retid)
|
||||
{retid[0]=manid;retid[1]=devid;};
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
int bdmflash_prog_x16(const flash_alg_info_t *alg, uint32_t addr,
|
||||
const void *data, long count)
|
||||
{
|
||||
int ret;
|
||||
uint16_t old,new,fault,val;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
ret=bdmflash_prepval_x16(&val,addr,data,count);
|
||||
if(ret<=0)
|
||||
return ret;
|
||||
addr=addr&~1l;
|
||||
/* check if FLASH needs programming */
|
||||
if(1){
|
||||
old=FLASH_RD16(addr);
|
||||
if(old==val) return ret;
|
||||
}
|
||||
/* security sequence */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR16(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* program command */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_prog);
|
||||
FLASH_WR16(addr,val);
|
||||
/* wait for result */
|
||||
old=FLASH_RD16(addr);
|
||||
while((new=FLASH_RD16(addr))!=old){
|
||||
if((fault=old&new&alg->fault_bit)){
|
||||
old=new;
|
||||
/* check for some false fault at finish or race of x8x2 */
|
||||
if(!(old^=(new=FLASH_RD16(addr)))) break; /* finished now */
|
||||
else{
|
||||
/* one chip of x8x2 configuration can finish earlier */
|
||||
if(!(old&0x00ff)||(fault&0x00ff))
|
||||
if(!(old&0xff00)||(fault&0xff00))
|
||||
{ret=-2;break;}
|
||||
}
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
if((FLASH_RD16(addr)!=val) && (ret>=0)) ret=-3;
|
||||
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
int bdmflash_erase_x16(const flash_alg_info_t *alg, uint32_t addr, long size)
|
||||
{
|
||||
uint16_t old,new,fault;
|
||||
int ret=0;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR16(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* erase command */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_erase);
|
||||
/* security sequence */
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR16(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* select erase range */
|
||||
a=addr;
|
||||
if(size==0)
|
||||
FLASH_WR16(a+alg->reg1_addr,alg->erase_all);
|
||||
else{
|
||||
FLASH_WR16(addr,alg->erase_sec);
|
||||
}
|
||||
/* wait for result */
|
||||
old=FLASH_RD16(addr);
|
||||
while((new=FLASH_RD16(addr))!=old){
|
||||
if((fault=old&new&alg->fault_bit)){
|
||||
old=new;
|
||||
/* check for some false fault at finish or race of x8x2 */
|
||||
if(!(old^=(new=FLASH_RD16(addr)))) break; /* finished now */
|
||||
else{
|
||||
/* one chip of x8x2 configuration can finish earlier */
|
||||
if(!(old&0x00ff)||(fault&0x00ff))
|
||||
if(!(old&0xff00)||(fault&0xff00))
|
||||
{ret=-2;break;}
|
||||
}
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR16(a,alg->cmd_reset);
|
||||
if(FLASH_RD16(addr)!=0xffff) ret--;
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* routines for single 8 bit wide Intel or AMD flash */
|
||||
|
||||
int bdmflash_check_id_x8(const flash_alg_info_t *alg, uint32_t addr,
|
||||
flash_d_t retid[2])
|
||||
{
|
||||
int ret=0;
|
||||
uint16_t devid, manid;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR8(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read manufacturer ID */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
manid=FLASH_RD8(a+0);
|
||||
if(manid!=alg->manid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR8(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read device ID */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
devid=FLASH_RD8(a+1);
|
||||
if(devid!=alg->devid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
if(retid)
|
||||
{retid[0]=manid;retid[1]=devid;};
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
int bdmflash_prog_x8(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count)
|
||||
{
|
||||
int ret=1;
|
||||
unsigned char old,new,val;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
val=*(unsigned char*)data;
|
||||
/* check if FLASH needs programming */
|
||||
if(1){
|
||||
old=FLASH_RD8(addr);
|
||||
if(old==val) return ret;
|
||||
}
|
||||
/* security sequence */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR8(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* program command */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_prog);
|
||||
FLASH_WR8(addr,val);
|
||||
/* wait for result */
|
||||
old=FLASH_RD8(addr);
|
||||
while((new=FLASH_RD8(addr))!=old){
|
||||
if((old&alg->fault_bit)&&(new&alg->fault_bit)){
|
||||
if((FLASH_RD8(addr))!=new) ret=-2;
|
||||
break;
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
if((FLASH_RD8(addr)!=val) && (ret>=0)) ret=-3;
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
int bdmflash_erase_x8(const flash_alg_info_t *alg, uint32_t addr, long size)
|
||||
{
|
||||
unsigned char old,new;
|
||||
int ret=0;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR8(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* erase command */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_erase);
|
||||
/* security sequence */
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR8(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* select erase range */
|
||||
a=addr;
|
||||
if(size==0)
|
||||
FLASH_WR8(a+alg->reg1_addr,alg->erase_all);
|
||||
else{
|
||||
FLASH_WR8(addr,alg->erase_sec);
|
||||
}
|
||||
old=FLASH_RD8(addr);
|
||||
while((new=FLASH_RD8(addr))!=old){
|
||||
if((old&alg->fault_bit)&&(new&alg->fault_bit)){
|
||||
if((FLASH_RD8(addr))!=new) ret=-2;
|
||||
break;
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR8(a,alg->cmd_reset);
|
||||
if(FLASH_RD16(addr)!=0xffff) ret--;
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/* routines for two/four interleaved 16/8 bit wide Intel or AMD flashes */
|
||||
|
||||
#ifdef WITH_TARGET_BUS32
|
||||
|
||||
int bdmflash_check_id_x32(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2])
|
||||
{
|
||||
int ret=0;
|
||||
uint32_t devid, manid;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR32(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read manufacturer ID */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
/* bank slecets swapped as i suspect (360DK only) !!!!!! */
|
||||
/*manid=FLASH_RD32(a+0xc); */
|
||||
manid=FLASH_RD32(a+0);
|
||||
if(manid!=alg->manid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR32(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* read device ID */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_rdid);
|
||||
devid=FLASH_RD32(a+4);
|
||||
if(devid!=alg->devid) ret=-1;
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
if(retid)
|
||||
{retid[0]=manid;retid[1]=devid;};
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
int bdmflash_prog_x32(const flash_alg_info_t *alg, uint32_t addr,
|
||||
const void *data, long count)
|
||||
{
|
||||
int ret=4;
|
||||
uint32_t old,new,fault,val;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
ret=bdmflash_prepval_x32(&val,addr,data,count);
|
||||
if(ret<=0)
|
||||
return ret;
|
||||
addr=addr&~3l;
|
||||
/* check if FLASH needs programming */
|
||||
if(1){
|
||||
old=FLASH_RD32(addr);
|
||||
if(old==val) return ret;
|
||||
}
|
||||
/* security sequence */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR32(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* program command */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_prog);
|
||||
FLASH_WR32(addr,val);
|
||||
/* wait for result */
|
||||
old=FLASH_RD32(addr);
|
||||
while((new=FLASH_RD32(addr))!=old){
|
||||
if((fault=old&new&alg->fault_bit)){
|
||||
old=new;
|
||||
/* check for some false fault at finish or race of x8x2 */
|
||||
if(!(old^=(new=FLASH_RD32(addr)))) break; /* finished now */
|
||||
else{
|
||||
/* one chip of x16x2 or x8x4 configuration can finish earlier */
|
||||
if(!(old&0x000000ff)||(fault&0x000000ff))
|
||||
if(!(old&0x0000ff00)||(fault&0x0000ff00))
|
||||
if(!(old&0x00ff0000)||(fault&0x00ff0000))
|
||||
if(!(old&0xff000000)||(fault&0xff000000))
|
||||
{ret=-2;break;}
|
||||
}
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
if((FLASH_RD32(addr)!=val) && (ret>=0)) ret=-3;
|
||||
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
|
||||
int bdmflash_erase_x32(const flash_alg_info_t *alg, uint32_t addr, long size)
|
||||
{
|
||||
uint32_t old,new,fault;
|
||||
int ret=0;
|
||||
uint32_t a=addr&~alg->addr_mask;
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
/* security sequence */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR32(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* erase command */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_erase);
|
||||
/* security sequence */
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->cmd_unlock1);
|
||||
if(alg->cmd_unlock2)
|
||||
FLASH_WR32(a+alg->reg2_addr,alg->cmd_unlock2);
|
||||
/* select erase range */
|
||||
a=addr;
|
||||
if(size==0)
|
||||
FLASH_WR32(a+alg->reg1_addr,alg->erase_all);
|
||||
else{
|
||||
FLASH_WR32(addr,alg->erase_sec);
|
||||
}
|
||||
/* wait for result */
|
||||
old=FLASH_RD32(addr);
|
||||
while((new=FLASH_RD32(addr))!=old){
|
||||
if((fault=old&new&alg->fault_bit)){
|
||||
old=new;
|
||||
/* check for some false fault at finish or race of x16x2 or x8x4 */
|
||||
if(!(old^=(new=FLASH_RD32(addr)))) break; /* finished now */
|
||||
else{
|
||||
/* one chip of x16x2 or x8x4 configuration can finish earlier */
|
||||
if(!(old&0x000000ff)||(fault&0x000000ff))
|
||||
if(!(old&0x0000ff00)||(fault&0x0000ff00))
|
||||
if(!(old&0x00ff0000)||(fault&0x00ff0000))
|
||||
if(!(old&0xff000000)||(fault&0xff000000))
|
||||
{ret=-2;break;}
|
||||
}
|
||||
}
|
||||
old=new;
|
||||
}
|
||||
/* reset */
|
||||
FLASH_WR32(a,alg->cmd_reset);
|
||||
if(FLASH_RD32(addr)!=0xffffffff) ret--;
|
||||
return ret;
|
||||
|
||||
mem_op_error:
|
||||
return -5;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_TARGET_BUS32 */
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
/* flash type independent check_id */
|
||||
int bdmflash_check_id(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2])
|
||||
{
|
||||
if(alg->check_id)
|
||||
return alg->check_id(alg, addr, retid);
|
||||
else
|
||||
return -10; /* we really need to define error constants in future */
|
||||
}
|
||||
|
||||
/* flash type independent program one location */
|
||||
int bdmflash_prog(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count)
|
||||
{
|
||||
if(alg->prog)
|
||||
return alg->prog(alg,addr,data,count);
|
||||
else
|
||||
return -10;
|
||||
}
|
||||
|
||||
/* flash type independent erase region */
|
||||
int bdmflash_erase(const flash_alg_info_t *alg, uint32_t addr, long size)
|
||||
{
|
||||
if(alg->erase)
|
||||
return alg->erase(alg,addr,size);
|
||||
else
|
||||
return -10;
|
||||
}
|
||||
|
||||
const flash_alg_info_t *
|
||||
bdmflash_alg_from_id(flash_d_t id[2])
|
||||
{
|
||||
int i;
|
||||
const flash_alg_info_t *alg;
|
||||
for(i=0;(alg=flash_alg_infos_def[i])!=NULL;i++)
|
||||
if((alg->manid==id[0])&&(alg->devid==id[0]))
|
||||
return alg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const flash_alg_info_t *
|
||||
bdmflash_alg_probe(uint32_t flash_adr)
|
||||
{
|
||||
int i;
|
||||
const flash_alg_info_t *alg,*alg1;
|
||||
flash_d_t testid[2];
|
||||
for(i=0;(alg=flash_alg_infos_def[i])!=NULL;i++){
|
||||
if(bdmflash_check_id(alg,flash_adr,testid)>=0)
|
||||
return alg;
|
||||
alg1=bdmflash_alg_from_id(testid);
|
||||
if(alg1!=NULL)
|
||||
if(bdmflash_check_id(alg1,flash_adr,testid)>=0)
|
||||
return alg1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
bdmflash_wrb_filt(bdmlib_bfilt_t * filt, uint32_t in_adr,
|
||||
unsigned int size, unsigned char * bl_ptr)
|
||||
{
|
||||
int offs=0,res;
|
||||
flash_d_t val;
|
||||
const flash_alg_info_t *alg=(flash_alg_info_t*)filt->info;
|
||||
|
||||
#if 0
|
||||
if(alg->width!=FLASH_ALG_BITS_x8) {
|
||||
/* 16 bit wide flash write path */
|
||||
if((u_long)in_adr&1) {
|
||||
in_adr-=1;
|
||||
val=(FLASH_RD16(in_adr)&0xff00)|bl_ptr[offs];
|
||||
if((res=bdmflash_prog(alg, in_adr, val))<0) {
|
||||
fprintf(stderr, "flash byte write error %d at 0x%lx\n",
|
||||
res,(u_long)in_adr);
|
||||
return offs;
|
||||
}
|
||||
in_adr+=2;
|
||||
size-=1;
|
||||
offs+=1;
|
||||
}
|
||||
while(size>=2) {
|
||||
val=(bl_ptr[offs]<<8)|bl_ptr[offs+1];
|
||||
if((res=bdmflash_prog(alg, in_adr, val))<0) {
|
||||
fprintf(stderr, "flash write error %d at 0x%lx\n",
|
||||
res,(u_long)in_adr);
|
||||
return offs;
|
||||
}
|
||||
in_adr+=2;
|
||||
size-=2;
|
||||
offs+=2;
|
||||
}
|
||||
if(size) {
|
||||
val=(FLASH_RD16(in_adr)&0x00ff)|(bl_ptr[offs]<<8);
|
||||
if((res=bdmflash_prog(alg, in_adr, val))<0) {
|
||||
fprintf(stderr, "flash byte write error %d at 0x%lx\n",
|
||||
res,(u_long)in_adr);
|
||||
return offs;
|
||||
}
|
||||
size-=1;
|
||||
offs+=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while(size>=1) {
|
||||
val=bl_ptr[offs];
|
||||
if((res=bdmflash_prog(alg, in_adr, bl_ptr+offs, size))<=0) {
|
||||
fprintf(stderr, "flash write error %d at 0x%lx\n",
|
||||
res,(u_long)in_adr);
|
||||
return offs;
|
||||
}
|
||||
in_adr+=res;
|
||||
size-=res;
|
||||
offs+=res;
|
||||
}
|
||||
return offs;
|
||||
|
||||
#if 0
|
||||
mem_op_error:
|
||||
fprintf(stderr, "bdm memory access error\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
bdmflash_erase_filt(bdmlib_bfilt_t * filt, uint32_t in_adr, unsigned int size)
|
||||
{
|
||||
int res=0;
|
||||
const flash_alg_info_t *alg=(flash_alg_info_t*)filt->info;
|
||||
if(!in_adr)
|
||||
in_adr=filt->begin_adr;
|
||||
|
||||
res=bdmflash_erase(alg, in_adr,size);
|
||||
if(res<0)
|
||||
fprintf(stderr, "flash erase error %d\n",res);
|
||||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* slow version of blank check */
|
||||
int
|
||||
bdmflash_blankck_filt(bdmlib_bfilt_t * filt, uint32_t in_adr, unsigned int size)
|
||||
{
|
||||
int errors=0;
|
||||
if(!in_adr||!size){
|
||||
in_adr=filt->begin_adr;
|
||||
size=filt->end_adr-in_adr+1;
|
||||
}
|
||||
if(((long)in_adr&1)&&size){
|
||||
if(FLASH_RD8(in_adr)!=0xff){
|
||||
fprintf(stderr,"blank check error at 0x%06lX",(long)in_adr);
|
||||
errors++;
|
||||
}
|
||||
in_adr++; size--;
|
||||
}
|
||||
while(size>=2){
|
||||
if(FLASH_RD16(in_adr)!=0xffff){
|
||||
if(errors<5){
|
||||
if(errors) fprintf(stderr,",0x%06lX",(long)in_adr);
|
||||
else fprintf(stderr,"blank check error at 0x%06lX",(long)in_adr);
|
||||
}else if(errors==5) fprintf(stderr, " and more");
|
||||
errors++;
|
||||
}
|
||||
if(!((long)in_adr&0xfff)) bdmlib_propeller(stdout);
|
||||
in_adr+=2; size-=2;
|
||||
}
|
||||
if(size){
|
||||
if(FLASH_RD8(in_adr)!=0xff){
|
||||
if(errors) fprintf(stderr,",0x%06lX",(long)in_adr);
|
||||
else fprintf(stderr,"blank check error at 0x%06lX",(long)in_adr);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if(errors) fprintf(stderr,"\n");
|
||||
|
||||
return errors;
|
||||
|
||||
mem_op_error:
|
||||
fprintf(stderr, "bdm memory access error\n");
|
||||
return -5;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* hopefully faster version of blank check */
|
||||
int
|
||||
bdmflash_blankck_filt(bdmlib_bfilt_t * filt, uint32_t in_adr,
|
||||
unsigned int size)
|
||||
{
|
||||
int errors=0, in_buf;
|
||||
unsigned char buf[1024], *p;
|
||||
if(!in_adr||!size){
|
||||
in_adr=filt->begin_adr;
|
||||
size=filt->end_adr-in_adr+1;
|
||||
}
|
||||
|
||||
while(size){
|
||||
if(size<sizeof(buf)) in_buf=size;
|
||||
else in_buf=sizeof(buf);
|
||||
|
||||
if(bdmlib_read_block(in_adr,in_buf,buf)!=in_buf)
|
||||
goto mem_op_error;
|
||||
|
||||
size-=in_buf;
|
||||
for(p=buf;in_buf--;in_adr++,p++){
|
||||
if(*p!=0xff){
|
||||
if(errors<10){
|
||||
if(errors) fprintf(stderr,",0x%06lX",(long)in_adr);
|
||||
else fprintf(stderr,"blank check error at 0x%06lX",(long)in_adr);
|
||||
}else if(errors==10) fprintf(stderr, " and more");
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
bdmlib_propeller((u_long)in_adr, stdout);
|
||||
}
|
||||
|
||||
if(errors) fprintf(stderr,"\n");
|
||||
|
||||
return errors;
|
||||
|
||||
mem_op_error:
|
||||
fprintf(stderr, "\nbdm memory access error\n");
|
||||
return -5;
|
||||
}
|
||||
|
||||
#endif
|
||||
75
m68k/flashlib/bdmflash.h
Normal file
75
m68k/flashlib/bdmflash.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef BDMFLASH_H
|
||||
#define BDMFLASH_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define FLASH_ALG_BITS_x8 0
|
||||
#define FLASH_ALG_BITS_x16 2
|
||||
#define FLASH_ALG_BITS_x8x2 3
|
||||
#define FLASH_ALG_BITS_x32 4
|
||||
#define FLASH_ALG_BITS_x16x2 5
|
||||
#define FLASH_ALG_BITS_x8x4 7
|
||||
|
||||
#define WITH_TARGET_BUS32
|
||||
|
||||
#ifndef WITH_TARGET_BUS32
|
||||
typedef uint16_t flash_d_t; /* Type able to store one flash location */
|
||||
#else /* WITH_TARGET_BUS32 */
|
||||
typedef uint32_t flash_d_t; /* Type able to store one flash location */
|
||||
#endif /* WITH_TARGET_BUS32 */
|
||||
|
||||
/* Structure describing programming operations for flash type */
|
||||
typedef struct flash_alg_info {
|
||||
/* Sets retid to manufacturer and type ID, returns <0 in case of error */
|
||||
int (*check_id)(const struct flash_alg_info *alg, uint32_t addr, flash_d_t retid[2]);
|
||||
/* Programs one location of flash and returns number of programmed bytes */
|
||||
int (*prog)(const struct flash_alg_info *alg, uint32_t addr, const void *data, long count);
|
||||
/* Erase all sectors overlaped by region from addr of size bytes, size=0 => erase all */
|
||||
/* This version is capable only of full erase (size=0) and one sector (size=1) */
|
||||
int (*erase)(const struct flash_alg_info *alg, uint32_t addr, long size);
|
||||
/* Numeric and string fields follows */
|
||||
uint32_t addr_mask; /* Mask to take offset inside flash */
|
||||
uint32_t reg1_addr; /* Flash control register 1 */
|
||||
uint32_t reg2_addr; /* Flash control register 2 */
|
||||
uint32_t sec_size; /* block size of bigger blocks */
|
||||
flash_d_t width; /* FLASH_ALG_BITS_x8 .. 8 bit data bus,
|
||||
FLASH_ALG_BITS_x16 .. 16 bit data,
|
||||
FLASH_ALG_BITS_x8x2 .. two interleaved 8 bit */
|
||||
flash_d_t cmd_unlock1;/* first byte of command sequence */
|
||||
flash_d_t cmd_unlock2;/* second byte of command sequence */
|
||||
flash_d_t cmd_rdid; /* read identifier */
|
||||
flash_d_t cmd_prog; /* program one loc */
|
||||
flash_d_t cmd_erase; /* erase command */
|
||||
flash_d_t cmd_reset; /* leave program mode */
|
||||
flash_d_t erase_all; /* erase all */
|
||||
flash_d_t erase_sec; /* erase sector */
|
||||
flash_d_t fault_bit; /* programing of location failed */
|
||||
flash_d_t manid; /* manufacturer ID */
|
||||
flash_d_t devid; /* device ID */
|
||||
char *alg_name; /* informative flash type name */
|
||||
} flash_alg_info_t;
|
||||
|
||||
int bdmflash_check_id(const flash_alg_info_t *alg, uint32_t addr,
|
||||
flash_d_t retid[2]);
|
||||
|
||||
int bdmflash_prog(const flash_alg_info_t *alg, uint32_t addr, const void *data, long count);
|
||||
|
||||
int bdmflash_erase(const flash_alg_info_t *alg, uint32_t addr, long size);
|
||||
|
||||
flash_alg_info_t **flash_alg_infos;
|
||||
|
||||
const flash_alg_info_t *bdmflash_alg_from_id(flash_d_t id[2]);
|
||||
|
||||
const flash_alg_info_t *bdmflash_alg_probe(uint32_t flash_adr);
|
||||
|
||||
int bdmflash_wrb_filt(bdmlib_bfilt_t * filt, uint32_t in_adr,
|
||||
unsigned int size, u_char * bl_ptr);
|
||||
|
||||
int bdmflash_erase_filt(bdmlib_bfilt_t * filt, uint32_t in_adr, unsigned int size);
|
||||
|
||||
int bdmflash_blankck_filt(bdmlib_bfilt_t * filt, uint32_t in_adr, unsigned int size);
|
||||
|
||||
int bdmflash_check_id(const flash_alg_info_t *alg, uint32_t addr, flash_d_t retid[2]);
|
||||
|
||||
#endif /* BDMFLASH_H */
|
||||
448
m68k/flashlib/elf-utils.c
Executable file
448
m68k/flashlib/elf-utils.c
Executable file
@@ -0,0 +1,448 @@
|
||||
/*
|
||||
* $Id: elf-utils.c,v 1.2 2008/07/31 01:53:44 cjohns Exp $
|
||||
*
|
||||
* Motorola Background Debug Mode Driver
|
||||
* Copyright (C) 2008 Chris Johns
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* ELF Support for libelf.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <elf-utils.h>
|
||||
|
||||
#if defined (__WIN32__)
|
||||
#define ELF_OPEN_MODE (O_RDONLY | O_BINARY)
|
||||
#else
|
||||
#define ELF_OPEN_MODE (O_RDONLY)
|
||||
#endif
|
||||
|
||||
void
|
||||
elf_handle_init (elf_handle* handle)
|
||||
{
|
||||
memset (handle, 0, sizeof (*handle));
|
||||
}
|
||||
|
||||
int
|
||||
elf_open (const char* file, elf_handle* handle, elf_output output)
|
||||
{
|
||||
if (handle->fd)
|
||||
{
|
||||
if (output)
|
||||
output ("elf-utils: ELF handle already initialised\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elf_version (EV_CURRENT) == EV_NONE)
|
||||
{
|
||||
if (output)
|
||||
output ("elf-utils: ELF library initialization failed: %s\n",
|
||||
elf_errmsg (-1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle->output = output;
|
||||
|
||||
if ((handle->fd = open (file, ELF_OPEN_MODE, 0)) < 0)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: open %s failed\n", file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((handle->elf = elf_begin (handle->fd, ELF_C_READ, NULL)) == NULL)
|
||||
{
|
||||
close (handle->fd);
|
||||
handle->fd = 0;
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_begin failed: %s\n", elf_errmsg (-1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle->file = strdup (file);
|
||||
handle->ek = elf_kind (handle->elf);
|
||||
|
||||
/*
|
||||
* Check the executable header.
|
||||
*/
|
||||
if (gelf_getehdr (handle->elf, &handle->ehdr) == NULL)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_getehdr failed: %s\n", elf_errmsg (-1));
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle->ehdr.e_machine != EM_68K)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: machine type not Motorola 68000\n");
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((handle->ehdr.e_type != ET_REL) && (handle->ehdr.e_type != ET_EXEC))
|
||||
{
|
||||
output ("elf-utils: file type no relocable or executable\n");
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((handle->eclass = gelf_getclass (handle->elf)) == ELFCLASSNONE)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_getclass failed: %s\n", elf_errmsg (-1));
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* No 64-bit Coldfires yet !
|
||||
*/
|
||||
if (handle->eclass != ELFCLASS32)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: ELF 64-bit, only 32-bit support: %s\n",
|
||||
handle->file);
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elf_getshnum (handle->elf, &handle->shnum) == 0)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_getshnum failed: %s\n", elf_errmsg (-1));
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elf_getshstrndx (handle->elf, &handle->shstrndx) == 0)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_getshstrndx failed: %s\n", elf_errmsg (-1));
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (elf_getphnum (handle->elf, &handle->phnum) == 0)
|
||||
{
|
||||
if (handle->output)
|
||||
output ("elf-utils: elf_getphnum failed: %s\n", elf_errmsg (-1));
|
||||
elf_close (handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
elf_close (elf_handle* handle)
|
||||
{
|
||||
if (!handle->fd)
|
||||
return 0;
|
||||
|
||||
elf_end (handle->elf);
|
||||
close (handle->fd);
|
||||
free (handle->file);
|
||||
|
||||
handle->elf = NULL;
|
||||
handle->file = NULL;
|
||||
handle->fd = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
elf_has_symbol_table (elf_handle* handle)
|
||||
{
|
||||
Elf_Scn* section = NULL;
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
if (gelf_getshdr (section, &shdr) != &shdr)
|
||||
{
|
||||
if (shdr.sh_type == SHT_SYMTAB)
|
||||
{
|
||||
Elf_Data* data = NULL;
|
||||
|
||||
data = elf_getdata (section, data);
|
||||
|
||||
if ((data == NULL) || (data->d_size == 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
elf_get_symbol (elf_handle* handle, const char* label, GElf_Sym* sym)
|
||||
{
|
||||
Elf_Scn* section = NULL;
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
|
||||
if (gelf_getshdr (section, &shdr) == &shdr)
|
||||
{
|
||||
if (shdr.sh_type == SHT_SYMTAB)
|
||||
{
|
||||
Elf_Data* data = NULL;
|
||||
int symbol = 0;
|
||||
char* name;
|
||||
|
||||
data = elf_getdata (section, data);
|
||||
|
||||
if ((data == NULL) || (data->d_size == 0))
|
||||
return 0;
|
||||
|
||||
while (gelf_getsym (data, symbol, sym) == sym)
|
||||
{
|
||||
name = elf_strptr (handle->elf,
|
||||
shdr.sh_link, (size_t) sym->st_name);
|
||||
if (!name)
|
||||
{
|
||||
if (handle->output)
|
||||
handle->output ("elf-utils: find symbol: %s\n",
|
||||
elf_errmsg (elf_errno ()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp (label, name) == 0)
|
||||
return 1;
|
||||
|
||||
symbol++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
elf_get_section_hdr (elf_handle* handle, int secindex, GElf_Shdr* shdr)
|
||||
{
|
||||
Elf_Scn* section = NULL;
|
||||
int count = 1;
|
||||
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
if (count == secindex)
|
||||
{
|
||||
if (gelf_getshdr (section, shdr) == shdr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
elf_get_section_data (elf_handle* handle, int secindex, uint32_t* size)
|
||||
{
|
||||
Elf_Scn* section = NULL;
|
||||
int count = 1;
|
||||
|
||||
*size = 0;
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
if (count == secindex)
|
||||
{
|
||||
Elf_Data* data = NULL;
|
||||
void* buffer;
|
||||
|
||||
data = elf_getdata (section, data);
|
||||
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
*size = (uint32_t) data->d_size;
|
||||
return data->d_buf;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void*
|
||||
elf_get_section_data_sym (elf_handle* handle, const char* label)
|
||||
{
|
||||
GElf_Sym esym;
|
||||
|
||||
if (elf_get_symbol (handle, label, &esym))
|
||||
{
|
||||
Elf_Scn* section = NULL;
|
||||
int count = 1;
|
||||
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
if (count == esym.st_shndx)
|
||||
{
|
||||
Elf_Data* data = NULL;
|
||||
|
||||
data = elf_getdata (section, data);
|
||||
|
||||
if ((data == NULL) || (data->d_size == 0))
|
||||
return NULL;
|
||||
|
||||
return ((uint8_t *) data->d_buf) + esym.st_value;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
elf_map_over_sections (elf_handle* handle, elf_section_handler handler,
|
||||
const char* sname)
|
||||
{
|
||||
/*
|
||||
* We need to iterate over the sections, and then for each section we decide
|
||||
* to load, we need to find the program header for that section. we match
|
||||
* the program header by finding the program header that has the same virtaul
|
||||
* address range. This yields us with the physical address which is needed
|
||||
* to know where to load the section on the target. I don't know if this is
|
||||
* the correct way to do this, if not, please fix.
|
||||
*/
|
||||
|
||||
Elf_Scn* section = NULL;
|
||||
int count = 1;
|
||||
size_t num_headers = 0;
|
||||
|
||||
if (elf_getphnum (handle->elf, &num_headers) == 0)
|
||||
{
|
||||
if (handle->output)
|
||||
handle->output ("elf-utils: elf_getphnum error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((section = elf_nextscn (handle->elf, section)) != 0)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
|
||||
if (gelf_getshdr (section, &shdr) == &shdr) {
|
||||
const char* name;
|
||||
name = elf_strptr (handle->elf, handle->shstrndx, shdr.sh_name);
|
||||
|
||||
if (!sname || (strcmp (sname, name) == 0))
|
||||
{
|
||||
/*
|
||||
* Find a LOAD program header in the same virtual address range.
|
||||
*/
|
||||
GElf_Addr vaddr = shdr.sh_addr - shdr.sh_offset;
|
||||
GElf_Phdr phdr;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num_headers; ++i)
|
||||
{
|
||||
if (gelf_getphdr (handle->elf, i, &phdr) != &phdr)
|
||||
{
|
||||
if (handle->output)
|
||||
handle->output ("elf-utils: gelf_getphdr error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(phdr.p_type == PT_LOAD)
|
||||
{
|
||||
if(phdr.p_vaddr <= shdr.sh_addr &&
|
||||
phdr.p_vaddr + phdr.p_memsz > shdr.sh_addr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!handler (handle, (i == num_headers) ? 0 : &phdr, &shdr, name, count))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PRINT_FORMAT " %-12s %d\n"
|
||||
#define PRINT_FORMAT_X " %-12s 0x%x\n"
|
||||
|
||||
void
|
||||
elf_show_exeheader (elf_handle* handle)
|
||||
{
|
||||
#define EHDR_PRINT_FIELD(N) do { \
|
||||
handle->output (PRINT_FORMAT ,#N, (uintmax_t) handle->ehdr.N); \
|
||||
} while (0)
|
||||
|
||||
char* s;
|
||||
|
||||
if (!handle->output)
|
||||
return;
|
||||
|
||||
switch (handle->ek)
|
||||
{
|
||||
case ELF_K_AR:
|
||||
s = "ar(1) archive";
|
||||
break;
|
||||
case ELF_K_ELF:
|
||||
s = "elf object";
|
||||
break;
|
||||
case ELF_K_NONE:
|
||||
s = "data";
|
||||
break;
|
||||
default:
|
||||
s = "unrecognized";
|
||||
}
|
||||
|
||||
handle->output ("%s: %s\n", handle->file, s);
|
||||
|
||||
EHDR_PRINT_FIELD (e_type);
|
||||
EHDR_PRINT_FIELD (e_machine);
|
||||
EHDR_PRINT_FIELD (e_version);
|
||||
EHDR_PRINT_FIELD (e_entry);
|
||||
EHDR_PRINT_FIELD (e_phoff);
|
||||
EHDR_PRINT_FIELD (e_shoff);
|
||||
EHDR_PRINT_FIELD (e_flags);
|
||||
EHDR_PRINT_FIELD (e_ehsize);
|
||||
EHDR_PRINT_FIELD (e_phentsize);
|
||||
EHDR_PRINT_FIELD (e_shentsize);
|
||||
|
||||
handle->output (PRINT_FORMAT, "(shnum)", (uintmax_t) handle->shnum);
|
||||
handle->output (PRINT_FORMAT, "(shstrndx)", (uintmax_t) handle->shstrndx);
|
||||
handle->output (PRINT_FORMAT, "(phnum)", (uintmax_t) handle->phnum);
|
||||
}
|
||||
|
||||
void
|
||||
elf_show_symbol (elf_handle* handle, GElf_Sym* esym)
|
||||
{
|
||||
#define ESYM_PRINT_FIELD(N) do { \
|
||||
handle->output (PRINT_FORMAT_X ,#N, (uintmax_t) esym->N); \
|
||||
} while (0)
|
||||
|
||||
if (!handle->output)
|
||||
return;
|
||||
|
||||
ESYM_PRINT_FIELD (st_name);
|
||||
ESYM_PRINT_FIELD (st_value);
|
||||
ESYM_PRINT_FIELD (st_size);
|
||||
ESYM_PRINT_FIELD (st_info);
|
||||
ESYM_PRINT_FIELD (st_other);
|
||||
ESYM_PRINT_FIELD (st_shndx);
|
||||
}
|
||||
76
m68k/flashlib/elf-utils.h
Executable file
76
m68k/flashlib/elf-utils.h
Executable file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Motorola Background Debug Mode Driver
|
||||
* Copyright (C) 2008 Chris Johns
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* ELF Support for libelf.
|
||||
*/
|
||||
|
||||
#if !defined (_ELF_UTILS_H_)
|
||||
#define _ELF_UTILS_H_
|
||||
|
||||
#define __LIBELF_INTERNAL__ 1
|
||||
#include <gelf.h>
|
||||
|
||||
/*
|
||||
* Output routine.
|
||||
*/
|
||||
typedef int (*elf_output) (const char *format, ...);
|
||||
|
||||
/*
|
||||
* Handle to access the file via libelf.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char* file;
|
||||
int fd;
|
||||
Elf* elf;
|
||||
Elf_Kind ek;
|
||||
GElf_Ehdr ehdr;
|
||||
int eclass;
|
||||
size_t shnum;
|
||||
size_t shstrndx;
|
||||
size_t phnum;
|
||||
elf_output output;
|
||||
} elf_handle;
|
||||
|
||||
/*
|
||||
* Section handler.
|
||||
*/
|
||||
typedef int (*elf_section_handler) (elf_handle* handle,
|
||||
GElf_Phdr* phdr,
|
||||
GElf_Shdr* shdr,
|
||||
const char* sname,
|
||||
int sindex);
|
||||
|
||||
void elf_handle_init (elf_handle* handle);
|
||||
|
||||
int elf_open (const char* file, elf_handle* handle, elf_output output);
|
||||
int elf_close (elf_handle* handle);
|
||||
|
||||
int elf_get_symbol (elf_handle* handle, const char* label, GElf_Sym* sym);
|
||||
|
||||
int elf_get_section_hdr (elf_handle* handle, int secindex, GElf_Shdr* shdr);
|
||||
|
||||
void* elf_get_section_data (elf_handle* handle, int secindex,
|
||||
uint32_t* size);
|
||||
void* elf_get_section_data_sym (elf_handle* handle, const char* label);
|
||||
int elf_map_over_sections (elf_handle* handle,
|
||||
elf_section_handler handler, const char* sname);
|
||||
|
||||
void elf_show_exeheader (elf_handle* handle);
|
||||
void elf_show_symbol (elf_handle* handle, GElf_Sym* esym);
|
||||
|
||||
#endif
|
||||
689
m68k/flashlib/flash29.c
Normal file
689
m68k/flashlib/flash29.c
Normal file
@@ -0,0 +1,689 @@
|
||||
/* $Id: flash29.c,v 1.6 2008/07/31 01:53:44 cjohns Exp $
|
||||
*
|
||||
* Driver for 29Fxxx and 49Fxxx flash chips.
|
||||
*
|
||||
* 2003-12-28 Josef Wolf (jw@raven.inka.de)
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This piece of code arose from ad-hoc code-snippets which I threw into
|
||||
discussions on the bdm-devel mailing list and in private mails to Pavel
|
||||
Pisa. I have put those pieces together, removed compiler-errors, rewrote
|
||||
them several times and optimized somewhat.
|
||||
|
||||
This code supports:
|
||||
|
||||
- 29Fxxx and 49Fxxx types of flash chips.
|
||||
- Host-only, target-assisted and target-only operation modes.
|
||||
- Bus widths of 1, 2 and 4 bytes.
|
||||
- Chip widths of 1, 2 and 4 bytes.
|
||||
- Autodetection of known chips on arbitrary bus/chip width combinations.
|
||||
- Fast bypass unlock programming mode on chips that support it.
|
||||
- Unaligned programming.
|
||||
*/
|
||||
|
||||
/* Todo:
|
||||
CSI command set? What is this?
|
||||
CFI specification http://www.amd.com/products/nvd/overview/cfi.html
|
||||
*/
|
||||
|
||||
#include "flash29.h"
|
||||
#include "flash_filter.h"
|
||||
|
||||
#if HOST_FLASHING
|
||||
# include <stdio.h>
|
||||
# include <BDMlib.h>
|
||||
#endif
|
||||
|
||||
/* This defines details for the flash algorithm.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cmd_unlock1;
|
||||
uint32_t cmd_unlock2;
|
||||
uint32_t cmd_reset;
|
||||
uint32_t cmd_autoselect;
|
||||
uint32_t cmd_program;
|
||||
uint32_t cmd_erase;
|
||||
uint32_t cmd_chiperase;
|
||||
uint32_t cmd_secterase;
|
||||
uint32_t cmd_bypass;
|
||||
uint32_t cmd_resbypass1;
|
||||
uint32_t cmd_resbypass2;
|
||||
|
||||
uint32_t timeout_mask;
|
||||
uint32_t adr_unlock1;
|
||||
uint32_t adr_unlock2;
|
||||
} alg_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
const uint32_t manufacturer, device_id;
|
||||
const uint32_t size; /* in bytes */
|
||||
const alg_info_t *alg_info;
|
||||
} chip_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const alg_info_t *alg_info; /* algorithm information */
|
||||
uint32_t adr; /* base adress of the chip */
|
||||
uint32_t size; /* in bytes */
|
||||
uint32_t chip_width; /* 1->8bit, 2->16bit, 4->32bit */
|
||||
uint32_t bus_width; /* 1->8bit, 2->16bit, 4->32bit */
|
||||
uint32_t wait_adr; /* address to check when waiting for erase */
|
||||
|
||||
/* From here on, everything is redundant. The only reason to maintain this
|
||||
redundant information is optimization. */
|
||||
uint32_t reg1; /* address of unlock register 1 */
|
||||
uint32_t reg2; /* address of unlock register 2 */
|
||||
|
||||
/* This information is placed at the end of the struct because
|
||||
download_struct() don't need to fiddle around with it. */
|
||||
void (*wr_func) (uint32_t, uint32_t); /* write function */
|
||||
uint32_t(*rd_func) (uint32_t); /* read function */
|
||||
uint32_t bus_mask; /* Mask to get bus_width lowest bytes */
|
||||
uint32_t chip_mask; /* Mask to get chip_width lowest bytes */
|
||||
uint32_t shift; /* shift for multiplication by bus_width */
|
||||
} chiptype_t;
|
||||
|
||||
static const alg_info_t alg_29_std = { /* standard 29fxx chips */
|
||||
0xaaaaaaaa, /* unlock 1 command */
|
||||
0x55555555, /* unlock 2 command */
|
||||
0xf0f0f0f0, /* res */
|
||||
0x90909090, /* asel */
|
||||
0xa0a0a0a0, /* prog */
|
||||
0x80808080, /* erase */
|
||||
0x10101010, /* chiperase */
|
||||
0x30303030, /* secterase */
|
||||
0x00000000, /* no unlock bypass */
|
||||
0x90909090, /* unlock bypass res1 */
|
||||
0x00000000, /* unlock bypass res2 */
|
||||
0x20, /* timeout bitmask */
|
||||
0x555, /* register 1 */
|
||||
0x2aa, /* register 5 */
|
||||
};
|
||||
|
||||
static const alg_info_t alg_29_unl = { /* 29fxx with unlock bypass mode */
|
||||
0xaaaaaaaa, /* unlock 1 command */
|
||||
0x55555555, /* unlock 2 command */
|
||||
0xf0f0f0f0, /* res */
|
||||
0x90909090, /* asel */
|
||||
0xa0a0a0a0, /* prog */
|
||||
0x80808080, /* erase */
|
||||
0x10101010, /* chiperase */
|
||||
0x30303030, /* secterase */
|
||||
0x20202020, /* unlock bypass */
|
||||
0x90909090, /* unlock bypass res1 */
|
||||
0x00000000, /* unlock bypass res2 */
|
||||
0x20, /* timeout bitmask */
|
||||
0x555, /* register 1 */
|
||||
0x2aa, /* register 5 */
|
||||
};
|
||||
|
||||
static const alg_info_t alg_49 = { /* 49fxx and 39fxx chips */
|
||||
0xaaaaaaaa, /* unlock 1 command */
|
||||
0x55555555, /* unlock 2 command */
|
||||
0xf0f0f0f0, /* res */
|
||||
0x90909090, /* asel */
|
||||
0xa0a0a0a0, /* prog */
|
||||
0x80808080, /* erase */
|
||||
0x10101010, /* chiperase */
|
||||
0x30303030, /* secterase *//* Block erase ? */
|
||||
0x00000000, /* no unlock bypass */
|
||||
0x90909090, /* unlock bypass res1 */
|
||||
0x00000000, /* unlock bypass res2 */
|
||||
0x00, /* no timeout support */
|
||||
0x5555, /* register 1 */
|
||||
0x2aaa, /* register 5 */
|
||||
};
|
||||
|
||||
/* Here come the known chips.
|
||||
*/
|
||||
static const chip_t chips[] = {
|
||||
{"Am29LV001BT", 0x01, 0xed, 0x20000, &alg_29_unl}, /* AMD */
|
||||
{"Am29LV001BB", 0x01, 0x6d, 0x20000, &alg_29_unl}, /* AMD */
|
||||
{"Am29LV002T", 0x01, 0x40, 0x40000, &alg_29_std}, /* AMD */
|
||||
{"Am29LV002B", 0x01, 0xc2, 0x40000, &alg_29_std}, /* AMD */
|
||||
{"Am29LV004T", 0x01, 0xb5, 0x80000, &alg_29_std}, /* AMD */
|
||||
{"Am29LV004B", 0x01, 0xb6, 0x80000, &alg_29_std}, /* AMD */
|
||||
{"Am29LV008BT", 0x01, 0x3e, 0x100000, &alg_29_unl}, /* AMD */
|
||||
{"Am29LV008BB", 0x01, 0x37, 0x100000, &alg_29_unl}, /* AMD */
|
||||
{"Am29LV017B", 0x01, 0xc8, 0x200000, &alg_29_unl}, /* AMD */
|
||||
|
||||
{"Am29F010B", 0x01, 0x20, 0x20000, &alg_29_std}, /* AMD */
|
||||
|
||||
{"At49F040", 0x1f, 0x13, 0x80000, &alg_49}, /* Atmel */
|
||||
|
||||
{"Am29F040B", 0x01, 0xa4, 0x80000, &alg_29_std}, /* AMD */
|
||||
{"Am29F400BT", 0x01, 0x2223, 0x80000, &alg_29_std}, /* AMD */
|
||||
{"Am29F400BB", 0x01, 0x22ab, 0x80000, &alg_29_std}, /* AMD */
|
||||
{"MBM29F400TC", 0x04, 0x2223, 0x80000, &alg_29_std}, /* Fujitsu */
|
||||
{"MBM29F400BC", 0x04, 0x22ab, 0x80000, &alg_29_std}, /* Fujitsu */
|
||||
{"M29F400BB", 0x20, 0x22d6, 0x80000, &alg_29_unl}, /* ST */
|
||||
{"M29F400BB", 0x20, 0x22d5, 0x80000, &alg_29_unl}, /* ST */
|
||||
|
||||
{"Am29F080B", 0x01, 0xd5, 0x100000, &alg_29_std}, /* AMD */
|
||||
{"Am29F800BT", 0x01, 0x22d6, 0x100000, &alg_29_std}, /* AMD */
|
||||
{"Am29F800BB", 0x01, 0x2258, 0x100000, &alg_29_std}, /* AMD */
|
||||
|
||||
{"Am29PL160C", 0x01, 0x2245, 0x200000, &alg_29_unl}, /* AMD */
|
||||
{"Am29LV160B", 0x01, 0x2249, 0x200000, &alg_29_unl}, /* AMD */
|
||||
{"M29LV160B", 0x20, 0x2249, 0x200000, &alg_29_unl}, /* ST */
|
||||
{"HY29LV160B", 0xad, 0x2249, 0x200000, &alg_29_unl}, /* HYRIX */
|
||||
{"MX29LV160B", 0xc2, 0x2245, 0x200000, &alg_29_unl}, /* MACRONIX */
|
||||
{"TC58FVB160A", 0x98, 0x0043, 0x200000, &alg_29_unl}, /* TOSHIBA */
|
||||
|
||||
{"Am29LV320B", 0x01, 0x22f9, 0x400000, &alg_29_unl}, /* AMD */
|
||||
{"HY29LV320B", 0xad, 0x227d, 0x400000, &alg_29_unl}, /* HYRIX */
|
||||
{"MX29LV320B", 0xc2, 0x22a8, 0x400000, &alg_29_unl}, /* MACRONIX */
|
||||
{"TC58FVM5B2A", 0x98, 0x0055, 0x400000, &alg_29_unl}, /* TOSHIBA */
|
||||
{"TC58FVM5B3A", 0x98, 0x0050, 0x400000, &alg_29_unl}, /* TOSHIBA */
|
||||
|
||||
{"Am29LV640MB", 0x01, 0x227e, 0x800000, &alg_29_unl}, /* AMD */
|
||||
{"M29W640DB", 0x20, 0x22df, 0x800000, &alg_29_unl}, /* ST */
|
||||
{"MBM29DLV640E", 0x04, 0x227e, 0x800000, &alg_29_std}, /* FUJITSU */
|
||||
{"MX29LV640MB", 0xc2, 0x22cb, 0x800000, &alg_29_unl}, /* MACRONIX */
|
||||
{"TC58FVM6B2A", 0x98, 0x0058, 0x800000, &alg_29_unl}, /* TOSHIBA */
|
||||
|
||||
{"Sst39VF1601", 0xbf, 0x234b, 0x200000, &alg_49}, /* SST */
|
||||
{"Sst39VF1602", 0xbf, 0x234a, 0x200000, &alg_49}, /* SST */
|
||||
{"Sst39VF3201", 0xbf, 0x235b, 0x400000, &alg_49}, /* SST */
|
||||
{"Sst39VF3202", 0xbf, 0x235a, 0x400000, &alg_49}, /* SST */
|
||||
{"Sst39VF6401", 0xbf, 0x236b, 0x800000, &alg_49}, /* SST */
|
||||
{"Sst39VF6402", 0xbf, 0x236a, 0x800000, &alg_49}, /* SST */
|
||||
};
|
||||
|
||||
/* define the actual access functions to the flash. There are three orthogonal
|
||||
aspects for the access functions:
|
||||
|
||||
1. Every bus_width needs its own set of functions because we need to access
|
||||
the chips with bus_width width. This is to avoid the access be split up
|
||||
into several accesses, which could abort a started command.
|
||||
|
||||
2. Bus accesses need two functions: one for reading and one for writing.
|
||||
|
||||
3. In addition, we need a second set of functions for host-assisted access.
|
||||
*/
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
# define DEFINE_READ_FUNC(funcname,vartype,bdmfunc) \
|
||||
static uint32_t funcname (uint32_t adr) { \
|
||||
vartype val; \
|
||||
if (bdmfunc (adr, &val) < 0) \
|
||||
fprintf (stderr, #bdmfunc "(0x%08lx,xxx): %s\n", \
|
||||
adr, bdmErrorString()); \
|
||||
return (uint32_t) val; \
|
||||
}
|
||||
|
||||
# define DEFINE_WRITE_FUNC(funcname,vartype,bdmfunc) \
|
||||
static void funcname (uint32_t adr, uint32_t val) { \
|
||||
if (bdmfunc (adr, val) < 0) \
|
||||
fprintf (stderr, #bdmfunc "(0x%08lx,0x%08x): %s\n", \
|
||||
adr, val, bdmErrorString()); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define DEFINE_READ_FUNC(funcname,vartype,bdmfunc) \
|
||||
static uint32_t funcname (uint32_t adr) { \
|
||||
return *(volatile vartype *)adr; \
|
||||
}
|
||||
|
||||
# define DEFINE_WRITE_FUNC(funcname,vartype,bdmfunc) \
|
||||
static void funcname (uint32_t adr,uint32_t val) { \
|
||||
*(volatile vartype *)adr = val; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DEFINE_READ_FUNC(chip_rd_char, unsigned char, bdmReadByte)
|
||||
DEFINE_READ_FUNC(chip_rd_word, unsigned short, bdmReadWord)
|
||||
DEFINE_READ_FUNC(chip_rd_long, unsigned long, bdmReadLongWord)
|
||||
|
||||
DEFINE_WRITE_FUNC(chip_wr_char, uint8_t, bdmWriteByte)
|
||||
DEFINE_WRITE_FUNC(chip_wr_word, uint16_t, bdmWriteWord)
|
||||
DEFINE_WRITE_FUNC(chip_wr_long, uint32_t, bdmWriteLongWord)
|
||||
|
||||
/* We need a unique symbol to associate a (target-based) plugin with its
|
||||
(host-based) driver.
|
||||
*/
|
||||
static char driver_magic[] = "flash29";
|
||||
|
||||
/* Populate the the chiptype structure with bus_width specific information.
|
||||
This information is redundant. It is maintained here only for
|
||||
optimizations.
|
||||
*/
|
||||
static void
|
||||
set_chip_access(chiptype_t * ct, uint32_t bus_width)
|
||||
{
|
||||
ct->bus_width = bus_width;
|
||||
switch (bus_width) {
|
||||
case 1:
|
||||
ct->shift = 0;
|
||||
ct->bus_mask = 0x0ff;
|
||||
ct->wr_func = chip_wr_char;
|
||||
ct->rd_func = chip_rd_char;
|
||||
break;
|
||||
case 2:
|
||||
ct->shift = 1;
|
||||
ct->bus_mask = 0x0ffff;
|
||||
ct->wr_func = chip_wr_word;
|
||||
ct->rd_func = chip_rd_word;
|
||||
break;
|
||||
case 4:
|
||||
ct->shift = 2;
|
||||
ct->bus_mask = 0x0ffffffff;
|
||||
ct->wr_func = chip_wr_long;
|
||||
ct->rd_func = chip_rd_long;
|
||||
break;
|
||||
}
|
||||
ct->chip_mask = (0x100 << ((ct->chip_width - 1) << 3)) - 1;
|
||||
}
|
||||
|
||||
/* Wait for the chip to complete an erase/program command. Pavel Pisa mentioned
|
||||
that there's probably a racing condition in this code, so we will need to
|
||||
take a closer look on this one.
|
||||
*/
|
||||
static int
|
||||
wait_chip(chiptype_t * ct, uint32_t adr, uint32_t expect)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t rval;
|
||||
uint32_t bus_mask = ct->bus_mask;
|
||||
uint32_t chip_mask = ct->chip_mask;
|
||||
uint32_t tout_mask = ct->alg_info->timeout_mask;
|
||||
|
||||
uint32_t(*rd_func) (uint32_t) = ct->rd_func;
|
||||
uint32_t last_val = (rd_func(adr) & bus_mask);
|
||||
|
||||
while ((rval = (rd_func(adr) & bus_mask)) != (expect & bus_mask)) {
|
||||
|
||||
/* We don't want to loop forever when we accidentally try to program an
|
||||
EPROM. So we expect at least one toggle-bit to change. */
|
||||
if (last_val == rval)
|
||||
return 0;
|
||||
|
||||
/* loop over chips */
|
||||
for (i = 0; i < ct->bus_width; i += ct->chip_width) {
|
||||
|
||||
/* shift to get bits of this chip onto the lowest bits. */
|
||||
uint32_t shift = i << 3;
|
||||
uint32_t shifted_chip_mask = chip_mask << shift;
|
||||
|
||||
/* check whether chip i signalled timeout. */
|
||||
if ((rval >> shift) & tout_mask)
|
||||
return 0;
|
||||
|
||||
/* check whether chip i returned expected data. */
|
||||
if (!(((rval ^ expect) & shifted_chip_mask))) {
|
||||
/* Yes, we're not interested in results from this chip anymore. */
|
||||
bus_mask &= ~shifted_chip_mask;
|
||||
}
|
||||
}
|
||||
last_val = rval;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if HOST_FLASHING
|
||||
static char *
|
||||
prog_entry(void)
|
||||
{
|
||||
return "flash29_prog";
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The actual programming function
|
||||
*/
|
||||
static uint32_t
|
||||
flash29_prog(void *chip_descr,
|
||||
uint32_t pos, unsigned char *data, uint32_t cnt)
|
||||
{
|
||||
uint32_t i, align;
|
||||
void (*wr_func) (uint32_t, uint32_t);
|
||||
uint32_t val = 0;
|
||||
|
||||
chiptype_t *ct = chip_descr;
|
||||
uint32_t reg1 = ct->reg1;
|
||||
uint32_t reg2 = ct->reg2;
|
||||
uint32_t siz = ct->bus_width;
|
||||
const alg_info_t *alg_info = ct->alg_info;
|
||||
uint32_t cmd_bypass = alg_info->cmd_bypass;
|
||||
uint32_t cmd_reset = alg_info->cmd_reset;
|
||||
uint32_t cmd_prog = alg_info->cmd_program;
|
||||
uint32_t cmd_unlock1 = alg_info->cmd_unlock1;
|
||||
uint32_t cmd_unlock2 = alg_info->cmd_unlock2;
|
||||
|
||||
set_chip_access(ct, siz);
|
||||
|
||||
wr_func = ct->wr_func;
|
||||
|
||||
/* handle unaligned programming */
|
||||
align = pos & ((1 << (siz - 1)) - 1);;
|
||||
|
||||
pos &= ~align;
|
||||
|
||||
for (i = 0; i < align; i++) {
|
||||
val <<= 8;
|
||||
val |= chip_rd_char(pos + i);
|
||||
}
|
||||
|
||||
if (cmd_bypass) {
|
||||
wr_func(reg1, cmd_reset);
|
||||
wr_func(reg1, cmd_unlock1);
|
||||
wr_func(reg2, cmd_unlock2);
|
||||
wr_func(reg1, cmd_bypass);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
#if FLASH_OPTIMIZE_FOR_SPEED
|
||||
switch (siz) {
|
||||
# if FLASH_BUS_WIDTH1
|
||||
case 1:
|
||||
for (; i < cnt; i++) {
|
||||
if (!cmd_bypass) {
|
||||
chip_wr_char(reg1, cmd_reset);
|
||||
chip_wr_char(reg1, cmd_unlock1);
|
||||
chip_wr_char(reg2, cmd_unlock2);
|
||||
}
|
||||
chip_wr_char(reg1, cmd_prog);
|
||||
|
||||
val = *data++;
|
||||
chip_wr_char(pos, val);
|
||||
if (!wait_chip(ct, pos, val))
|
||||
break; /* error out */
|
||||
|
||||
pos++;
|
||||
}
|
||||
# endif
|
||||
# if FLASH_BUS_WIDTH2
|
||||
case 2:
|
||||
if (align)
|
||||
goto W1;
|
||||
while (i < cnt) {
|
||||
val = (val << 8) | *data++;
|
||||
W1:val =
|
||||
(val << 8) | (i++ <
|
||||
cnt ? *data++ : chip_rd_char(pos + 1));
|
||||
|
||||
if (!cmd_bypass) {
|
||||
chip_wr_word(reg1, cmd_reset);
|
||||
chip_wr_word(reg1, cmd_unlock1);
|
||||
chip_wr_word(reg2, cmd_unlock2);
|
||||
}
|
||||
chip_wr_word(reg1, cmd_prog);
|
||||
chip_wr_word(pos, val);
|
||||
if (!wait_chip(ct, pos, val))
|
||||
break; /* error out */
|
||||
|
||||
pos += 2;
|
||||
i++;
|
||||
val = 0;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
# if FLASH_BUS_WIDTH4
|
||||
case 4:
|
||||
switch (align) {
|
||||
case 1:
|
||||
goto L1;
|
||||
case 2:
|
||||
goto L2;
|
||||
case 3:
|
||||
goto L3;
|
||||
}
|
||||
while (i < cnt) {
|
||||
val = (val << 8) | *data++;
|
||||
L1:val =
|
||||
(val << 8) | (i++ <
|
||||
cnt ? *data++ : chip_rd_char(pos + 1));
|
||||
L2:val =
|
||||
(val << 8) | (i++ <
|
||||
cnt ? *data++ : chip_rd_char(pos + 2));
|
||||
L3:val =
|
||||
(val << 8) | (i++ <
|
||||
cnt ? *data++ : chip_rd_char(pos + 3));
|
||||
if (!cmd_bypass) {
|
||||
chip_wr_long(reg1, cmd_reset);
|
||||
chip_wr_long(reg1, cmd_unlock1);
|
||||
chip_wr_long(reg2, cmd_unlock2);
|
||||
}
|
||||
chip_wr_long(reg1, cmd_prog);
|
||||
chip_wr_long(pos, val);
|
||||
if (!wait_chip(ct, pos, val))
|
||||
break; /* error out */
|
||||
|
||||
pos += 4;
|
||||
i++;
|
||||
val = 0;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
#else
|
||||
while (i < cnt) {
|
||||
uint32_t j;
|
||||
|
||||
for (j = 0; j < siz - align; j++) {
|
||||
val <<= 8;
|
||||
val |= i + j < cnt ? *data++ : chip_rd_char(pos + j);
|
||||
}
|
||||
if (!cmd_bypass) {
|
||||
wr_func(reg1, cmd_reset);
|
||||
wr_func(reg1, cmd_unlock1);
|
||||
wr_func(reg2, cmd_unlock2);
|
||||
}
|
||||
wr_func(reg1, cmd_prog);
|
||||
wr_func(pos, val);
|
||||
|
||||
if (!wait_chip(ct, pos, val))
|
||||
break; /* error out */
|
||||
|
||||
pos += siz;
|
||||
i += siz;
|
||||
|
||||
val = 0;
|
||||
align = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmd_bypass) {
|
||||
wr_func(reg1, ct->alg_info->cmd_resbypass1);
|
||||
wr_func(reg2, ct->alg_info->cmd_resbypass2);
|
||||
}
|
||||
|
||||
return i > cnt ? cnt : i;
|
||||
}
|
||||
|
||||
/* Initiate erase operation. Sector address is relative to chip-base.
|
||||
With sector address==-1, the whole chip is erased. The erase operation
|
||||
can be called several times before flash_29_erase_wait() is called for
|
||||
simultanous erasure of multiple sectors.
|
||||
*/
|
||||
static void
|
||||
flash29_erase(void *chip_descr, int32_t sector_address)
|
||||
{
|
||||
chiptype_t *ct = chip_descr;
|
||||
uint32_t reg1 = ct->reg1;
|
||||
uint32_t reg2 = ct->reg2;
|
||||
const alg_info_t *alg_info = ct->alg_info;
|
||||
void (*wr_func) (uint32_t, uint32_t) = ct->wr_func;
|
||||
|
||||
wr_func(reg1, alg_info->cmd_reset);
|
||||
wr_func(reg1, alg_info->cmd_unlock1);
|
||||
wr_func(reg2, alg_info->cmd_unlock2);
|
||||
wr_func(reg1, alg_info->cmd_erase);
|
||||
wr_func(reg1, alg_info->cmd_unlock1);
|
||||
wr_func(reg2, alg_info->cmd_unlock2);
|
||||
|
||||
if (sector_address >= 0 && sector_address < ct->size) {
|
||||
ct->wait_adr = ct->adr + (sector_address << ct->shift);
|
||||
wr_func(ct->wait_adr, alg_info->cmd_secterase);
|
||||
} else {
|
||||
ct->wait_adr = ct->adr;
|
||||
wr_func(reg1, alg_info->cmd_chiperase);
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for queued erasing operations to finish
|
||||
*/
|
||||
static int
|
||||
flash29_erase_wait(void *chip_descr)
|
||||
{
|
||||
chiptype_t *ct = chip_descr;
|
||||
|
||||
return wait_chip(ct, ct->wait_adr, ct->bus_mask);
|
||||
}
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
/* read the chip ID
|
||||
*/
|
||||
static uint32_t
|
||||
read_id(chiptype_t * ct, int adr)
|
||||
{
|
||||
unsigned int ret;
|
||||
uint32_t reg1 = ct->reg1;
|
||||
uint32_t reg2 = ct->reg2;
|
||||
const alg_info_t *alg_info = ct->alg_info;
|
||||
void (*wr_func) (uint32_t, uint32_t) = ct->wr_func;
|
||||
|
||||
wr_func(reg1, alg_info->cmd_reset);
|
||||
wr_func(reg1, alg_info->cmd_unlock1);
|
||||
wr_func(reg2, alg_info->cmd_unlock2);
|
||||
wr_func(reg1, alg_info->cmd_autoselect);
|
||||
|
||||
ret = ct->rd_func(ct->adr + (adr << ct->shift));
|
||||
|
||||
wr_func(reg1, alg_info->cmd_reset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* autodetect a 29Fxxx type chip
|
||||
*/
|
||||
static uint32_t
|
||||
flash29_search_chip(void *chip_descr, char *description, uint32_t pos)
|
||||
{
|
||||
chiptype_t *ct = chip_descr;
|
||||
int i, j, bw, cw;
|
||||
uint32_t m, d;
|
||||
uint32_t exp;
|
||||
const alg_info_t *alg_info;
|
||||
const chip_t *chip;
|
||||
|
||||
ct->adr = pos;
|
||||
|
||||
for (bw = 4; bw; bw >>= 1) {
|
||||
for (cw = bw; cw; cw >>= 1) {
|
||||
ct->chip_width = cw;
|
||||
|
||||
set_chip_access(ct, bw);
|
||||
|
||||
for (i = 0; i < NUMOF(chips); i++) {
|
||||
chip = &chips[i];
|
||||
ct->size = chip->size * (bw / cw);
|
||||
ct->alg_info = alg_info = chip->alg_info;
|
||||
ct->reg1 = pos + ((alg_info->adr_unlock1) << (ct->shift));
|
||||
ct->reg2 = pos + ((alg_info->adr_unlock2) << (ct->shift));
|
||||
|
||||
if ((m = read_id(ct, 0)) != chip->manufacturer)
|
||||
continue;
|
||||
|
||||
exp = 0;
|
||||
for (j = 0; j < bw; j += cw) {
|
||||
exp <<= ((cw - 1) << 3);
|
||||
exp |= (chip->device_id) & (ct->chip_mask);
|
||||
}
|
||||
|
||||
if ((d = read_id(ct, 1)) != exp)
|
||||
continue;
|
||||
|
||||
/* check if we are just reading ram */
|
||||
if (m == ct->rd_func(pos) && d == ct->rd_func(pos + (1 << ct->shift)))
|
||||
return 0;
|
||||
|
||||
if (description) {
|
||||
sprintf(description, "%10s @ 0x%08lx..0x%08lx "
|
||||
"bw:%d cw:%d manuf:0x%02lx device:0x%04lx size:0x%08lx",
|
||||
chip->name, pos, pos + ct->size, bw, cw, m, d, ct->size);
|
||||
}
|
||||
|
||||
return ct->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
# define CHIP_WR(base,str,field,val) \
|
||||
chip_wr_long((base)+(((unsigned char*)&((str)->field)) - \
|
||||
((unsigned char*)str)), \
|
||||
(val));
|
||||
|
||||
/* FIXME: this function assumes that data sizes and alignment requirements
|
||||
on target and host are identical.
|
||||
*/
|
||||
static int
|
||||
download_struct(void *chip_descr, uint32_t adr)
|
||||
{
|
||||
chiptype_t *ct = chip_descr;
|
||||
const alg_info_t *alg = ct->alg_info;
|
||||
|
||||
uint32_t alg_adr = adr + sizeof(*ct);
|
||||
|
||||
CHIP_WR(adr, ct, alg_info, alg_adr);
|
||||
CHIP_WR(adr, ct, adr, ct->adr);
|
||||
CHIP_WR(adr, ct, size, ct->size);
|
||||
CHIP_WR(adr, ct, chip_width, ct->chip_width);
|
||||
CHIP_WR(adr, ct, bus_width, ct->bus_width);
|
||||
CHIP_WR(adr, ct, reg1, ct->reg1);
|
||||
CHIP_WR(adr, ct, reg2, ct->reg2);
|
||||
|
||||
CHIP_WR(alg_adr, alg, cmd_unlock1, alg->cmd_unlock1);
|
||||
CHIP_WR(alg_adr, alg, cmd_unlock2, alg->cmd_unlock2);
|
||||
CHIP_WR(alg_adr, alg, cmd_reset, alg->cmd_reset);
|
||||
CHIP_WR(alg_adr, alg, cmd_program, alg->cmd_program);
|
||||
CHIP_WR(alg_adr, alg, cmd_bypass, alg->cmd_bypass);
|
||||
CHIP_WR(alg_adr, alg, cmd_resbypass1, alg->cmd_resbypass1);
|
||||
CHIP_WR(alg_adr, alg, cmd_resbypass2, alg->cmd_resbypass2);
|
||||
CHIP_WR(alg_adr, alg, timeout_mask, alg->timeout_mask);
|
||||
|
||||
return alg_adr + sizeof(*alg);
|
||||
}
|
||||
|
||||
void
|
||||
init_flash29(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, sizeof(chiptype_t),
|
||||
download_struct,
|
||||
flash29_search_chip,
|
||||
flash29_erase, 0, flash29_erase_wait, flash29_prog,
|
||||
prog_entry);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
init_flash29(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, 0, 0, 0,
|
||||
flash29_erase, 0, flash29_erase_wait, flash29_prog, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
47
m68k/flashlib/flash29.h
Normal file
47
m68k/flashlib/flash29.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* $Id: flash29.h,v 1.2 2008/07/31 01:53:44 cjohns Exp $
|
||||
*
|
||||
* Header for 29Fxxx and 49Fxxx flash driver.
|
||||
*
|
||||
* 2003-12-28 Josef Wolf (jw@raven.inka.de)
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This function will be called by flash_filter and is responsible to register
|
||||
the driver
|
||||
*/
|
||||
void init_flash29(int num);
|
||||
|
||||
/* following #define's should probably be set by configure
|
||||
*/
|
||||
|
||||
/* Setting this to 0 produces more generic (and compact) code which is able
|
||||
to program all bus widths at the expense of performance. Setting this
|
||||
to 1 approximately doubles the programming speed on a 20MHz 68332 with
|
||||
Am29F400 in 16-bit-mode.
|
||||
*/
|
||||
#define FLASH_OPTIMIZE_FOR_SPEED 0
|
||||
|
||||
/* When FLASH_OPTIMIZE_FOR_SPEED==1, selecting only required bus widths can
|
||||
reduce size of generated code
|
||||
*/
|
||||
#define FLASH_BUS_WIDTH1 1
|
||||
#define FLASH_BUS_WIDTH2 1
|
||||
#define FLASH_BUS_WIDTH4 1
|
||||
|
||||
#if FLASH_OPTIMIZE_FOR_SPEED
|
||||
# if ( !FLASH_BUS_WIDTH1 && !FLASH_BUS_WIDTH2 && !FLASH_BUS_WIDTH4 )
|
||||
# error At least one bus width must be defined when FLASH_OPTIMIZE_FOR_SPEED!=0
|
||||
# endif
|
||||
#endif
|
||||
654
m68k/flashlib/flash_filter.c
Normal file
654
m68k/flashlib/flash_filter.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/* $Id: flash_filter.c,v 1.7 2008/09/09 11:48:50 cjohns Exp $
|
||||
*
|
||||
* Flash filtering layer.
|
||||
*
|
||||
* 2003-12-28 Josef Wolf (jw@raven.inka.de)
|
||||
* 2008 Chris Johns (cjohns@users.sourceforge.net)
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This code was inspired by the filtering code from Pavel Pisa. But it was
|
||||
written from scratch to achieve stronger data encapsulation and enable
|
||||
target-mode plugins. For the long run, it should be extended for
|
||||
target-only operation mode.
|
||||
|
||||
CCJ : Remove BFD support and replaced with libelf.
|
||||
*/
|
||||
|
||||
#include "flash29.h"
|
||||
#include "flashcfm.h"
|
||||
#include "flashintelc3.h"
|
||||
#include "flash_filter.h"
|
||||
|
||||
#if HOST_FLASHING
|
||||
# include <errno.h>
|
||||
# include <stdint.h>
|
||||
# include <stdio.h>
|
||||
# include <limits.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
# include <elf-utils.h>
|
||||
# include <BDMlib.h>
|
||||
#endif
|
||||
|
||||
#define mkstring(_s) #_s
|
||||
|
||||
/* Interface to flash modules.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void (*init) (int);
|
||||
int struct_size;
|
||||
char *driver_magic;
|
||||
int (*download_struct) (void *, uint32_t);
|
||||
uint32_t (*search_chip) (void *, char *, uint32_t);
|
||||
void (*erase) (void *, int32_t);
|
||||
int (*blank_chk) (void *, int32_t);
|
||||
int (*erase_wait) (void *);
|
||||
uint32_t (*prog) (void *, uint32_t, unsigned char *, uint32_t);
|
||||
char *(*prog_entry) (void);
|
||||
unsigned char *p_code;
|
||||
uint32_t p_entry;
|
||||
uint32_t p_len;
|
||||
uint32_t ram;
|
||||
uint32_t len;
|
||||
} alg_t;
|
||||
|
||||
/* Known flashing algorithms
|
||||
*/
|
||||
alg_t algorithm[] = {
|
||||
{init_flash29},
|
||||
{init_flashcfm},
|
||||
{init_flashintelc3},
|
||||
};
|
||||
|
||||
/* Description of memory areas.
|
||||
*/
|
||||
typedef struct area_s
|
||||
{
|
||||
uint32_t adr;
|
||||
uint32_t end; /* last byte inclusive */
|
||||
alg_t *alg;
|
||||
void *chip_descriptor;
|
||||
struct area_s *next;
|
||||
} area_t;
|
||||
|
||||
/* Memory areas. Assume RAM for unregistered areas.
|
||||
*/
|
||||
static area_t ram_area = { 0, ~0, NULL, NULL, NULL, };
|
||||
static area_t *area = NULL;
|
||||
|
||||
/* Maximum size of a chip_descriptor. Since the chip-descriptor is algorithm's
|
||||
internal information, we don't know the size of the descriptor until we
|
||||
know which algorithm to use. Therefore we need to allocate a maximum size
|
||||
for autodetection.
|
||||
*/
|
||||
static int maxsiz = 0;
|
||||
|
||||
/* Variables.
|
||||
*/
|
||||
typedef struct variable_s
|
||||
{
|
||||
struct variable_s *next;
|
||||
const char *name;
|
||||
uint32_t value;
|
||||
} variable_t;
|
||||
|
||||
static variable_t *s_variables = 0;
|
||||
|
||||
/* Initialize all known algorithms, determine maximum size of chip descriptors
|
||||
and register RAM for whole address range.
|
||||
*/
|
||||
static void
|
||||
init (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (area)
|
||||
return; /* Already initialized */
|
||||
|
||||
for (i = 0; i < NUMOF(algorithm); i++) {
|
||||
algorithm[i].p_code = 0;
|
||||
algorithm[i].init(i);
|
||||
if (maxsiz < algorithm[i].struct_size)
|
||||
maxsiz = algorithm[i].struct_size;
|
||||
}
|
||||
|
||||
area = &ram_area; /* register RAM fallback for whole address range */
|
||||
}
|
||||
|
||||
/* This is the callback for the init functions of the basic flash modules.
|
||||
Each flash module shall register itself with this function.
|
||||
Doing it this way keeps algorithm's private data private and minimizes
|
||||
pollution of namespace.
|
||||
*/
|
||||
void
|
||||
register_algorithm(int num,
|
||||
char *driver_magic,
|
||||
int struct_size,
|
||||
int (*download_struct) (void *, uint32_t),
|
||||
uint32_t (*search_chip) (void *, char *, uint32_t),
|
||||
void (*erase) (void *, int32_t),
|
||||
int (*blank_chk) (void *, int32_t),
|
||||
int (*erase_wait) (void *),
|
||||
uint32_t (*prog) (void *, uint32_t, unsigned char *,
|
||||
uint32_t), char *(*prog_entry) (void))
|
||||
{
|
||||
algorithm[num].driver_magic = strdup(driver_magic); /* FIXME */
|
||||
algorithm[num].struct_size = struct_size;
|
||||
algorithm[num].download_struct = download_struct;
|
||||
algorithm[num].search_chip = search_chip;
|
||||
algorithm[num].erase = erase;
|
||||
algorithm[num].blank_chk = blank_chk;
|
||||
algorithm[num].erase_wait = erase_wait;
|
||||
algorithm[num].prog = prog;
|
||||
algorithm[num].prog_entry = prog_entry;
|
||||
|
||||
algorithm[num].p_code = NULL;
|
||||
algorithm[num].p_entry = 0;
|
||||
algorithm[num].p_len = 0;
|
||||
algorithm[num].ram = 0;
|
||||
algorithm[num].len = 0;
|
||||
}
|
||||
|
||||
/* Search memory area where ADR belongs to.
|
||||
*/
|
||||
static area_t *
|
||||
search_area (adr)
|
||||
{
|
||||
area_t *a;
|
||||
|
||||
for (a = area; a; a = a->next)
|
||||
if (a->adr <= adr && a->end >= adr)
|
||||
return a;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
/* register target flash plugins. The adr/len defines a RAM area on the
|
||||
target that can be used to download plugin and contents.
|
||||
*/
|
||||
int
|
||||
elf_flash_plugin_load(int (*prfunc) (const char *format, ...),
|
||||
uint32_t adr, uint32_t len, const char *fname)
|
||||
{
|
||||
struct stat sb;
|
||||
elf_handle handle;
|
||||
const char *dmagic;
|
||||
const char* prefix = mkstring (PREFIX);
|
||||
char* name = (char*) fname;
|
||||
int i;
|
||||
|
||||
elf_handle_init(&handle);
|
||||
|
||||
if (name[0] != '/')
|
||||
{
|
||||
if (stat (name, &sb) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
if (prefix[strlen (prefix) - 1] != '/')
|
||||
{
|
||||
name = strdup (prefix);
|
||||
name = strcat (name, "/");
|
||||
}
|
||||
else
|
||||
name = strdup (prefix);
|
||||
|
||||
name = strcat (name, "share/m68k-bdm/plugins/");
|
||||
name = strcat (name, fname);
|
||||
|
||||
if (stat (name, &sb) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
prfunc ("cannot find plugin: %s\n", fname);
|
||||
prfunc ("searched:\n .\n %s: ", mkstring (PREFIX));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!elf_open (name, &handle, prfunc))
|
||||
{
|
||||
if (prfunc)
|
||||
prfunc ("open %s failed", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dmagic = elf_get_section_data_sym(&handle, "driver_magic");
|
||||
|
||||
if (!dmagic)
|
||||
{
|
||||
if (prfunc)
|
||||
prfunc ("no 'driver_magic' symbol found");
|
||||
elf_close (&handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMOF(algorithm); i++)
|
||||
{
|
||||
uint32_t value;
|
||||
GElf_Sym entrysym;
|
||||
GElf_Shdr shdr;
|
||||
void *data;
|
||||
uint32_t size;
|
||||
|
||||
if (!STREQ(dmagic, algorithm[i].driver_magic))
|
||||
continue;
|
||||
|
||||
if (!elf_get_symbol(&handle, algorithm[i].prog_entry(), &entrysym))
|
||||
{
|
||||
if (prfunc)
|
||||
prfunc("could not find prog entry symbol %s",
|
||||
algorithm[i].prog_entry());
|
||||
elf_close(&handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!elf_get_section_hdr(&handle, entrysym.st_shndx, &shdr))
|
||||
{
|
||||
if (prfunc)
|
||||
prfunc("could not get section header for prog entry");
|
||||
elf_close(&handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data = elf_get_section_data(&handle, entrysym.st_shndx, &size);
|
||||
if (!data)
|
||||
{
|
||||
if (prfunc)
|
||||
prfunc("could not get section data for prog entry");
|
||||
elf_close(&handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
algorithm[i].p_entry = entrysym.st_value;
|
||||
algorithm[i].p_len = size;
|
||||
algorithm[i].p_code = malloc(size);
|
||||
memcpy(algorithm[i].p_code, data, size);
|
||||
|
||||
algorithm[i].ram = adr;
|
||||
algorithm[i].len = len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (prfunc)
|
||||
{
|
||||
if (i < NUMOF(algorithm))
|
||||
prfunc("%s loaded, size:%d", dmagic, algorithm[i].p_len);
|
||||
else
|
||||
prfunc("no algorithm %s found", dmagic);
|
||||
}
|
||||
|
||||
elf_close(&handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
srec_flash_plugin_load(int (*prfunc) (const char *format, ...),
|
||||
uint32_t adr, uint32_t len, const char *fname)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_plugin(int (*prfunc) (const char *format, ...),
|
||||
uint32_t adr, uint32_t len, char *argv[])
|
||||
{
|
||||
int cnt;
|
||||
|
||||
init();
|
||||
|
||||
for (cnt = 0; argv[cnt]; cnt++)
|
||||
{
|
||||
if (!elf_flash_plugin_load(prfunc, adr, len, argv[cnt]))
|
||||
if (!srec_flash_plugin_load(prfunc, adr, len, argv[cnt]))
|
||||
if (prfunc)
|
||||
prfunc("no suitable loader found: %s", argv[cnt]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int
|
||||
prog_clone(area_t * area, uint32_t adr, unsigned char *data, uint32_t size)
|
||||
{
|
||||
#if HOST_FLASHING
|
||||
char driver_magic[1024]; /* FIXME: should be dynamically */
|
||||
uint32_t mem;
|
||||
uint32_t len;
|
||||
static uint32_t entry = 0;
|
||||
static uint32_t content = 0;
|
||||
static area_t *last_area = NULL;
|
||||
uint32_t sp, ra;
|
||||
uint32_t sent = 0;
|
||||
uint32_t num;
|
||||
unsigned long wrote_num = 0;
|
||||
int cpu_type;
|
||||
|
||||
if (!area->alg)
|
||||
return 0;
|
||||
if (bdmGetProcessor(&cpu_type) < 0)
|
||||
return 0;
|
||||
|
||||
if (!area->alg->p_code) {
|
||||
/* No plugin loaded -> use host-only mode. */
|
||||
return area->alg->prog (area->chip_descriptor, adr, data, size);
|
||||
}
|
||||
|
||||
mem = area->alg->ram;
|
||||
len = area->alg->len;
|
||||
|
||||
if (area != last_area) {
|
||||
/* Download plugin and chip descriptor into target. */
|
||||
entry = area->alg->download_struct (area->chip_descriptor, mem);
|
||||
bdmWriteMemory (entry, area->alg->p_code, area->alg->p_len);
|
||||
content = entry + area->alg->p_len;
|
||||
last_area = area;
|
||||
}
|
||||
|
||||
while (sent < size) {
|
||||
sp = mem + len;
|
||||
|
||||
num = sp - 0x200 - content; /* FIXME: stack size should be
|
||||
determined dynamically */
|
||||
if (num > size - sent)
|
||||
num = size - sent;
|
||||
|
||||
/* Set up stack frame.
|
||||
* Be careful with the longword writes, they must be longword aligned!
|
||||
*/
|
||||
switch (cpu_type) {
|
||||
case BDM_CPU32:
|
||||
sp -= 4;
|
||||
ra = sp;
|
||||
bdmWriteWord (sp, 0x4afa); /* BGND instruction */
|
||||
break;
|
||||
case BDM_COLDFIRE:
|
||||
sp -= 4;
|
||||
ra = sp;
|
||||
bdmWriteWord (sp, 0x4ac8); /* HALT instruction */
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sp -= 4;
|
||||
bdmWriteLongWord (sp, num); /* amount of data to flash */
|
||||
sp -= 4;
|
||||
bdmWriteLongWord (sp, content); /* adr of memory contents */
|
||||
sp -= 4;
|
||||
bdmWriteLongWord (sp, adr); /* destination adr */
|
||||
sp -= 4;
|
||||
bdmWriteLongWord (sp, mem); /* chip descriptor */
|
||||
sp -= 4;
|
||||
bdmWriteLongWord (sp, ra); /* return address to BGND */
|
||||
|
||||
/* Download contents. */
|
||||
bdmWriteMemory (content, data, num);
|
||||
|
||||
/* Set stack pointer and program counter. */
|
||||
bdmWriteRegister(BDM_REG_A7, sp);
|
||||
bdmWriteSystemRegister(BDM_REG_RPC, entry + area->alg->p_entry);
|
||||
|
||||
/* Execute */
|
||||
bdmGo();
|
||||
while (!((bdmStatus ()) & (BDM_TARGETSTOPPED | BDM_TARGETHALT))) ;
|
||||
|
||||
bdmReadRegister (BDM_REG_D0, &wrote_num);
|
||||
|
||||
if (num != (uint32_t) wrote_num) {
|
||||
printf ("Returned 0x%08x\n", wrote_num);
|
||||
break; /* write failed */
|
||||
}
|
||||
|
||||
sent += num;
|
||||
data += num;
|
||||
adr += num;
|
||||
}
|
||||
#else
|
||||
/* FIXME: to be done */
|
||||
#endif
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
/* Register a new memory region. The new region should always overlap with
|
||||
the RAM fallback (which is registered by the init function). The overlap
|
||||
is resolved by shrinking/splitting the RAM fallback area. Returns 1 on
|
||||
success, 0 otherwise.
|
||||
*/
|
||||
int
|
||||
flash_register(char *description, uint32_t adr, char *hint_driver)
|
||||
{
|
||||
int i;
|
||||
uint32_t size;
|
||||
area_t *bold, *new, *aold; /* order is _b_efore, new, _a_fter */
|
||||
void *chip;
|
||||
|
||||
init();
|
||||
if (!(chip = malloc (maxsiz)))
|
||||
return 0;
|
||||
|
||||
/* Search area where the address belongs to. The result should be the RAM
|
||||
fallback. */
|
||||
bold = search_area(adr);
|
||||
|
||||
for (i = 0; i < NUMOF(algorithm); i++) {
|
||||
if (hint_driver != NULL) {
|
||||
if (!STREQ(hint_driver, algorithm[i].driver_magic))
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((size = algorithm[i].search_chip(chip, description, adr))) {
|
||||
if (bold->end > adr + (size - 1)) {
|
||||
/* End of old area is bigger than end of new area -> add new area of
|
||||
old style behind new area. */
|
||||
if (!(aold = malloc(sizeof(*aold))))
|
||||
break;
|
||||
*aold = *bold;
|
||||
aold->adr = adr + size;
|
||||
aold->next = bold->next;
|
||||
bold->next = aold;
|
||||
}
|
||||
if (bold->adr < adr) {
|
||||
/* start of old area is less than start of new area -> add new area
|
||||
of old style in front of new area. */
|
||||
if (!(new = malloc(sizeof(*new))))
|
||||
return 0;
|
||||
new->next = bold->next; /* insert new area into chain */
|
||||
bold->next = new;
|
||||
bold->end = adr - 1; /* shrink old area */
|
||||
} else {
|
||||
new = bold; /* same start address -> just replace old area */
|
||||
}
|
||||
|
||||
/* fill new area with contents */
|
||||
new->adr = adr;
|
||||
new->end = adr + (size - 1);
|
||||
new->alg = &algorithm[i];
|
||||
new->chip_descriptor = chip;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search area of address and call its erase algorithm.
|
||||
*/
|
||||
int
|
||||
flash_erase(uint32_t adr, int32_t sector_offset)
|
||||
{
|
||||
area_t *a;
|
||||
alg_t *alg;
|
||||
|
||||
if (!(a = search_area(adr)))
|
||||
return 0;
|
||||
|
||||
if (alg = a->alg) {
|
||||
if (alg->erase) {
|
||||
alg->erase(a->chip_descriptor, sector_offset);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search area of address and call its blank check algorithm.
|
||||
*/
|
||||
int
|
||||
flash_blank_chk(uint32_t adr, int32_t sector_offset)
|
||||
{
|
||||
area_t *a;
|
||||
alg_t *alg;
|
||||
|
||||
if (!(a = search_area(adr)))
|
||||
return 0;
|
||||
|
||||
if (alg = a->alg) {
|
||||
if (alg->blank_chk) {
|
||||
return alg->blank_chk(a->chip_descriptor, sector_offset);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search area of address and call its erase_wait algorithm.
|
||||
*/
|
||||
int
|
||||
flash_erase_wait(uint32_t adr)
|
||||
{
|
||||
area_t *a;
|
||||
alg_t *alg;
|
||||
|
||||
if (!(a = search_area(adr)))
|
||||
return 0;
|
||||
|
||||
if (alg = a->alg) {
|
||||
if (alg->erase_wait) {
|
||||
return alg->erase_wait(a->chip_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write to memory through registered algorithms.
|
||||
*/
|
||||
uint32_t
|
||||
write_memory(uint32_t adr, unsigned char *data, uint32_t cnt)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t wrote = 0;
|
||||
|
||||
init();
|
||||
|
||||
while (wrote < cnt) {
|
||||
area_t *area = search_area(adr + wrote);
|
||||
|
||||
/* That much fits into this area. */
|
||||
uint32_t size = (area->end - (adr + wrote)) + 1;
|
||||
|
||||
/* Limit size if it is more than we actually want to write. */
|
||||
if (size > cnt - wrote)
|
||||
size = cnt - wrote;
|
||||
|
||||
if (area->alg && area->alg->prog) {
|
||||
ret = prog_clone(area, adr, data, size);
|
||||
wrote += ret;
|
||||
if (ret != size)
|
||||
return wrote;
|
||||
} else {
|
||||
/* no programming algorithm defined, assume RAM */
|
||||
#if HOST_FLASHING
|
||||
if (bdmWriteMemory(adr, data, size) < 0)
|
||||
return wrote;
|
||||
#else
|
||||
memcpy((unsigned char *) adr, data, size);
|
||||
#endif
|
||||
wrote += size;
|
||||
}
|
||||
}
|
||||
return wrote;
|
||||
}
|
||||
|
||||
int
|
||||
flash_set_var(const char *name, uint32_t value)
|
||||
{
|
||||
/* find and update existing var */
|
||||
variable_t *var = s_variables;
|
||||
while(var) {
|
||||
if(strcmp(var->name, name) == 0) {
|
||||
var->value = value;
|
||||
return 1;
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
|
||||
/* add a new var */
|
||||
var = (variable_t *) malloc(sizeof(variable_t));
|
||||
if(!var)
|
||||
return 0;
|
||||
var->name = strdup(name);
|
||||
if(!var->name)
|
||||
return 0;
|
||||
var->value = value;
|
||||
var->next = s_variables;
|
||||
s_variables = var;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
flash_get_var(const char *name, uint32_t *value, uint32_t value_default)
|
||||
{
|
||||
variable_t *var = s_variables;
|
||||
while(var) {
|
||||
if(strcmp(var->name, name) == 0) {
|
||||
*value = var->value;
|
||||
return 1;
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
*value = value_default;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
flash_spin(int c)
|
||||
{
|
||||
#if HOST_FLASHING
|
||||
const char spin[] = {'|', '/', '-', '\\'};
|
||||
int n = c / 100;
|
||||
printf("\b%c", spin[n % 4]);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
return ++c;
|
||||
}
|
||||
79
m68k/flashlib/flash_filter.h
Normal file
79
m68k/flashlib/flash_filter.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* $Id: flash_filter.h,v 1.4 2008/07/31 01:53:44 cjohns Exp $
|
||||
*
|
||||
* Header for the flash filtering layer.
|
||||
*
|
||||
* 2003-12-28 Josef Wolf (jw@raven.inka.de)
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _FLASH_FILTER_H_
|
||||
# define _FLASH_FILTER_H_
|
||||
|
||||
# include <stdint.h>
|
||||
|
||||
/* This one should be removed in the long term.
|
||||
*/
|
||||
# ifndef HOST_FLASHING
|
||||
# define HOST_FLASHING 1
|
||||
# endif
|
||||
|
||||
# ifndef STREQ
|
||||
# define STREQ(a,b) (!strcmp((a),(b)))
|
||||
# endif
|
||||
|
||||
# ifndef NUMOF
|
||||
# define NUMOF(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||
# endif
|
||||
|
||||
/* A driver need to register itself with this function
|
||||
*/
|
||||
void register_algorithm(int num, /* number that was passed to init function */
|
||||
char *driver_magic,
|
||||
/* size of the chip description structure */
|
||||
int struct_size,
|
||||
/* dnload chip-descr */
|
||||
int (*download_struct) (void *, uint32_t),
|
||||
uint32_t (*search_chip) (void *, char *, uint32_t),
|
||||
void (*erase) (void *, int32_t),
|
||||
int (*blank_chk) (void *, int32_t),
|
||||
int (*erase_wait) (void *),
|
||||
uint32_t (*prog) (void *, uint32_t,
|
||||
unsigned char *, uint32_t),
|
||||
/* returns the name of the entry function */
|
||||
char *(*prog_entry) (void)
|
||||
);
|
||||
|
||||
/* Load target drivers. ADR and LEN define memory region in the target that
|
||||
can be used for downloading code/data.
|
||||
*/
|
||||
int flash_plugin (int (*prfunc) (const char *format, ...),
|
||||
uint32_t adr, uint32_t len, char *argv[]);
|
||||
|
||||
/* Register a flash chip on ADR
|
||||
*/
|
||||
int flash_register (char *description, uint32_t adr, char *hint_driver);
|
||||
|
||||
int flash_erase (uint32_t adr, int32_t sec_adr);
|
||||
int flash_blank_chk (uint32_t adr, int32_t sec_adr);
|
||||
int flash_erase_wait (uint32_t adr);
|
||||
|
||||
uint32_t write_memory (uint32_t adr, unsigned char *data, uint32_t cnt);
|
||||
|
||||
int flash_set_var (const char *name, uint32_t value);
|
||||
int flash_get_var (const char *name, uint32_t *value, uint32_t value_default);
|
||||
|
||||
int flash_spin (int c);
|
||||
|
||||
#endif
|
||||
364
m68k/flashlib/flashcfm.c
Normal file
364
m68k/flashlib/flashcfm.c
Normal file
@@ -0,0 +1,364 @@
|
||||
/* $Id:
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "flashcfm.h"
|
||||
#include "flash_filter.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if HOST_FLASHING
|
||||
# include <stdio.h>
|
||||
# include <BDMlib.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#define MCF_CFM_CFMCLKD_DIVLD (0x80)
|
||||
|
||||
#define MCF_CFM_CFMUSTAT_BLANK (0x04)
|
||||
#define MCF_CFM_CFMUSTAT_CCIF (0x40)
|
||||
#define MCF_CFM_CFMUSTAT_CBEIF (0x80)
|
||||
|
||||
#define MCF_CFM_CFMCMD_BLANK_CHECK (0x5)
|
||||
#define MCF_CFM_CFMCMD_PAGE_ERASE_VERIFY (0x6)
|
||||
#define MCF_CFM_CFMCMD_WORD_PROGRAM (0x20)
|
||||
#define MCF_CFM_CFMCMD_PAGE_ERASE (0x40)
|
||||
#define MCF_CFM_CFMCMD_MASS_ERASE (0x41)
|
||||
|
||||
/*
|
||||
* Warning! do not change this struct without changing the download_struct
|
||||
* function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t backdoor_address_start;
|
||||
uint32_t backdoor_address_end;
|
||||
uint32_t flash_address;
|
||||
uint32_t flash_size;
|
||||
uint32_t ipsbar;
|
||||
uint32_t cfmclkd;
|
||||
uint32_t cfmustat;
|
||||
uint32_t cfmcmd;
|
||||
} chiptype_t;
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
static inline uint8_t
|
||||
read_byte(uint32_t a_addr)
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
if (bdmReadByte(a_addr, &result) < 0)
|
||||
fprintf(stderr, "read_byte(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
return (uint8_t) result;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
read_word(uint32_t a_addr)
|
||||
{
|
||||
unsigned short result;
|
||||
|
||||
if (bdmReadWord(a_addr, &result) < 0)
|
||||
fprintf(stderr, "read_word(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
return (uint16_t) result;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
read_longword(uint32_t a_addr)
|
||||
{
|
||||
unsigned long result;
|
||||
|
||||
if (bdmReadLongWord(a_addr, &result) < 0)
|
||||
fprintf(stderr, "read_longword(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
return (uint32_t) result;
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_byte(uint32_t a_addr, uint8_t a_x)
|
||||
{
|
||||
if (bdmWriteByte(a_addr, a_x) < 0)
|
||||
fprintf(stderr, "write_byte(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_word(uint32_t a_addr, uint16_t a_x)
|
||||
{
|
||||
if (bdmWriteWord(a_addr, a_x) < 0)
|
||||
fprintf(stderr, "write_word(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_longword(uint32_t a_addr, uint32_t a_x)
|
||||
{
|
||||
if (bdmWriteLongWord(a_addr, a_x) < 0)
|
||||
fprintf(stderr, "write_longword(0x%08x): %s\n", a_addr, bdmErrorString());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define read_byte(A) (*((volatile uint8_t *) (A)))
|
||||
# define read_word(A) (*((volatile uint16_t *) (A)))
|
||||
# define read_longword(A) (*((volatile uint32_t *) (A)))
|
||||
# define write_byte(A, B) *((volatile uint8_t *)(A)) = (B)
|
||||
# define write_word(A, B) *((volatile uint16_t *)(A)) = (B)
|
||||
# define write_longword(A, B) *((volatile uint32_t *)(A)) = (B)
|
||||
|
||||
#endif
|
||||
|
||||
static inline uint32_t
|
||||
swap32(uint32_t a_v)
|
||||
{
|
||||
return (uint32_t) (((a_v >> 24) & 0x000000ff) | ((a_v << 24) & 0xff000000) |
|
||||
((a_v >> 8) & 0x0000ff00) | ((a_v << 8) & 0x00ff0000));
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_little_endian(void)
|
||||
{
|
||||
uint32_t i = 1;
|
||||
return (int) *((uint8_t *) &i);
|
||||
}
|
||||
|
||||
/* We need a unique symbol to associate a (target-based) plugin with its
|
||||
(host-based) driver.
|
||||
*/
|
||||
static char driver_magic[] = "flashcfm";
|
||||
|
||||
#if HOST_FLASHING
|
||||
static char *
|
||||
prog_entry(void)
|
||||
{
|
||||
return "flashcfm_prog";
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The actual programming function.
|
||||
* NOTE: pos and cnt need to be 4 byte aligned!
|
||||
*/
|
||||
static uint32_t
|
||||
flashcfm_prog(void *chip_descr,
|
||||
uint32_t pos, unsigned char *data, uint32_t cnt)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
uint32_t offset = ct->backdoor_address_start + (pos - ct->flash_address);
|
||||
uint32_t n = 0;
|
||||
|
||||
cnt /= 4;
|
||||
|
||||
if (read_byte(ct->cfmclkd) & MCF_CFM_CFMCLKD_DIVLD) {
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CBEIF)) {
|
||||
}
|
||||
|
||||
for (n = 0; n < cnt; ++n) {
|
||||
uint32_t d = ((uint32_t *) data)[n];
|
||||
|
||||
/* write_longword on host assumes host endianess so will perform a
|
||||
* byte order swap if host is little endian. we need to swap if little
|
||||
* endian such that the swap will just swap back to the correct endianess
|
||||
*/
|
||||
if(is_little_endian())
|
||||
d = swap32(d);
|
||||
write_longword(offset + n * 4, d);
|
||||
|
||||
write_byte(ct->cfmcmd, MCF_CFM_CFMCMD_WORD_PROGRAM);
|
||||
write_byte(ct->cfmustat, MCF_CFM_CFMUSTAT_CBEIF);
|
||||
|
||||
if (read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CBEIF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CCIF)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n * 4;
|
||||
}
|
||||
|
||||
/* Initiate erase operation. Sector address is relative to chip-base.
|
||||
With sector address==-1, the whole chip is erased. The erase operation
|
||||
can be called several times before flash_29_erase_wait() is called for
|
||||
simultanous erasure of multiple sectors.
|
||||
*/
|
||||
static void
|
||||
flashcfm_erase(void *chip_descr, int32_t sector_address)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
|
||||
if (read_byte(ct->cfmclkd) & MCF_CFM_CFMCLKD_DIVLD) {
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CBEIF)) {
|
||||
}
|
||||
|
||||
if (sector_address == -1) {
|
||||
write_longword(ct->backdoor_address_start, 0);
|
||||
write_byte(ct->cfmcmd, MCF_CFM_CFMCMD_MASS_ERASE);
|
||||
} else {
|
||||
write_longword(ct->backdoor_address_start +
|
||||
(sector_address - ct->flash_address), 0);
|
||||
write_byte(ct->cfmcmd, MCF_CFM_CFMCMD_PAGE_ERASE);
|
||||
}
|
||||
write_byte(ct->cfmustat, MCF_CFM_CFMUSTAT_CBEIF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Blank check operation. Sector address is relative to chip-base.
|
||||
With sector address==-1, the whole chip is checked.
|
||||
*/
|
||||
static int
|
||||
flashcfm_blank_chk(void *chip_descr, int32_t sector_address)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
int result = 0;
|
||||
|
||||
if (read_byte(ct->cfmclkd) & MCF_CFM_CFMCLKD_DIVLD) {
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CBEIF)) {
|
||||
}
|
||||
|
||||
if (sector_address == -1) {
|
||||
write_longword(ct->backdoor_address_start, 0);
|
||||
write_byte(ct->cfmcmd, MCF_CFM_CFMCMD_BLANK_CHECK);
|
||||
} else {
|
||||
write_longword(ct->backdoor_address_start +
|
||||
(sector_address - ct->flash_address), 0);
|
||||
write_byte(ct->cfmcmd, MCF_CFM_CFMCMD_PAGE_ERASE_VERIFY);
|
||||
}
|
||||
write_byte(ct->cfmustat, MCF_CFM_CFMUSTAT_CBEIF);
|
||||
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CCIF)) {
|
||||
}
|
||||
|
||||
if (read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_BLANK) {
|
||||
result = 1;
|
||||
write_byte(ct->cfmustat, MCF_CFM_CFMUSTAT_BLANK);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* wait for queued erasing operations to finish
|
||||
*/
|
||||
static int
|
||||
flashcfm_erase_wait(void *chip_descr)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
#if HOST_FLASHING
|
||||
int spin = 0;
|
||||
#endif
|
||||
|
||||
if (read_byte(ct->cfmclkd) & MCF_CFM_CFMCLKD_DIVLD) {
|
||||
while (!(read_byte(ct->cfmustat) & MCF_CFM_CFMUSTAT_CCIF)) {
|
||||
#if HOST_FLASHING
|
||||
spin = flash_spin(spin);
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
/* autodetect
|
||||
*/
|
||||
static uint32_t
|
||||
flashcfm_search_chip(void *chip_descr, char *description, uint32_t pos)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
|
||||
unsigned long flashbar = 0;
|
||||
uint32_t fbar_reg;
|
||||
|
||||
flash_get_var("%flashbar", &fbar_reg, 0x0c04);
|
||||
|
||||
if (bdmReadControlRegister(fbar_reg, &flashbar) >= 0) {
|
||||
if ((flashbar & 1) && ((flashbar & 0xfff80000) == pos)) {
|
||||
|
||||
flash_get_var("IPSBAR", &ct->ipsbar, 0x40000000);
|
||||
flash_get_var("FLASH_BACKDOOR", &ct->backdoor_address_start, 0x04000000);
|
||||
flash_get_var("FLASH_SIZE", &ct->flash_size, 256 * 1024);
|
||||
|
||||
ct->backdoor_address_start += ct->ipsbar;
|
||||
ct->backdoor_address_end = ct->backdoor_address_start +
|
||||
ct->flash_size;
|
||||
|
||||
flash_get_var("MCF_CFM_CFMCLKD", &ct->cfmclkd, 0x1D0002);
|
||||
flash_get_var("MCF_CFM_CFMUSTAT", &ct->cfmustat, 0x1D0020);
|
||||
flash_get_var("ct->cfmcmd", &ct->cfmcmd, 0x1D0024);
|
||||
|
||||
ct->cfmclkd += ct->ipsbar;
|
||||
ct->cfmustat += ct->ipsbar;
|
||||
ct->cfmcmd += ct->ipsbar;
|
||||
|
||||
ct->flash_address = pos;
|
||||
|
||||
if (description) {
|
||||
sprintf(description, "Coldfire flash module @ 0x%08lx..0x%08lx "
|
||||
"size:0x%08lx",
|
||||
pos, pos + ct->flash_size, ct->flash_size);
|
||||
}
|
||||
|
||||
return ct->flash_size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
download_struct(void *chip_descr, uint32_t adr)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
|
||||
bdmWriteLongWord(adr, ct->backdoor_address_start);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->backdoor_address_end);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->flash_address);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->flash_size);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->ipsbar);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->cfmclkd);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->cfmustat);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->cfmcmd);
|
||||
adr += 4;
|
||||
|
||||
return adr;
|
||||
}
|
||||
|
||||
void
|
||||
init_flashcfm(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, sizeof(chiptype_t),
|
||||
download_struct,
|
||||
flashcfm_search_chip,
|
||||
flashcfm_erase,
|
||||
flashcfm_blank_chk,
|
||||
flashcfm_erase_wait, flashcfm_prog, prog_entry);
|
||||
}
|
||||
#else
|
||||
void
|
||||
init_flashcfm(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, 0,
|
||||
0,
|
||||
0,
|
||||
flashcfm_erase,
|
||||
flashcfm_blank_chk,
|
||||
flashcfm_erase_wait, flashcfm_prog, 0);
|
||||
}
|
||||
#endif
|
||||
44
m68k/flashlib/flashcfm.h
Normal file
44
m68k/flashlib/flashcfm.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* $Id:
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To use the flashcfm algorithm:
|
||||
*
|
||||
* set the following flash varialbes (flash_set_var)
|
||||
*
|
||||
* varname (default) note
|
||||
* IPSBAR (0x40000000)
|
||||
* MCF_CFM_CFMCLKD (0x1D0002) ipsbar offset
|
||||
* MCF_CFM_CFMUSTAT (0x1D0020) ipsbar offset
|
||||
* MCF_CFM_CFMCMD (0x1D0024) ipsbar offset
|
||||
* FLASHBAR_REG (0x0C04)
|
||||
* FLASH_SIZE (256 * 1024)
|
||||
* FLASH_BACKDOOR (0x04000000) ipsbar offset
|
||||
*
|
||||
* NOTE: The target and flash clock must be setup to the correct flashing
|
||||
* frequency prior to invoking this flash algorithm
|
||||
*
|
||||
* NOTE: Flash detection simply checks flashbar, so flashbar must be configured
|
||||
* prior to calling flash_register
|
||||
*
|
||||
* NOTE: Flash addresses and write memory sizes need to be 4 byte aligned!
|
||||
*
|
||||
*/
|
||||
|
||||
/* This function will be called by flash_filter and is responsible to register
|
||||
the driver
|
||||
*/
|
||||
void init_flashcfm(int num);
|
||||
416
m68k/flashlib/flashintelc3.c
Normal file
416
m68k/flashlib/flashintelc3.c
Normal file
@@ -0,0 +1,416 @@
|
||||
/* $Id:
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "flashintelc3.h"
|
||||
#include "flash_filter.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if HOST_FLASHING
|
||||
# include <stdio.h>
|
||||
# include <BDMlib.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
const uint32_t manufacturer, device_id;
|
||||
const uint32_t size; /* in bytes */
|
||||
const uint32_t num_sectors;
|
||||
const uint32_t top;
|
||||
} chip_t;
|
||||
|
||||
/*
|
||||
* Warning! do not change this struct without changing the download_struct
|
||||
* function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t flash_address;
|
||||
uint32_t flash_size;
|
||||
uint32_t num_sectors;
|
||||
uint32_t top;
|
||||
} chiptype_t;
|
||||
|
||||
static const chip_t chips[] = {
|
||||
{"28F800C3T", 0x0089, 0x88C0, 0x100000, 23, 1}, /* INTEL */
|
||||
{"28F800C3B", 0x0089, 0x88C1, 0x100000, 23, 0}, /* INTEL */
|
||||
{"28F160C3T", 0x0089, 0x88C2, 0x200000, 39, 1}, /* INTEL */
|
||||
{"28F160C3B", 0x0089, 0x88C3, 0x200000, 39, 0}, /* INTEL */
|
||||
{"28F320C3T", 0x0089, 0x88C4, 0x400000, 71, 1}, /* INTEL */
|
||||
{"28F320C3B", 0x0089, 0x88C5, 0x400000, 71, 0}, /* INTEL */
|
||||
{"28F640C3T", 0x0089, 0x88CC, 0x800000, 135, 1}, /* INTEL */
|
||||
{"28F640C3B", 0x0089, 0x88CD, 0x800000, 135, 0}, /* INTEL */
|
||||
};
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
# define DEFINE_READ_FUNC(funcname,vartype,bdmfunc) \
|
||||
static uint32_t funcname (uint32_t adr) { \
|
||||
vartype val; \
|
||||
if (bdmfunc (adr, &val) < 0) \
|
||||
fprintf (stderr, #bdmfunc "(0x%08lx,xxx): %s\n", \
|
||||
adr, bdmErrorString()); \
|
||||
return (uint32_t) val; \
|
||||
}
|
||||
|
||||
# define DEFINE_WRITE_FUNC(funcname,vartype,bdmfunc) \
|
||||
static void funcname (uint32_t adr, uint32_t val) { \
|
||||
if (bdmfunc (adr, val) < 0) \
|
||||
fprintf (stderr, #bdmfunc "(0x%08lx,0x%08x): %s\n", \
|
||||
adr, val, bdmErrorString()); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define DEFINE_READ_FUNC(funcname,vartype,bdmfunc) \
|
||||
static uint32_t funcname (uint32_t adr) { \
|
||||
return *(volatile vartype *)adr; \
|
||||
}
|
||||
|
||||
# define DEFINE_WRITE_FUNC(funcname,vartype,bdmfunc) \
|
||||
static void funcname (uint32_t adr,uint32_t val) { \
|
||||
*(volatile vartype *)adr = val; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline uint16_t
|
||||
swap16(uint16_t a_v)
|
||||
{
|
||||
return (uint16_t) (((a_v >> 8) & 0x00ff) | ((a_v << 8) & 0xff00));
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_little_endian(void)
|
||||
{
|
||||
uint32_t i = 1;
|
||||
return (int) *((uint8_t *) &i);
|
||||
}
|
||||
|
||||
DEFINE_READ_FUNC(chip_rd_word, unsigned short, bdmReadWord)
|
||||
DEFINE_WRITE_FUNC(chip_wr_word, uint16_t, bdmWriteWord)
|
||||
|
||||
/* We need a unique symbol to associate a (target-based) plugin with its
|
||||
(host-based) driver.
|
||||
*/
|
||||
static char driver_magic[] = "flashintelc3";
|
||||
|
||||
#if HOST_FLASHING
|
||||
static char *
|
||||
prog_entry(void)
|
||||
{
|
||||
return "flashintelc3_prog";
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t
|
||||
flashintelc3_sector_size(chiptype_t* chip, int sector)
|
||||
{
|
||||
if(chip->top) {
|
||||
if(sector < (chip->num_sectors - 8)) {
|
||||
return 0x10000;
|
||||
}
|
||||
else {
|
||||
return 0x2000;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(sector < 8) {
|
||||
return 0x2000;
|
||||
}
|
||||
else {
|
||||
return 0x10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
flashintelc3_sector_offset(chiptype_t* chip, int sector)
|
||||
{
|
||||
if(chip->top) {
|
||||
uint32_t d = chip->num_sectors - 8;
|
||||
if(sector < d) {
|
||||
return 0x10000 * sector;
|
||||
}
|
||||
else {
|
||||
return (0x10000 * d) + (0x2000 * (sector - d));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(sector < 8) {
|
||||
return 0x2000 * sector;
|
||||
}
|
||||
else {
|
||||
return 0x10000 + (0x10000 * (sector - 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 0=unlock, 1=lock */
|
||||
static void
|
||||
flashintelc3_lock(void *chip_descr, uint32_t start, uint32_t bytes, int cmd)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
int i, s = 0, e = 0;
|
||||
int ucmd = (cmd) ? 0x01 : 0xD0;
|
||||
|
||||
if(bytes == 0)
|
||||
return;
|
||||
|
||||
/* find start sector */
|
||||
for(i = 0; i < ct->num_sectors; ++i) {
|
||||
uint32_t off = flashintelc3_sector_offset(ct, i);
|
||||
uint32_t size = flashintelc3_sector_size(ct, i);
|
||||
if((start >= ct->flash_address + off) &&
|
||||
(start < ct->flash_address + off + size)) {
|
||||
s = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* find end */
|
||||
for(; i < ct->num_sectors; ++i) {
|
||||
uint32_t off = flashintelc3_sector_offset(ct, i);
|
||||
uint32_t size = flashintelc3_sector_size(ct, i);
|
||||
if(start + bytes <= ct->flash_address + off + size) {
|
||||
e = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlock range */
|
||||
for(i = s; i <= e; ++i) {
|
||||
uint32_t off = flashintelc3_sector_offset(ct, i);
|
||||
chip_wr_word(ct->flash_address + off, 0x60);
|
||||
chip_wr_word(ct->flash_address + off, ucmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* The actual programming function.
|
||||
* NOTE: pos and cnt need to be 2 byte aligned!
|
||||
*/
|
||||
static uint32_t
|
||||
flashintelc3_prog(void *chip_descr,
|
||||
uint32_t pos, unsigned char *data, uint32_t cnt)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
uint32_t n = 0;
|
||||
uint16_t status;
|
||||
|
||||
flashintelc3_lock(ct, pos, cnt, 0);
|
||||
|
||||
cnt /= 2;
|
||||
for (n = 0; n < cnt; ++n) {
|
||||
uint16_t d = ((uint16_t *) (void*) data)[n];
|
||||
|
||||
chip_wr_word(pos, 0x40);
|
||||
|
||||
/* write_word on host assumes host endianess so will perform a
|
||||
* byte order swap if host is little endian. we need to swap if little
|
||||
* endian such that the swap will just swap back to the correct endianess
|
||||
*/
|
||||
if(is_little_endian())
|
||||
d = swap16(d);
|
||||
chip_wr_word(pos, d);
|
||||
|
||||
/*
|
||||
* Wait for program operation to finish
|
||||
*/
|
||||
do {
|
||||
chip_wr_word(pos, 0x70);
|
||||
status = chip_rd_word(pos);
|
||||
}
|
||||
while (!(status & 0x80));
|
||||
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
chip_wr_word(ct->flash_address, 0xff);
|
||||
|
||||
return n * 2;
|
||||
}
|
||||
|
||||
static void
|
||||
flashintelc3_erase(void *chip_descr, int32_t sector_address)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
uint16_t status;
|
||||
int i;
|
||||
#if HOST_FLASHING
|
||||
int spin = 0;
|
||||
#endif
|
||||
|
||||
if(sector_address == -1) {
|
||||
flashintelc3_lock(ct, ct->flash_address, ct->flash_size, 0);
|
||||
|
||||
/* erasing all sectors */
|
||||
for(i = 0; i < ct->num_sectors; ++i) {
|
||||
uint32_t off = flashintelc3_sector_offset(ct, i);
|
||||
|
||||
chip_wr_word(ct->flash_address + off, 0x20);
|
||||
chip_wr_word(ct->flash_address + off, 0xD0);
|
||||
|
||||
/* wait */
|
||||
do {
|
||||
chip_wr_word(ct->flash_address + off, 0x70);
|
||||
status = chip_rd_word(ct->flash_address + off);
|
||||
#if HOST_FLASHING
|
||||
spin = flash_spin(spin);
|
||||
#endif
|
||||
} while(!(status & 0x80));
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32_t off = flashintelc3_sector_offset(ct, sector_address);
|
||||
flashintelc3_lock(ct, ct->flash_address + off, 1, 0);
|
||||
|
||||
/* erasing said sector address */
|
||||
chip_wr_word(ct->flash_address + off, 0x20);
|
||||
chip_wr_word(ct->flash_address + off, 0xD0);
|
||||
|
||||
/* wait */
|
||||
do {
|
||||
chip_wr_word(ct->flash_address + off, 0x70);
|
||||
status = chip_rd_word(ct->flash_address + off);
|
||||
#if HOST_FLASHING
|
||||
spin = flash_spin(spin);
|
||||
#endif
|
||||
} while(!(status & 0x80));
|
||||
}
|
||||
|
||||
chip_wr_word(ct->flash_address, 0xff);
|
||||
}
|
||||
|
||||
/* Blank check operation. Sector address is relative to chip-base.
|
||||
With sector address==-1, the whole chip is checked.
|
||||
*/
|
||||
static int
|
||||
flashintelc3_blank_chk(void *chip_descr, int32_t sector_address)
|
||||
{
|
||||
#if HOST_FLASHING
|
||||
printf("intelc3: blank_chk not implemented!\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* wait for queued erasing operations to finish
|
||||
*/
|
||||
static int
|
||||
flashintelc3_erase_wait(void *chip_descr)
|
||||
{
|
||||
#if HOST_FLASHING
|
||||
printf("intelc3: no wait needed!\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HOST_FLASHING
|
||||
|
||||
# ifndef NUMOF
|
||||
# define NUMOF(ary) (sizeof(ary)/sizeof(ary[0]))
|
||||
# endif
|
||||
|
||||
/* autodetect
|
||||
*/
|
||||
static uint32_t
|
||||
flashintelc3_search_chip(void *chip_descr, char *description, uint32_t pos)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
uint32_t m, d;
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
const chip_t *chip;
|
||||
int i;
|
||||
|
||||
/* read the manufacturer id */
|
||||
chip_wr_word(pos, 0x90);
|
||||
m = chip_rd_word(pos + 0);
|
||||
|
||||
/* read the device id */
|
||||
chip_wr_word(pos, 0x90);
|
||||
d = chip_rd_word(pos + 2);
|
||||
|
||||
/* find our device */
|
||||
for (i = 0; i < NUMOF(chips); i++) {
|
||||
chip = &chips[i];
|
||||
if(chip->manufacturer == m && chip->device_id == d) {
|
||||
ct->flash_address = pos;
|
||||
ct->flash_size = chip->size;
|
||||
ct->num_sectors = chip->num_sectors;
|
||||
ct->top = chip->top;
|
||||
size = chip->size;
|
||||
|
||||
if (description) {
|
||||
sprintf(description, "%10s @ 0x%08lx..0x%08lx "
|
||||
"manuf:0x%02lx device:0x%04lx size:0x%08lx",
|
||||
chip->name, pos, pos + chip->size, m, d, chip->size);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* put the device back into read mode */
|
||||
chip_wr_word(pos, 0xff);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int
|
||||
download_struct(void *chip_descr, uint32_t adr)
|
||||
{
|
||||
chiptype_t *ct = (chiptype_t *) chip_descr;
|
||||
|
||||
bdmWriteLongWord(adr, ct->flash_address);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->flash_size);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->num_sectors);
|
||||
adr += 4;
|
||||
bdmWriteLongWord(adr, ct->top);
|
||||
adr += 4;
|
||||
|
||||
return adr;
|
||||
}
|
||||
|
||||
void
|
||||
init_flashintelc3(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, sizeof(chiptype_t),
|
||||
download_struct,
|
||||
flashintelc3_search_chip,
|
||||
flashintelc3_erase,
|
||||
flashintelc3_blank_chk,
|
||||
flashintelc3_erase_wait, flashintelc3_prog, prog_entry);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void
|
||||
init_flashintelc3(int num)
|
||||
{
|
||||
register_algorithm(num, driver_magic, 0,
|
||||
0,
|
||||
0,
|
||||
flashintelc3_erase,
|
||||
flashintelc3_blank_chk,
|
||||
flashintelc3_erase_wait, flashintelc3_prog, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
32
m68k/flashlib/flashintelc3.h
Normal file
32
m68k/flashlib/flashintelc3.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* $Id:
|
||||
*
|
||||
* Portions of this program which I authored may be used for any purpose
|
||||
* so long as this notice is left intact.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To use the flashintelc3 algorithm:
|
||||
*
|
||||
* NOTE: You'll need to setup any chip selects etc.
|
||||
*
|
||||
* NOTE: No need to use an erase wait command for batch erases. if doing
|
||||
* a sector erase you'll need to do an erase followed by an erase wait!
|
||||
*
|
||||
* NOTE: Flash addresses and write memory sizes need to be 4 byte aligned!
|
||||
*
|
||||
*/
|
||||
|
||||
/* This function will be called by flash_filter and is responsible to register
|
||||
the driver
|
||||
*/
|
||||
void init_flashintelc3(int num);
|
||||
21
m68k/flashlib/m68k-bdm-compile-plugin
Executable file
21
m68k/flashlib/m68k-bdm-compile-plugin
Executable file
@@ -0,0 +1,21 @@
|
||||
#! /bin/sh
|
||||
|
||||
CC=$1 # The m68k cross compiler.
|
||||
SRC=$2 # The source file.
|
||||
OUTPUT=$3 # The output file. Contains the CPU.
|
||||
|
||||
CPU=$(echo $OUTPUT | sed -e 's/.*-//g' -e 's/\..*//g')
|
||||
|
||||
PWARN="-pedantic -Wall -Wcast-align -Wstrict-prototypes -Wmissing-prototypes"
|
||||
POPT="-O2 -fomit-frame-pointer"
|
||||
PREL="-mpcrel"
|
||||
PDEF="-DHOST_FLASHING=0"
|
||||
PTGT="-mcpu=$CPU"
|
||||
|
||||
OPT="$PWARN $POPT $PREL $PDEF $PTGT"
|
||||
|
||||
CMD="$CC $OPT -c -o $OUTPUT $SRC"
|
||||
echo $CMD
|
||||
$CMD
|
||||
|
||||
exit $?
|
||||
Reference in New Issue
Block a user