diff --git a/jtag/ChangeLog b/jtag/ChangeLog index 48330aa2..a472d73b 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,6 +1,13 @@ 2008-01-18 Kolja Waschk - * Warning - the modification 1873220 is not yet completely done! + * Moved the code from libbrux/ subdirectory into appropriate locations in + our src/ subdirectory (Enhancement 1873220): + + libbrux/cmd/help.c -> src/cmd/help.c + libbrux/cmd/quit.c -> src/cmd/quit.c + libbrux/cmd/cmd.c + src/cmd.c -> src/cmd/cmd.c + libbrux/cmd/cmd_detectflash.c -> src/cmd/detectflash.c + libbrux/flash + Makefile.am -> src/flash/ * Merged the header files from openwince "include" package, which were previously moved in inclow/, into our final include/ directory, omitting @@ -9,13 +16,13 @@ common.h -> n/a (use bitmask.h!) openwince.h (asm/C detection) -> n/a (use #ifdef __ASSEMBLY__) openwince.h (bitmasks) -> bitmask.h - arm/pxa2x0/mc.h -> bus/pxa2x0.h - brux/bus.h -> bus/driver.h brux/cmd.h + cmd.h -> cmd.h - brux/cfi.h + brux/flash.h + cmd.h -> flash.h + brux/cfi.h + brux/flash.h+flash.h -> flash.h + brux/bus.h -> bus_driver.h std/mic.h -> flash/mic.h device/flash/cfi.h -> flash/cfi.h device/flash/intel.h -> flash/intel.h + arm/pxa2x0/mc.h -> src/bus/pxa2x0_mc.h 2008-01-17 Kolja Waschk diff --git a/jtag/Makefile.am b/jtag/Makefile.am index bdc9bb9d..bb618811 100644 --- a/jtag/Makefile.am +++ b/jtag/Makefile.am @@ -24,7 +24,6 @@ include $(top_srcdir)/Makefile.rules SUBDIRS = \ - libbrux \ doc \ include \ data \ @@ -32,7 +31,6 @@ SUBDIRS = \ po DIST_SUBDIRS = \ - inclow \ $(SUBDIRS) noinst_HEADERS = \ diff --git a/jtag/configure.ac b/jtag/configure.ac index 3f7491e6..ff51719d 100644 --- a/jtag/configure.ac +++ b/jtag/configure.ac @@ -66,6 +66,7 @@ AC_CONFIG_FILES( src/tap/Makefile src/part/Makefile src/bus/Makefile + src/flash/Makefile src/cmd/Makefile src/svf/Makefile src/bsdl/Makefile @@ -133,30 +134,6 @@ else AM_CONDITIONAL([BISON_LOCATIONS], false) fi -AC_CONFIG_SUBDIRS(libbrux) - -#AC_ARG_WITH(include, -# AC_HELP_STRING([--with-include=PATH], [Absolute path to the openwince includes]), -# openwince_inc="$withval") -#AC_CACHE_CHECK([for the openwince includes], openwince_includes_path, [ -# openwince_includes_path="no" -# for openwince_include in $openwince_inc /usr/include/openwince /usr/local/include/openwince; do -# if test -f "$openwince_include/common.h"; then -# openwince_includes_path="$openwince_include" -# break -# fi -# done -#]) -#if test "$openwince_includes_path" = "no"; then -# AC_MSG_ERROR([The openwince include package can not be found.]) -#fi -#CPPFLAGS="$CPPFLAGS -I$openwince_includes_path -I$openwince_includes_path/device -I$openwince_includes_path/arm" - -AC_CONFIG_SUBDIRS(inclow) -CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/inclow" -CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/inclow/device" -CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/inclow/arm" - AC_SEARCH_LIBS([ioperm], [ioperm]) if test "$ac_cv_search_ioperm" != "no"; then AC_DEFINE(HAVE_IOPERM, 1, [Define to 1 if you have the ioperm() function]) diff --git a/jtag/include/Makefile.am b/jtag/include/Makefile.am index 45bc22fe..f55194f3 100644 --- a/jtag/include/Makefile.am +++ b/jtag/include/Makefile.am @@ -26,12 +26,17 @@ include $(top_srcdir)/Makefile.rules noinst_HEADERS = \ bsbit.h \ bsdl.h \ + bitmask.h \ bus.h \ + bus_driver.h \ cable.h \ chain.h \ data_register.h \ cmd.h \ flash.h \ + flash/cfi.h \ + flash/mic.h \ + flash/intel.h \ gettext.h \ instruction.h \ parport.h \ diff --git a/jtag/include/bus.h b/jtag/include/bus.h index 7766c95a..b034ad39 100644 --- a/jtag/include/bus.h +++ b/jtag/include/bus.h @@ -29,7 +29,7 @@ #include #include "chain.h" -#include +#include typedef struct { int len; diff --git a/jtag/include/bus/driver.h b/jtag/include/bus_driver.h similarity index 100% rename from jtag/include/bus/driver.h rename to jtag/include/bus_driver.h diff --git a/jtag/include/flash.h b/jtag/include/flash.h index 0c802e33..2e65438c 100644 --- a/jtag/include/flash.h +++ b/jtag/include/flash.h @@ -37,14 +37,12 @@ #include #include -#include +#include /* Following moved here from brux/cfi.h */ #include -#include - typedef struct { int width; /* 1 for 8 bits, 2 for 16 bits, 4 for 32 bits, etc. */ cfi_query_structure_t cfi; diff --git a/jtag/include/flash/cfi.h b/jtag/include/flash/cfi.h index a0943c55..5d958f12 100644 --- a/jtag/include/flash/cfi.h +++ b/jtag/include/flash/cfi.h @@ -41,9 +41,7 @@ #ifndef FLASH_CFI_H #define FLASH_CFI_H -#include - -#if LANGUAGE == C +#ifndef __ASSEMBLY__ #include #endif @@ -62,14 +60,14 @@ #define ALT_VENDOR_ID_OFFSET 0x17 #define ALT_VENDOR_TABLE_ADR_OFFSET 0x19 -#if LANGUAGE == C +#ifndef __ASSEMBLY__ typedef struct cfi_query_identification_string { uint16_t pri_id_code; void *pri_vendor_tbl; uint16_t alt_id_code; void *alt_vendor_tbl; } cfi_query_identification_string_t; -#endif /* LANGUAGE == C */ +#endif /* __ASSEMBLY__ */ /* Algorithm command set & control interface ID codes - see Table 1 in [2] */ @@ -97,7 +95,7 @@ typedef struct cfi_query_identification_string { #define MAX_BLOCK_ERASE_TIMEOUT_OFFSET 0x25 /* Maximum timeout per individual block erase */ #define MAX_CHIP_ERASE_TIMEOUT_OFFSET 0x26 /* Maximum timeout for chip erase */ -#if LANGUAGE == C +#ifndef __ASSEMBLY__ typedef struct cfi_query_system_interface_information { uint16_t vcc_min_wev; /* in mV */ uint16_t vcc_max_wev; /* in mV */ @@ -112,7 +110,7 @@ typedef struct cfi_query_system_interface_information { uint32_t max_block_erase_timeout; /* in ms, 0 - not supported */ uint32_t max_chip_erase_timeout; /* in ms, 0 - not supported */ } cfi_query_system_interface_information_t; -#endif /* LANGUAGE == C */ +#endif /* __ASSEMBLY__ */ /* Device geometry definition - see 4.3.4 in [1] */ @@ -122,7 +120,7 @@ typedef struct cfi_query_system_interface_information { #define NUMBER_OF_ERASE_REGIONS_OFFSET 0x2C /* Number of Erase Block Regions */ #define ERASE_BLOCK_REGION_OFFSET 0x2D /* Erase Block Region Information */ -#if LANGUAGE == C +#ifndef __ASSEMBLY__ typedef struct cfi_erase_block_region cfi_erase_block_region_t; typedef struct cfi_device_geometry { @@ -137,7 +135,7 @@ struct cfi_erase_block_region { uint32_t erase_block_size; /* in B */ uint32_t number_of_erase_blocks; }; -#endif /* LANGUAGE == C */ +#endif /* __ASSEMBLY__ */ /* Device interface code assignments (for cfi_device_geometry.device_interface) - see Table 2 in [2] */ @@ -149,12 +147,12 @@ struct cfi_erase_block_region { /* CFI Query structure - see 4.3.1 in [1] */ -#if LANGUAGE == C +#ifndef __ASSEMBLY__ typedef struct cfi_query_structure { cfi_query_identification_string_t identification_string; cfi_query_system_interface_information_t system_interface_info; cfi_device_geometry_t device_geometry; } cfi_query_structure_t; -#endif /* LANGUAGE == C */ +#endif /* __ASSEMBLY__ */ #endif /* FLASH_CFI_H */ diff --git a/jtag/include/flash/intel.h b/jtag/include/flash/intel.h index 3a82e3c2..febdb482 100644 --- a/jtag/include/flash/intel.h +++ b/jtag/include/flash/intel.h @@ -40,7 +40,7 @@ #ifndef FLASH_INTEL_H #define FLASH_INTEL_H -#include +#include /* Intel CFI commands - see Table 4. in [1] and Table 3. in [2] */ diff --git a/jtag/include/jtag.h b/jtag/include/jtag.h index f2ee9fcb..967f374f 100644 --- a/jtag/include/jtag.h +++ b/jtag/include/jtag.h @@ -28,7 +28,7 @@ #include #include -#include +#include #include "chain.h" #include "bus.h" diff --git a/jtag/include/state.h b/jtag/include/state.h index 2ea7f73d..b8ae2873 100644 --- a/jtag/include/state.h +++ b/jtag/include/state.h @@ -25,7 +25,7 @@ #ifndef STATE_H #define STATE_H -#include +#include #include "chain.h" diff --git a/jtag/src/Makefile.am b/jtag/src/Makefile.am index 156498d5..c2666cc3 100644 --- a/jtag/src/Makefile.am +++ b/jtag/src/Makefile.am @@ -24,6 +24,7 @@ include $(top_srcdir)/Makefile.rules SUBDIRS = \ + flash \ lib \ tap \ part \ @@ -54,7 +55,7 @@ bsdl2jtag_SOURCES = \ bsdl2jtag.c jtag_DEPENDENCIES = \ - ../libbrux/libbrux.a \ + flash/libflash.a \ lib/libjtaglib.a \ tap/libtap.a \ part/libpart.a \ @@ -73,9 +74,8 @@ jtag_LDADD = \ -Ltap -ltap \ -Lpart -lpart \ -Llib -ljtaglib \ - -L../libbrux -lbrux \ + -Lflash -lflash \ -Lcmd -lcmd \ - -L../libbrux -lbrux \ -Lbus -lbus \ -lm \ @FTD2XXLIB@ \ diff --git a/jtag/src/bsdl/bsdl.c b/jtag/src/bsdl/bsdl.c index 0c57e97c..898754a7 100644 --- a/jtag/src/bsdl/bsdl.c +++ b/jtag/src/bsdl/bsdl.c @@ -34,7 +34,7 @@ #include "sysdep.h" #include -#include +#include #include "bsdl.h" diff --git a/jtag/src/bsdl/bsdl_sem.c b/jtag/src/bsdl/bsdl_sem.c index 51c71e0b..20e89857 100644 --- a/jtag/src/bsdl/bsdl_sem.c +++ b/jtag/src/bsdl/bsdl_sem.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "bsdl_bison.h" diff --git a/jtag/src/bus/Makefile.am b/jtag/src/bus/Makefile.am index bf98a017..edd62fa6 100644 --- a/jtag/src/bus/Makefile.am +++ b/jtag/src/bus/Makefile.am @@ -41,6 +41,7 @@ libbus_a_SOURCES = \ ppc405ep.c \ prototype.c \ pxa2x0.c \ + pxa2x0_mc.h \ sa1110.c \ s3c4510x.c \ sh7727.c \ diff --git a/jtag/src/bus/pxa2x0.c b/jtag/src/bus/pxa2x0.c index 19e062df..f07f4643 100644 --- a/jtag/src/bus/pxa2x0.c +++ b/jtag/src/bus/pxa2x0.c @@ -36,14 +36,15 @@ #include #include -#include - #include "part.h" #include "bus.h" #include "bssignal.h" #include "jtag.h" #include "buses.h" +#include "pxa2x0_mc.h" + + /* * the following defines are used in proc field of the the * bus_params_t structure and are used in various functions diff --git a/jtag/include/bus/pxa2x0.h b/jtag/src/bus/pxa2x0_mc.h similarity index 99% rename from jtag/include/bus/pxa2x0.h rename to jtag/src/bus/pxa2x0_mc.h index 63647d01..926e923c 100644 --- a/jtag/include/bus/pxa2x0.h +++ b/jtag/src/bus/pxa2x0_mc.h @@ -45,9 +45,9 @@ #ifndef PXA2X0_MC_H #define PXA2X0_MC_H -#include +#include -#if LANGUAGE == C +#ifndef __ASSEMBLY__ #include #endif @@ -63,7 +63,7 @@ #define MC_BASE 0x48000000 -#if LANGUAGE == C +#ifndef __ASSEMBLY__ typedef volatile struct MC_registers { uint32_t mdcnfg; uint32_t mdrefr; @@ -119,7 +119,7 @@ typedef volatile struct MC_registers { #if !defined(PXA2X0_NOPXA260) #define SA1111CR MC_pointer->sa1111cr #endif /* PXA260 and above only */ -#endif /* LANGUAGE == C */ +#endif /* __ASSEMBLY__ */ #define MDCNFG_OFFSET 0x00 #define MDREFR_OFFSET 0x04 diff --git a/jtag/src/cmd/Makefile.am b/jtag/src/cmd/Makefile.am index eb56b687..17c2a9b7 100644 --- a/jtag/src/cmd/Makefile.am +++ b/jtag/src/cmd/Makefile.am @@ -31,6 +31,9 @@ libcmd_a_SOURCES = \ reset.c \ discovery.c \ detect.c \ + detectflash.c \ + help.c \ + quit.c \ signal.c \ salias.c \ bit.c \ diff --git a/jtag/src/cmd/cmd.c b/jtag/src/cmd/cmd.c index 25f29e35..29dfecbc 100644 --- a/jtag/src/cmd/cmd.c +++ b/jtag/src/cmd/cmd.c @@ -123,3 +123,61 @@ cmd_test_cable( void ) printf( _("Error: Cable not configured. Please use '%s' command first!\n"), "cable" ); return 0; } + +/* Remainder copied from libbrux/cmd/cmd.c */ + +int +cmd_run( char *params[] ) +{ + int i; + + if (!params[0]) + return 1; + + for (i = 0; cmds[i]; i++) + if (strcasecmp( cmds[i]->name, params[0] ) == 0) { + int r = cmds[i]->run( params ); + if (r < 0) + printf( _("%s: syntax error!\n"), params[0] ); + return r; + } + + printf( _("%s: unknown command\n"), params[0] ); + return 1; +} + +int +cmd_params( char *params[] ) +{ + int i = 0; + + while (params[i]) + i++; + + return i; +} + +int +cmd_get_number( char *s, unsigned int *i ) +{ + int n; + int r; + size_t l; + + if (!s || !i) + return -1; + + l = strlen( s ); + + n = -1; + r = sscanf( s, "0x%x%n", i, &n); + if (r == 1 && n == l) + return 0; + + n = -1; + r = sscanf( s, "%u%n", i, &n ); + if (r == 1 && n == l) + return 0; + + return -1; +} diff --git a/jtag/src/cmd/detectflash.c b/jtag/src/cmd/detectflash.c new file mode 100644 index 00000000..f27415c5 --- /dev/null +++ b/jtag/src/cmd/detectflash.c @@ -0,0 +1,69 @@ +/* + * $Id$ + * + * Copyright (C) 2003 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2003. + * + */ + +#include "sysdep.h" + +#include + +#include +#include + +static int +cmd_detectflash_run( char *params[] ) +{ + uint32_t adr; + + if (cmd_params( params ) != 2) + return -1; + + if (!bus) { + printf( _("Error: Bus driver missing.\n") ); + return 1; + } + + if (cmd_get_number( params[1], &adr )) + return -1; + + detectflash( bus, adr ); + + return 1; +} + +static void +cmd_detectflash_help( void ) +{ + printf( _( + "Usage: %s ADDRESS\n" + "Detect flash memory type connected to a part.\n" + "\n" + "ADDRESS Base address for memory region\n" + ), "detectflash" ); +} + +cmd_t cmd_detectflash = { + "detectflash", + N_("detect parameters of flash chips attached to a part"), + cmd_detectflash_help, + cmd_detectflash_run +}; diff --git a/jtag/src/cmd/help.c b/jtag/src/cmd/help.c new file mode 100644 index 00000000..e114cea7 --- /dev/null +++ b/jtag/src/cmd/help.c @@ -0,0 +1,76 @@ +/* + * $Id$ + * + * Copyright (C) 2003 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2003. + * + */ + +#include "sysdep.h" + +#include +#include + +#include + +static int +cmd_help_run( char *params[] ) +{ + int i; + + /* short description generation */ + if (!params[1]) { + printf( _("Command list:\n\n") ); + for (i = 0; cmds[i]; i++) + printf( _("%-13s %s\n"), cmds[i]->name, cmds[i]->desc ? _(cmds[i]->desc) : _("(no description available)") ); + printf( _("\nType \"help COMMAND\" for details about a particular command.\n") ); + return 1; + } + + if (params[2]) + return -1; + + /* search and print help for a particular command */ + for (i = 0; cmds[i]; i++) + if (strcasecmp( cmds[i]->name, params[1] ) == 0) { + if (cmds[i]->help) + cmds[i]->help(); + return 1; + } + + printf( _("%s: unknown command\n"), params[1] ); + + return 1; +} + +static void +cmd_help_help( void ) +{ + printf( _( + "Usage: %s [COMMAND]\n" + "Print short help for COMMAND, or list of available commands.\n" + ), "help" ); +} + +cmd_t cmd_help = { + "help", + N_("display this help"), + cmd_help_help, + cmd_help_run +}; diff --git a/jtag/src/cmd/quit.c b/jtag/src/cmd/quit.c new file mode 100644 index 00000000..aebb0bf4 --- /dev/null +++ b/jtag/src/cmd/quit.c @@ -0,0 +1,54 @@ +/* + * $Id$ + * + * Copyright (C) 2003 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2003. + * + */ + +#include "sysdep.h" + +#include + +#include + +static int +cmd_quit_run( char *params[] ) +{ + if (params[1]) + return -1; + + return 0; +} + +static void +cmd_quit_help( void ) +{ + printf( _( + "Usage: %s\n" + "Exit from %s.\n" + ), "quit", PACKAGE ); +} + +cmd_t cmd_quit = { + "quit", + N_("exit and terminate this session"), + cmd_quit_help, + cmd_quit_run +}; diff --git a/jtag/src/detect.c b/jtag/src/detect.c index 0a17e4b2..6b767b54 100644 --- a/jtag/src/detect.c +++ b/jtag/src/detect.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include diff --git a/jtag/src/flash.c b/jtag/src/flash.c index 483dd2dc..00199a32 100644 --- a/jtag/src/flash.c +++ b/jtag/src/flash.c @@ -41,7 +41,6 @@ #include #include -#include #include "bus.h" #include "flash.h" diff --git a/jtag/src/flash/Makefile.am b/jtag/src/flash/Makefile.am new file mode 100644 index 00000000..c95334c9 --- /dev/null +++ b/jtag/src/flash/Makefile.am @@ -0,0 +1,34 @@ +# +# $Id: Makefile.am 506 2003-08-13 10:05:15Z telka $ +# +# Copyright (C) 2002 ETC s.r.o. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. +# +# Written by Marcel Telka , 2002. +# + +include $(top_srcdir)/Makefile.rules + +noinst_LIBRARIES = libflash.a + +libflash_a_SOURCES = \ + amd.c \ + amd_flash.c \ + cfi.c \ + detectflash.c \ + intel.c \ + jedec.c diff --git a/jtag/src/flash/amd.c b/jtag/src/flash/amd.c new file mode 100644 index 00000000..221560c2 --- /dev/null +++ b/jtag/src/flash/amd.c @@ -0,0 +1,391 @@ +/* + * $Id$ + * + * Flash driver for AMD Am29LV640D, Am29LV641D, Am29LV642D + * Copyright (C) 2003 AH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by August Hörandl + * Modified by Marcel Telka , 2003. + * + * Documentation: + * [1] Advanced Micro Devices, "Am29LV640D/Am29LV641D", + * September 20, 2002 Rev B, 22366b8.pdf + * [2] Advanced Micro Devices, "Am29LV642D", + * August 14, 2001 Rev A, 25022.pdf + * + */ + +#include "sysdep.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int dbg = 0; + +static int amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ); +static int amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); +static int amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static void amd_flash_read_array( cfi_array_t *cfi_array ); + +/* The code below assumes a connection of the flash chip address LSB (A0) + * to A0, A1 or A2 of the CPU bus dependent on the bus width, which is the + * most common connection pattern: + * 8 Bit devices: A0..Ax connected to A0..Ax of CPU bus + * 16 Bit devices: A0..Ax connected to A1..Ax+1 of CPU bus + * 32 Bit devices: A0..Ax connected to A2..Ax+2 of CPU bus + * The offset "o" is used here dependent on the bus width (8, 16 or 32 bit) to + * align the patterns emitted on the address lines at either A0, A1 or A2. */ + +static int o; + +/* NOTE: It does not work for SoC chips or boards with extra address decoders + * that do address alignment themselves, such as the Samsung S3C4510B. The bus + * driver has to deal with this. - kawk 2008-01 */ + +/* autodetect, we can handle this chip */ +static int +amd_flash_autodetect32( cfi_array_t *cfi_array ) +{ + if(cfi_array->bus_width != 4) return 0; + o = 2; /* Heuristic */ + return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS); +} + +static int +amd_flash_autodetect16( cfi_array_t *cfi_array ) +{ + if(cfi_array->bus_width != 2) return 0; + o = 1; /* Heuristic */ + return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS); +} + +static int +amd_flash_autodetect8( cfi_array_t *cfi_array ) +{ + if(cfi_array->bus_width != 1) return 0; + o = 0; /* Heuristic */ + return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS); +} +/* + * check device status + * 1/true PASS + * 0/false FAIL + */ +/* + * first implementation: see [1], page 29 + */ +#if 0 +static int +amdstatus29( parts *ps, uint32_t adr, uint32_t data ) +{ + int timeout; + uint32_t dq7mask = ((1 << 7) << 16) + (1 << 7); + uint32_t dq5mask = ((1 << 5) << 16) + (1 << 5); + uint32_t bit7 = (data & (1 << 7)) != 0; + uint32_t data1; + + for (timeout = 0; timeout < 100; timeout++) { + data1 = bus_read( ps, adr << o ); + data1 = bus_read( ps, adr << o ); + if (dbg) + printf( "amdstatus %d: %04X (%04X) = %04X\n", timeout, data1, (data1 & dq7mask), bit7 ); + if (((data1 & dq7mask) == dq7mask) == bit7) /* FIXME: This looks non-portable */ + return 1; + + if ((data1 & dq5mask) == dq5mask) + break; + usleep( 100 ); + } + + data1 = bus_read( ps, adr << o ); + if (((data1 & dq7mask) == dq7mask) == bit7) /* FIXME: This looks non-portable */ + return 1; + + return 0; +} +#endif /* 0 */ + + +#if 1 +/* + * second implementation: see [1], page 30 + */ +static int +amdstatus( bus_t *bus, uint32_t adr, int data ) +{ + int timeout; + uint32_t togglemask = ((1 << 6) << 16) + (1 << 6); /* DQ 6 */ + /* int dq5mask = ((1 << 5) << 16) + (1 << 5); DQ5 */ + + for (timeout = 0; timeout < 100; timeout++) { + uint32_t data1 = bus_read( bus, adr ); + uint32_t data2 = bus_read( bus, adr ); + + /*printf("amdstatus %d: %04X/%04X %04X/%04X \n", */ + /* timeout, data1, data2, (data1 & togglemask), (data2 & togglemask)); */ + if ( (data1 & togglemask) == (data2 & togglemask)) + return 1; + + /* if ( (data1 & dq5mask) != 0 ) TODO */ + /* return 0; */ + if (dbg) + printf( "amdstatus %d: %04X/%04X\n", timeout, data1, data2 ); + else + printf( "." ); + usleep( 100 ); + } + return 0; +} + +#else /* 1 */ + +/* Note: This implementation of amdstatus() has been added by patch + [ 1429825 ] EJTAG driver (some remaining patch lines for flash/amd.c) + It's a quirk workaround and seems to break status polling for other chips. + Therefore it's deactivated at the moment but kept for reference. */ +/* + * second implementation: see [1], page 30 + */ +static int +amdstatus( bus_t *bus, uint32_t adr, int data ) +{ + int timeout; + uint32_t togglemask = ((1 << 6) << 16) + (1 << 6); /* DQ 6 */ + /* int dq5mask = ((1 << 5) << 16) + (1 << 5); DQ5 */ + uint32_t data1, data2; + + data1 = bus_read( bus, adr ); + for (timeout = 0; timeout < 100; timeout++) { + data2 = bus_read( bus, adr ); + + + /*printf("amdstatus %d: %04X/%04X %04X/%04X \n", */ + /* timeout, data1, data2, (data1 & togglemask), (data2 & togglemask)); */ + /* Work around an issue with RTL8181: toggle bits don't + toggle when reading the same flash address repeatedly + without any other memory access in between. Other + bits reflect the current status, and data after the + operation is complete - only Q6/Q2 bits don't toggle + when they should. Looks like the CPU not deasserting + CE or OE, so data is output to the bus continuously. + So, check for the correct data read twice instead. */ + /*if ( (data1 & togglemask) == (data2 & togglemask)) */ + if ( (data1 == data) && (data2 == data) ) + return 1; + + /* if ( (data1 & dq5mask) != 0 ) TODO */ + /* return 0; */ + if (dbg) + printf( "amdstatus %d: %04X/%04X\n", timeout, data1, data2 ); + else + printf( "." ); + usleep( 100 ); + data1 = data2; + } + return 0; +} + +#endif /* 0 */ + +#if 0 +static int +amdisprotected( parts *ps, cfi_array_t *cfi_array, uint32_t adr ) +{ + uint32_t data; + + bus_write( ps, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, sector erase */ + bus_write( ps, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( ps, cfi_array->address + (0x0555 << o), 0x00900090 ); + + data = bus_read( ps, adr + (0x0002 << 2) ); + /* Read Array */ + amd_flash_read_array( ps ); /* AMD reset */ + + return ((data & 0x00ff00ff) != 0); +} +#endif /* 0 */ + +static void +amd_flash_print_info( cfi_array_t *cfi_array ) +{ + int mid, cid, prot; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29 */ + bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00900090 ); + mid = bus_read( bus, cfi_array->address + (0x00 << o) ) & 0xFFFF; + cid = bus_read( bus, cfi_array->address + (0x01 << o) ) & 0xFFFF; + prot = bus_read( bus, cfi_array->address + (0x02 << o) ) & 0xFF; + amd_flash_read_array( cfi_array ); /* AMD reset */ + printf( _("Chip: AMD Flash\n\tManufacturer: ") ); + switch (mid) { + case 0x0001: + printf( _("AMD") ); + break; + case 0x0020: + printf( _("ST/Samsung") ); + break; + case 0x002C: + printf( _("Macronix") ); + break; + default: + printf( _("Unknown manufacturer (ID 0x%04x)"), mid ); + break; + } + printf( _("\n\tChip: ") ); + switch (cid) { + case 0x004F: + printf( _("Am29LV040B") ); + break; + case 0x22D7: + printf( _("Am29LV640D/Am29LV641D/Am29LV642D") ); + break; + case 0x225B: + printf( _("Am29LV800B") ); + break; + case 0x2249: + printf( _("MX29LV160B") ); + break; + case 0x0049: + printf( _("AM29LV160DB") ); + break; + case 0x0093: + printf( _("Am29LV065D") ); + break; + case 0x00ca: + printf( _("M29W320DT") ); + break; + case 0x00cb: + printf( _("M29W320DB") ); + break; + default: + printf ( _("Unknown (ID 0x%04x)"), cid ); + break; + } + printf( _("\n\tProtected: %04x\n"), prot ); + + /* Read Array */ + bus_write( bus, cfi_array->address + (0x0000 << o), 0x00ff00ff ); +} + +static int +amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + bus_t *bus = cfi_array->bus; + + printf("flash_erase_block 0x%08X\n", adr); + + /* printf("protected: %d\n", amdisprotected(ps, cfi_array, adr)); */ + + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, sector erase */ + bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00800080 ); + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); + bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( bus, adr, 0x00300030 ); + + if (amdstatus( bus, adr, 0xffff )) { + printf( "flash_erase_block 0x%08X DONE\n", adr ); + amd_flash_read_array( cfi_array ); /* AMD reset */ + return 0; + } + printf( "flash_erase_block 0x%08X FAILED\n", adr ); + /* Read Array */ + amd_flash_read_array( cfi_array ); /* AMD reset */ + + return FLASH_ERROR_UNKNOWN; +} + +static int +amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + printf( "flash_unlock_block 0x%08X IGNORE\n", adr ); + return 0; +} + +static int +amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +{ + int status; + bus_t *bus = cfi_array->bus; + + if (dbg) + printf("\nflash_program 0x%08X = 0x%08X\n", adr, data); + + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, program */ + bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 ); + bus_write( bus, cfi_array->address + (0x0555 << o), 0x00A000A0 ); + + bus_write( bus, adr, data ); + status = amdstatus( bus, adr, data ); + /* amd_flash_read_array(ps); */ + + return !status; +} + +static void +amd_flash_read_array( cfi_array_t *cfi_array ) +{ + /* Read Array */ + bus_write( cfi_array->bus, cfi_array->address, 0x00F000F0 ); /* AMD reset */ +} + +flash_driver_t amd_32_flash_driver = { + 4, /* buswidth */ + N_("AMD/Fujitsu Standard Command Set"), + N_("supported: AMD 29LV640D, 29LV641D, 29LV642D; 2x16 Bit"), + amd_flash_autodetect32, + amd_flash_print_info, + amd_flash_erase_block, + amd_flash_unlock_block, + amd_flash_program, + amd_flash_read_array, +}; + +flash_driver_t amd_16_flash_driver = { + 2, /* buswidth */ + N_("AMD/Fujitsu Standard Command Set"), + N_("supported: AMD 29LV800B; 1x16 Bit"), + amd_flash_autodetect16, + amd_flash_print_info, + amd_flash_erase_block, + amd_flash_unlock_block, + amd_flash_program, + amd_flash_read_array, +}; + +flash_driver_t amd_8_flash_driver = { + 1, /* buswidth */ + N_("AMD/Fujitsu Standard Command Set"), + N_("supported: AMD 29LV160, AMD 29LV065D, AMD 29LV040B; 1x8 Bit"), + amd_flash_autodetect8, + amd_flash_print_info, + amd_flash_erase_block, + amd_flash_unlock_block, + amd_flash_program, + amd_flash_read_array, +}; diff --git a/jtag/src/flash/amd_flash.c b/jtag/src/flash/amd_flash.c new file mode 100644 index 00000000..5cb5fb1c --- /dev/null +++ b/jtag/src/flash/amd_flash.c @@ -0,0 +1,353 @@ +/* + * $Id: amd_flash.c,v 1.0 20/09/2006 12:38:01 $ + * + * AMD 8 bit flash driver for AM29F040B & AM29LV040B + * Copyright (C) 2006 Kila Medical Systems. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Ajith Kumar P.C + * + * Documentation: + * [1] Spansion, Am29F040B Data Sheet + * [2] Spansion, Am29LV040B Data Sheet +*/ + +#include "sysdep.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//write specific +#define AMD_SECTOR_PROTECTED + +//Read Specific +#define AMD_READ_IN_ERASE_SUSPENDED_SECTOR +#define AMD_READ_IN_NON_ERASE_SUSPENDED_SECTOR +#define AMD_NORMAL_READ +#define AMD_UNKNOWN_READ + +//Mode +#define AMD_ERASE_SUSPEND_MODE +#define AMD_READING_MODE +#define AMD_EMBEDDED_ERASE_ALGORITHM +#define AMD_EMBEDDED_PROGRAM_ALGORITHM +#define AMD_UNDEFINED_MODE + +#define FLASH_ERASE_ERROR -5 +#define ERASE_FLASH_SUCCESS 1 + +#define AMD_29xx040B 1 + +#define AMD_BYPASS_UNLOCK_ALGORITHM 1 +#define AMD_STANDARD_WRITE_ALGORITHM 0 +#define AMD_BYPASS_UNLOCK_MODE 1 +#define AMD_STANDARD_MODE 0 + +struct +{ + unsigned long flash; + unsigned short algorithm; + unsigned short unlock_bypass; +} +var_forced_detection; + +int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ); +static int amd_29xx040_autodetect( cfi_array_t *cfi_array ); +static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data ); +static void amd_29xx040_print_info( cfi_array_t *cfi_array ); +static void amd_29xx040_read_array( cfi_array_t *cfi_array ); +static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr ); +static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); + +int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ) +{ + int mid; + int did; + bus_area_t area; + cfi_query_structure_t *cfi ; + + if (!cfi_array || !bus) + return -1; /* invalid parameters */ + + *cfi_array = calloc( 1, sizeof (cfi_array_t) ); + if (!*cfi_array) + return -2; /* out of memory */ + + bus_write( bus, adr+0x0, 0xf0 ); + bus_write( bus, adr+0x555, 0xaa ); + bus_write( bus, adr+0x2AA, 0x55 ); + bus_write( bus, adr+0x555, 0x90 ); + mid = bus_read( bus, adr+0x0); + did = bus_read( bus, adr+0x1); + bus_write( bus, adr+0x0, 0xf0 ); + + printf( "%s: mid %x, did %x\n", __FUNCTION__, mid, did ); + if (mid != 0x01) + return -1; + + switch(did) + { + case 0xA4: + var_forced_detection.flash = AMD_29xx040B; + break; + case 0x4F: + var_forced_detection.flash = AMD_29xx040B; + var_forced_detection.algorithm = AMD_BYPASS_UNLOCK_ALGORITHM; + break; + default: + break; + } + + (*cfi_array)->bus = bus; + (*cfi_array)->address = 0; + if (bus_area( bus, adr+0, &area ) != 0) + return -8; /* bus width detection failed */ + unsigned int bw = area.width; + int ba,i; + if (bw != 8 && bw != 16 && bw != 32) + return -3; /* invalid bus width */ + (*cfi_array)->bus_width = ba = bw / 8; + (*cfi_array)->cfi_chips = calloc( ba, sizeof (cfi_chip_t *) ); + if (!(*cfi_array)->cfi_chips) + return -2; + for ( i=0; icfi_chips[i] = calloc( 1, sizeof (cfi_chip_t) ); + if (!(*cfi_array)->cfi_chips[i]) + return -2; /* out of memory */ + (*cfi_array)->cfi_chips[i]->width = 1; //ba; + cfi = &(*cfi_array)->cfi_chips[i]->cfi; + + cfi->identification_string.pri_id_code = CFI_VENDOR_NULL; + cfi->identification_string.pri_vendor_tbl = NULL; + cfi->identification_string.alt_id_code = 0; + cfi->identification_string.alt_vendor_tbl = NULL; + + cfi->device_geometry.device_size = 512*1024; + cfi->device_geometry.device_interface = 0; // x 8 + cfi->device_geometry.max_bytes_write = 32; //not used + cfi->device_geometry.number_of_erase_regions = 1; + cfi->device_geometry.erase_block_regions = + malloc( cfi->device_geometry.number_of_erase_regions * sizeof (cfi_erase_block_region_t) ); + if (!cfi->device_geometry.erase_block_regions) + return -2; /* out of memory */ + + cfi->device_geometry.erase_block_regions[i].erase_block_size = 64 * 1024; + cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks = 8; + //Add other details for info + } + return 0; +} + + +static int amd_29xx040_autodetect( cfi_array_t *cfi_array ) +{ + return(var_forced_detection.flash == AMD_29xx040B); //Non-CFI Am29xx040B flash +} + +static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data ) +{ + short timeout; + unsigned short dq7bit,dq7mask,dq5mask; + unsigned short data1; + + dq7mask = (1 << 7); + dq5mask = (1 << 5); + dq7bit = data & dq7mask; + + for (timeout = 0; timeout < 1000; timeout++) //typical sector erase time = 0.7 sec + { + data1 = (unsigned short)(bus_read( bus, adr ) & 0xFF); + if((data1 & dq7mask) == dq7bit) + return 1; //Success + + if((data1 & dq5mask) == dq5mask) + { + data1 = (unsigned short)(bus_read( bus, adr ) & 0xFF); + if((data1 & dq7mask) == dq7bit) + { + return 1; //Success + } + else + { + return 0; //Failure - Needs a reset command to return back to read array data + } + } + usleep (50); + } + + return 0; //hardware failure +} + + + +static void amd_29xx040_print_info( cfi_array_t *cfi_array ) +{ + int mid, did, prot; + bus_t *bus = cfi_array->bus; + + + bus_write( bus, cfi_array->address + 0x0, 0xf0 ); + bus_write( bus, cfi_array->address + 0x555, 0xaa ); + bus_write( bus, cfi_array->address + 0x2AA, 0x55 ); + bus_write( bus, cfi_array->address + 0x555, 0x90 ); + mid = bus_read( bus, cfi_array->address + 0x0); + did = bus_read( bus, cfi_array->address + 0x1); + prot = bus_read( bus, cfi_array->address + 0x2); + bus_write( bus, cfi_array->address + 0x0, 0xf0 ); + + printf( "%s: mid %x, did %x\n", __FUNCTION__, mid, did ); +// amd_29xx040_read_array( cfi_array ); /* AMD reset */ + + switch (mid) + { + case 0x01: + printf( _("Chip: AMD Flash\n\tPartNumber: ") ); + break; + default: + printf( _("Unknown manufacturer (ID 0x%04x)"), mid ); + break; + } + printf( _("\n\tChip: ") ); + switch (did) { + case 0xA4: + printf( _("Am29C040B\t-\t") ); + printf( _("5V Flash\n") ); + break; + case 0x4F: + printf( _("Am29LV040B\t-\t") ); + printf( _("3V Flash\n") ); + break; + default: + printf ( _("Unknown (ID 0x%04x)"), did ); + break; + } + printf( _("\n\tProtected: %04x\n"), prot ); +} + +static void amd_29xx040_read_array( cfi_array_t *cfi_array ) +{ + /* Read Array */ + if(var_forced_detection.unlock_bypass == AMD_BYPASS_UNLOCK_MODE) + { + bus_write( bus, cfi_array->address + 0x555, 0x90 ); + bus_write( bus, cfi_array->address + 0x2AA, 0x00 ); + usleep(100); + var_forced_detection.unlock_bypass = AMD_STANDARD_MODE; + } + bus_write( cfi_array->bus, cfi_array->address + 0x0, 0x0F0 ); /* AMD reset */ +} + + + +static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + bus_t *bus = cfi_array->bus; + + printf("flash_erase_block 0x%08X\n", adr); + + /* printf("protected: %d\n", amdisprotected(ps, adr)); */ + + if(var_forced_detection.unlock_bypass == AMD_BYPASS_UNLOCK_MODE) + { + bus_write( bus, cfi_array->address + 0x555, 0x90 ); + bus_write( bus, cfi_array->address + 0x2AA, 0x00 ); + usleep(100); + var_forced_detection.unlock_bypass = AMD_STANDARD_MODE; + } + + bus_write( bus, cfi_array->address + 0x0, 0xf0 ); + bus_write( bus, cfi_array->address + 0x555, 0xaa ); + bus_write( bus, cfi_array->address + 0x2AA, 0x55 ); + bus_write( bus, cfi_array->address + 0x555, 0x80 ); + bus_write( bus, cfi_array->address + 0x555, 0xaa ); + bus_write( bus, cfi_array->address + 0x2AA, 0x55 ); +// bus_write( bus, cfi_array->address + 0x555, 0x10 ); //Chip Erase + bus_write( bus, adr, 0x30 ); //Sector erase + + + if (amd_29xx040_status( bus, adr, 0xff )) { + printf( "flash_erase_block 0x%08X DONE\n", adr ); + amd_29xx040_read_array( cfi_array ); /* AMD reset */ + return ERASE_FLASH_SUCCESS; + } + printf( "flash_erase_block 0x%08X FAILED\n", adr ); + /* Read Array */ + amd_29xx040_read_array( cfi_array ); /* AMD reset */ + + return FLASH_ERASE_ERROR; +} + +static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +{ + int status; + bus_t *bus = cfi_array->bus; + + if (0) + printf("\nflash_program 0x%08X = 0x%08X\n", adr, data); + if(var_forced_detection.algorithm == AMD_BYPASS_UNLOCK_ALGORITHM) + { + if(var_forced_detection.unlock_bypass != AMD_BYPASS_UNLOCK_MODE) + { + bus_write( bus, cfi_array->address + 0x555, 0xaa ); + bus_write( bus, cfi_array->address + 0x2AA, 0x55 ); + bus_write( bus, cfi_array->address + 0x555, 0x20 ); + usleep(1000); + var_forced_detection.unlock_bypass = AMD_BYPASS_UNLOCK_MODE; + } + } + else + { + bus_write( bus, cfi_array->address + 0x555, 0xaa ); + bus_write( bus, cfi_array->address + 0x2AA, 0x55 ); + } + + bus_write( bus, cfi_array->address + 0x555, 0xA0 ); + bus_write( bus, adr, data ); + status = amd_29xx040_status( bus, adr, data ); + /* amd_29xx040_read_array(cfi_array); */ + + return !status; +} + +static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + printf( "flash_unlock_block 0x%08X IGNORE\n", adr ); + return 0; +} + + +flash_driver_t amd_29xx040_flash_driver = { + 1, /* buswidth */ + N_("AMD Standard Command Set"), + N_("supported: AMD 29LV040B, 29C040B, 1x8 Bit"), + amd_29xx040_autodetect, + amd_29xx040_print_info, + amd_29xx040_erase_block, + amd_29xx040_unlock_block, + amd_29xx040_program, + amd_29xx040_read_array, +}; diff --git a/jtag/src/flash/cfi.c b/jtag/src/flash/cfi.c new file mode 100644 index 00000000..2d943a88 --- /dev/null +++ b/jtag/src/flash/cfi.c @@ -0,0 +1,258 @@ +/* + * $Id$ + * + * Copyright (C) 2002, 2003 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2002, 2003. + * + * Documentation: + * [1] JEDEC Solid State Technology Association, "Common Flash Interface (CFI)", + * September 1999, Order Number: JESD68 + * [2] Intel Corporation, "Common Flash Interface (CFI) and Command Sets + * Application Note 646", April 2000, Order Number: 292204-004 + * + */ + +#include "sysdep.h" + +#include +#include +#include + +#include +#include + +void +cfi_array_free( cfi_array_t *cfi_array ) +{ + if (!cfi_array) + return; + + if (cfi_array->cfi_chips) { + int i; + + for (i = 0; i < cfi_array->bus_width; i++) { + if (!cfi_array->cfi_chips[i]) + continue; + + free( cfi_array->cfi_chips[i]->cfi.device_geometry.erase_block_regions ); + free( cfi_array->cfi_chips[i] ); + } + free( cfi_array->cfi_chips ); + } + + free( cfi_array ); +} + +int +cfi_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ) +{ + unsigned int bw; /* bus width */ + unsigned int d; /* data offset */ + int ba; /* bus width address multiplier */ + int ma; /* flash mode address multiplier */ + bus_area_t area; + + if (!cfi_array || !bus) + return -1; /* invalid parameters */ + + *cfi_array = calloc( 1, sizeof (cfi_array_t) ); + if (!*cfi_array) + return -2; /* out of memory */ + + (*cfi_array)->bus = bus; + (*cfi_array)->address = adr; + if (bus_area( bus, adr, &area ) != 0) + return -8; /* bus width detection failed */ + bw = area.width; + if (bw != 8 && bw != 16 && bw != 32) + return -3; /* invalid bus width */ + (*cfi_array)->bus_width = ba = bw / 8; + (*cfi_array)->cfi_chips = calloc( ba, sizeof (cfi_chip_t *) ); + if (!(*cfi_array)->cfi_chips) + return -2; /* out of memory */ + + for (d = 0; d < bw; d += 8) { +#define A(off) (adr + (off) * ba * ma) +#define D(data) ((data) << d) +#define gD(data) (((data) >> d) & 0xFF) +#define read1(off) gD(bus_read( bus, A(off) )) +#define read2(off) (bus_read_start( bus, A(off) ), gD(bus_read_next( bus, A((off) + 1) )) | gD(bus_read_end( bus )) << 8) +#define write1(off,data) bus_write( bus, A(off), D(data) ) + + cfi_query_structure_t *cfi; + uint32_t tmp; + int ret = -4; /* CFI not detected (Q) */ + + /* detect CFI capable devices - see Table 1 in [1] */ + for (ma = 1; ma <= 4; ma *= 2) { + write1( CFI_CMD_QUERY_OFFSET, CFI_CMD_QUERY ); + + if (read1(CFI_QUERY_ID_OFFSET) == 'Q') { + ret = -5; /* CFI not detected (R) */ + if (read1(CFI_QUERY_ID_OFFSET + 1) == 'R') + break; + } + + write1( 0, CFI_CMD_READ_ARRAY1 ); + } + + if (ma > 4) + return ret; /* CFI not detected (Q or R) */ + + if (read1(CFI_QUERY_ID_OFFSET + 2) != 'Y') { + write1( 0, CFI_CMD_READ_ARRAY1 ); + return -6; /* CFI not detected (Y) */ + } + + (*cfi_array)->cfi_chips[d / 8] = calloc( 1, sizeof (cfi_chip_t) ); + if (!(*cfi_array)->cfi_chips[d / 8]) { + write1( 0, CFI_CMD_READ_ARRAY1 ); + return -2; /* out of memory */ + } + cfi = &(*cfi_array)->cfi_chips[d / 8]->cfi; + + /* Identification string - see Table 6 in [1] */ + cfi->identification_string.pri_id_code = read2(PRI_VENDOR_ID_OFFSET); + cfi->identification_string.pri_vendor_tbl = NULL; + cfi->identification_string.alt_id_code = read2(ALT_VENDOR_ID_OFFSET); + cfi->identification_string.alt_vendor_tbl = NULL; + + /* System interface information - see Table 7 in [1] */ + tmp = read1(VCC_MIN_WEV_OFFSET); + cfi->system_interface_info.vcc_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100; + tmp = read1(VCC_MAX_WEV_OFFSET); + cfi->system_interface_info.vcc_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100; + tmp = read1(VPP_MIN_WEV_OFFSET); + cfi->system_interface_info.vpp_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100; + tmp = read1(VPP_MAX_WEV_OFFSET); + cfi->system_interface_info.vpp_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100; + + /* TODO: Add out of range checks for timeouts */ + tmp = read1(TYP_SINGLE_WRITE_TIMEOUT_OFFSET); + cfi->system_interface_info.typ_single_write_timeout = tmp ? (1 << tmp) : 0; + + tmp = read1(TYP_BUFFER_WRITE_TIMEOUT_OFFSET); + cfi->system_interface_info.typ_buffer_write_timeout = tmp ? (1 << tmp) : 0; + + tmp = read1(TYP_BLOCK_ERASE_TIMEOUT_OFFSET); + cfi->system_interface_info.typ_block_erase_timeout = tmp ? (1 << tmp) : 0; + + tmp = read1(TYP_CHIP_ERASE_TIMEOUT_OFFSET); + cfi->system_interface_info.typ_chip_erase_timeout = tmp ? (1 << tmp) : 0; + + tmp = read1(MAX_SINGLE_WRITE_TIMEOUT_OFFSET); + cfi->system_interface_info.max_single_write_timeout = + (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_single_write_timeout; + + tmp = read1(MAX_BUFFER_WRITE_TIMEOUT_OFFSET); + cfi->system_interface_info.max_buffer_write_timeout = + (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_buffer_write_timeout; + + tmp = read1(MAX_BLOCK_ERASE_TIMEOUT_OFFSET); + cfi->system_interface_info.max_block_erase_timeout = + (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_block_erase_timeout; + + tmp = read1(MAX_CHIP_ERASE_TIMEOUT_OFFSET); + cfi->system_interface_info.max_chip_erase_timeout = + (tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_chip_erase_timeout; + + /* Device geometry - see Table 8 in [1] */ + /* TODO: Add out of range check */ + cfi->device_geometry.device_size = 1 << read1(DEVICE_SIZE_OFFSET); + + cfi->device_geometry.device_interface = read2(FLASH_DEVICE_INTERFACE_OFFSET); + + /* TODO: Add out of range check */ + cfi->device_geometry.max_bytes_write = 1 << read2(MAX_BYTES_WRITE_OFFSET); + + tmp = cfi->device_geometry.number_of_erase_regions = read1(NUMBER_OF_ERASE_REGIONS_OFFSET); + + cfi->device_geometry.erase_block_regions = malloc( tmp * sizeof (cfi_erase_block_region_t) ); + if (!cfi->device_geometry.erase_block_regions) { + write1( 0, CFI_CMD_READ_ARRAY1 ); + return -2; /* out of memory */ + } + + { + int a; + int i; + + for (i = 0, a = ERASE_BLOCK_REGION_OFFSET; i < tmp; i++, a += 4) { + uint32_t y = read2(a); + uint32_t z = read2(a + 2) << 8; + if (z == 0) + z = 128; + cfi->device_geometry.erase_block_regions[i].erase_block_size = z; + cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks = y + 1; + } + } + + /* TODO: Intel Primary Algorithm Extended Query Table - see Table 5. in [2] */ + + /* Read Array */ + write1( 0, CFI_CMD_READ_ARRAY1 ); + +#undef A +#undef D +#undef gD +#undef read1 +#undef read2 +#undef write1 + + switch (cfi->device_geometry.device_interface) { + case CFI_INTERFACE_X8: + if (ma != 1) + return -7; /* error in device detection */ + (*cfi_array)->cfi_chips[d / 8]->width = 1; + break; + case CFI_INTERFACE_X16: + if (ma != 1) + return -7; /* error in device detection */ + (*cfi_array)->cfi_chips[d / 8]->width = 2; + d += 8; + break; + case CFI_INTERFACE_X8_X16: + if (ma != 1 && ma != 2) + return -7; /* error in device detection */ + (*cfi_array)->cfi_chips[d / 8]->width = 2 / ma; + if (ma == 1) + d += 8; + break; + case CFI_INTERFACE_X32: + if (ma != 1) + return -7; /* error in device detection */ + (*cfi_array)->cfi_chips[d / 8]->width = 4; + d += 24; + break; + case CFI_INTERFACE_X16_X32: + if (ma != 1 && ma != 2) + return -7; /* error in device detection */ + (*cfi_array)->cfi_chips[d / 8]->width = 4 / ma; + if (ma == 1) + d += 24; + else + d += 8; + break; + default: + return -7; /* error in device detection */ + } + } + + return 0; +} diff --git a/jtag/src/flash/detectflash.c b/jtag/src/flash/detectflash.c new file mode 100644 index 00000000..a30605f1 --- /dev/null +++ b/jtag/src/flash/detectflash.c @@ -0,0 +1,205 @@ +/* + * $Id$ + * + * Copyright (C) 2002 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2002. + * + * Documentation: + * [1] JEDEC Solid State Technology Association, "Common Flash Interface (CFI)", + * September 1999, Order Number: JESD68 + * [2] JEDEC Solid State Technology Association, "Common Flash Interface (CFI) ID Codes", + * September 2001, Order Number: JEP137-A + * + */ + +#include "sysdep.h" + +#include +#include +#include +#include +#include + +#include +#include + +cfi_array_t *cfi_array = NULL; + +extern int jedec_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ); + +extern int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ); //Ajith + +void +detectflash( bus_t *bus, uint32_t adr ) +{ + cfi_query_structure_t *cfi; + const char *s; + + if (!bus) { + printf( _("Error: Missing bus driver!\n") ); + return; + } + + cfi_array_free( cfi_array ); + cfi_array = NULL; + + bus_prepare( bus ); + + if (cfi_detect( bus, adr, &cfi_array )) { + cfi_array_free( cfi_array ); + cfi_array = NULL; + if (jedec_detect( bus, adr, &cfi_array ) != 0) { + cfi_array_free( cfi_array ); + if(amd_detect(bus, adr, &cfi_array ) != 0) + { + cfi_array_free( cfi_array ); + cfi_array->bus_width = 1; + cfi_array = NULL; + printf( _("Flash not found!\n") ); + return; + } + } + } + + cfi = &cfi_array->cfi_chips[0]->cfi; + + /* detect CFI capable devices */ + /* TODO: Low chip only */ + /* see 4.3.2 in [1] */ + printf( _("Query identification string:\n") ); + /* see section 2 in [2] */ + switch (cfi->identification_string.pri_id_code) { + case CFI_VENDOR_NULL: + s = N_("null"); + break; + case CFI_VENDOR_INTEL_ECS: + s = N_("Intel/Sharp Extended Command Set"); + break; + case CFI_VENDOR_AMD_SCS: + s = N_("AMD/Fujitsu Standard Command Set"); + break; + case CFI_VENDOR_INTEL_SCS: + s = N_("Intel Standard Command Set"); + break; + case CFI_VENDOR_AMD_ECS: + s = N_("AMD/Fujitsu Extended Command Set"); + break; + case CFI_VENDOR_MITSUBISHI_SCS: + s = N_("Mitsubishi Standard Command Set"); + break; + case CFI_VENDOR_MITSUBISHI_ECS: + s = N_("Mitsubishi Extended Command Set"); + break; + case CFI_VENDOR_SST_PWCS: + s = N_("Page Write Command Set"); + break; + default: + s = N_("unknown!!!"); + break; + } + printf( _("\tPrimary Algorithm Command Set and Control Interface ID Code: 0x%04X (%s)\n"), cfi->identification_string.pri_id_code, _(s) ); + switch (cfi->identification_string.alt_id_code) { + case CFI_VENDOR_NULL: + s = N_("null"); + break; + case CFI_VENDOR_INTEL_ECS: + s = N_("Intel/Sharp Extended Command Set"); + break; + case CFI_VENDOR_AMD_SCS: + s = N_("AMD/Fujitsu Standard Command Set"); + break; + case CFI_VENDOR_INTEL_SCS: + s = N_("Intel Standard Command Set"); + break; + case CFI_VENDOR_AMD_ECS: + s = N_("AMD/Fujitsu Extended Command Set"); + break; + case CFI_VENDOR_MITSUBISHI_SCS: + s = N_("Mitsubishi Standard Command Set"); + break; + case CFI_VENDOR_MITSUBISHI_ECS: + s = N_("Mitsubishi Extended Command Set"); + break; + case CFI_VENDOR_SST_PWCS: + s = N_("Page Write Command Set"); + break; + default: + s = N_("unknown!!!"); + break; + } + printf( _("\tAlternate Algorithm Command Set and Control Interface ID Code: 0x%04X (%s)\n"), cfi->identification_string.alt_id_code, _(s) ); + + /* see 4.3.3 in [1] */ + printf( _("Query system interface information:\n") ); + printf( _("\tVcc Logic Supply Minimum Write/Erase or Write voltage: %d mV\n"), cfi->system_interface_info.vcc_min_wev ); + printf( _("\tVcc Logic Supply Maximum Write/Erase or Write voltage: %d mV\n"), cfi->system_interface_info.vcc_max_wev ); + printf( _("\tVpp [Programming] Supply Minimum Write/Erase voltage: %d mV\n"), cfi->system_interface_info.vpp_min_wev ); + printf( _("\tVpp [Programming] Supply Maximum Write/Erase voltage: %d mV\n"), cfi->system_interface_info.vpp_max_wev ); + printf( _("\tTypical timeout per single byte/word program: %d us\n"), cfi->system_interface_info.typ_single_write_timeout ); + printf( _("\tTypical timeout for maximum-size multi-byte program: %d us\n"), cfi->system_interface_info.typ_buffer_write_timeout ); + printf( _("\tTypical timeout per individual block erase: %d ms\n"), cfi->system_interface_info.typ_block_erase_timeout ); + printf( _("\tTypical timeout for full chip erase: %d ms\n"), cfi->system_interface_info.typ_chip_erase_timeout ); + printf( _("\tMaximum timeout for byte/word program: %d us\n"), cfi->system_interface_info.max_single_write_timeout ); + printf( _("\tMaximum timeout for multi-byte program: %d us\n"), cfi->system_interface_info.max_buffer_write_timeout ); + printf( _("\tMaximum timeout per individual block erase: %d ms\n"), cfi->system_interface_info.max_block_erase_timeout ); + printf( _("\tMaximum timeout for chip erase: %d ms\n"), cfi->system_interface_info.max_chip_erase_timeout ); + + /* see 4.3.4 in [1] */ + printf( _("Device geometry definition:\n") ); + printf( _("\tDevice Size: %d B (%d KiB, %d MiB)\n"), + cfi->device_geometry.device_size, + cfi->device_geometry.device_size / 1024, + cfi->device_geometry.device_size / (1024 * 1024) ); + /* see section 4 in [2] */ + switch (cfi->device_geometry.device_interface) { + case CFI_INTERFACE_X8: + s = N_("x8"); + break; + case CFI_INTERFACE_X16: + s = N_("x16"); + break; + case CFI_INTERFACE_X8_X16: + s = N_("x8/x16"); + break; + case CFI_INTERFACE_X32: + s = N_("x32"); + break; + case CFI_INTERFACE_X16_X32: + s = N_("x16/x32"); + break; + default: + s = N_("unknown!!!"); + break; + } + printf( _("\tFlash Device Interface Code description: 0x%04X (%s)\n"), cfi->device_geometry.device_interface, _(s) ); + printf( _("\tMaximum number of bytes in multi-byte program: %d\n"), cfi->device_geometry.max_bytes_write ); + printf( _("\tNumber of Erase Block Regions within device: %d\n"), cfi->device_geometry.number_of_erase_regions ); + printf( _("\tErase Block Region Information:\n") ); + { + int i; + + for (i = 0; i < cfi->device_geometry.number_of_erase_regions; i++) { + printf( _("\t\tRegion %d:\n"), i ); + printf( _("\t\t\tErase Block Size: %d B (%d KiB)\n"), + cfi->device_geometry.erase_block_regions[i].erase_block_size, + cfi->device_geometry.erase_block_regions[i].erase_block_size / 1024 ); + printf( _("\t\t\tNumber of Erase Blocks: %d\n"), cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks ); + } + } +} diff --git a/jtag/src/flash/intel.c b/jtag/src/flash/intel.c new file mode 100644 index 00000000..24c5f74a --- /dev/null +++ b/jtag/src/flash/intel.c @@ -0,0 +1,380 @@ +/* + * $Id$ + * + * Copyright (C) 2002 ETC s.r.o. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2002. + * Changed by August Hörandl, 2003 + * + * Documentation: + * [1] Advanced Micro Devices, "Common Flash Memory Interface Specification Release 2.0", + * December 1, 2001 + * [2] Intel Corporation, "Intel PXA250 and PXA210 Application Processors + * Developer's Manual", February 2002, Order Number: 278522-001 + * [3] Intel Corporation, "Common Flash Interface (CFI) and Command Sets + * Application Note 646", April 2000, Order Number: 292204-004 + * [4] Advanced Micro Devices, "Common Flash Memory Interface Publication 100 Vendor & Device + * ID Code Assignments", December 1, 2001, Volume Number: 96.1 + * + */ + +#include "sysdep.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +static int intel_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ); +static int intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ); +static int intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); +static int intel_flash_erase_block32( cfi_array_t *cfi_array, uint32_t adr ); +static int intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr ); +static int intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ); + +/* autodetect, we can handle this chip */ +static int +intel_flash_autodetect32( cfi_array_t *cfi_array ) +{ + bus_area_t area; + + if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0) + return 0; + + return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS) + || (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS)) + && (area.width == 32); +} + +static int +intel_flash_autodetect( cfi_array_t *cfi_array ) +{ + bus_area_t area; + + if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0) + return 0; + + return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS) + || (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS)) + && (area.width == 16); +} + +static int +intel_flash_autodetect8( cfi_array_t *cfi_array ) +{ + bus_area_t area; + + if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0) + return 0; + + return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS) + || (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS)) + && (area.width == 8); +} + +static void +_intel_flash_print_info( cfi_array_t *cfi_array, int o ) +{ + uint32_t mid, cid; + bus_t *bus = cfi_array->bus; + + mid = (bus_read( bus, cfi_array->address + (0x00 << o) ) & 0xFF); + switch (mid) { + case STD_MIC_INTEL: + printf( _("Manufacturer: %s\n"), STD_MICN_INTEL ); + break; + default: + printf( _("Unknown manufacturer (0x%04X)!\n"), mid); + break; + } + + printf( _("Chip: ") ); + cid = (bus_read( bus, cfi_array->address + (0x01 << o) ) & 0xFFFF); + switch (cid) { + case 0x0016: + printf( "28F320J3A\n" ); + break; + case 0x0017: + printf( "28F640J3A\n" ); + break; + case 0x0018: + printf( "28F128J3A\n" ); + break; + case 0x001D: + printf( "28F256J3A\n" ); + break; + case 0x8801: + printf( "28F640K3\n" ); + break; + case 0x8802: + printf( "28F128K3\n" ); + break; + case 0x8803: + printf( "28F256K3\n" ); + break; + case 0x8805: + printf( "28F640K18\n" ); + break; + case 0x8806: + printf( "28F128K18\n" ); + break; + case 0x8807: + printf( "28F256K18\n" ); + break; + case 0x880B: + printf( "GE28F640L18T\n" ); + break; + case 0x880C: + printf( "GE28F128L18T\n" ); + break; + case 0x880D: + printf( "GE28F256L18T\n" ); + break; + case 0x880E: + printf( "GE28F640L18B\n" ); + break; + case 0x880F: + printf( "GE28F128L18B\n" ); + break; + case 0x8810: + printf( "GE28F256L18B\n" ); + break; + default: + printf( _("Unknown (0x%02X)!\n"), cid ); + break; + } + + /* Read Array */ + bus_write( bus, cfi_array->address + (0 << o), 0x00FF00FF ); +} + +static void +intel_flash_print_info( cfi_array_t *cfi_array ) +{ + int o = 1; + bus_t *bus = cfi_array->bus; + + /* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */ + /* TODO */ + + /* Clear Status Register */ + bus_write( bus, cfi_array->address + (0 << o), 0x0050 ); + + /* Read Identifier Command */ + bus_write( bus, cfi_array->address + (0 << 0), 0x0090 ); + + _intel_flash_print_info( cfi_array, o ); +} + +static void +intel_flash_print_info32( cfi_array_t *cfi_array ) +{ + int o = 2; + bus_t *bus = cfi_array->bus; + /* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */ + /* TODO */ + + /* Clear Status Register */ + bus_write( bus, cfi_array->address + (0 << o), 0x00500050 ); + + /* Read Identifier Command */ + bus_write( bus, cfi_array->address + (0 << 0), 0x00900090 ); + + _intel_flash_print_info( cfi_array, o ); +} + +static int +intel_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + uint16_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, CFI_INTEL_CMD_BLOCK_ERASE ); + bus_write( bus, adr, CFI_INTEL_CMD_CONFIRM ); + + while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + switch (sr & ~CFI_INTEL_SR_READY) { + case 0: + return 0; + case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_PROGRAM_ERROR: + printf( _("flash: invalid command seq\n") ); + return FLASH_ERROR_INVALID_COMMAND_SEQUENCE; + case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_VPEN_ERROR: + printf( _("flash: low vpen\n") ); + return FLASH_ERROR_LOW_VPEN; + case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_BLOCK_LOCKED: + printf( _("flash: block locked\n") ); + return FLASH_ERROR_BLOCK_LOCKED; + default: + break; + } + + return FLASH_ERROR_UNKNOWN; +} + +static int +intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr ) +{ + uint16_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, CFI_INTEL_CMD_LOCK_SETUP ); + bus_write( bus, adr, CFI_INTEL_CMD_UNLOCK_BLOCK ); + + while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != CFI_INTEL_SR_READY) { + printf( _("flash: unknown error while unblocking\n") ); + return FLASH_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +{ + uint16_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, CFI_INTEL_CMD_PROGRAM1 ); + bus_write( bus, adr, data ); + + while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != CFI_INTEL_SR_READY) { + printf( _("flash: unknown error while programming\n") ); + return FLASH_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_erase_block32( cfi_array_t *cfi_array, uint32_t adr ) +{ + uint32_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, (CFI_INTEL_CMD_BLOCK_ERASE << 16) | CFI_INTEL_CMD_BLOCK_ERASE ); + bus_write( bus, adr, (CFI_INTEL_CMD_CONFIRM << 16) | CFI_INTEL_CMD_CONFIRM ); + + while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) { + printf( "\nsr = 0x%08X\n", sr ); + return FLASH_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr ) +{ + uint32_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, (CFI_INTEL_CMD_LOCK_SETUP << 16) | CFI_INTEL_CMD_LOCK_SETUP ); + bus_write( bus, adr, (CFI_INTEL_CMD_UNLOCK_BLOCK << 16) | CFI_INTEL_CMD_UNLOCK_BLOCK ); + + while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) { + printf( "\nsr = 0x%08X\n", sr ); + return FLASH_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data ) +{ + uint32_t sr; + bus_t *bus = cfi_array->bus; + + bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, (CFI_INTEL_CMD_PROGRAM1 << 16) | CFI_INTEL_CMD_PROGRAM1 ); + bus_write( bus, adr, data ); + + while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) { + printf( "\nsr = 0x%08X\n", sr ); + return FLASH_ERROR_UNKNOWN; + } else + return 0; +} + +static void +intel_flash_readarray32( cfi_array_t *cfi_array ) +{ + /* Read Array */ + bus_write( cfi_array->bus, cfi_array->address, 0x00FF00FF ); +} + +static void +intel_flash_readarray( cfi_array_t *cfi_array ) +{ + /* Read Array */ + bus_write( cfi_array->bus, cfi_array->address, 0x00FF00FF ); +} + +flash_driver_t intel_32_flash_driver = { + 4, /* buswidth */ + N_("Intel Standard Command Set"), + N_("supported: 28Fxxxx, 2 x 16 bit"), + intel_flash_autodetect32, + intel_flash_print_info32, + intel_flash_erase_block32, + intel_flash_unlock_block32, + intel_flash_program32, + intel_flash_readarray32, +}; + +flash_driver_t intel_16_flash_driver = { + 2, /* buswidth */ + N_("Intel Standard Command Set"), + N_("supported: 28Fxxxx, 1 x 16 bit"), + intel_flash_autodetect, + intel_flash_print_info, + intel_flash_erase_block, + intel_flash_unlock_block, + intel_flash_program, + intel_flash_readarray, +}; + +flash_driver_t intel_8_flash_driver = { + 1, /* buswidth */ + N_("Intel Standard Command Set"), + N_("supported: 28Fxxxx, 1 x 8 bit"), + intel_flash_autodetect8, + intel_flash_print_info, + intel_flash_erase_block, + intel_flash_unlock_block, + intel_flash_program, + intel_flash_readarray, +}; diff --git a/jtag/src/flash/jedec.c b/jtag/src/flash/jedec.c new file mode 100644 index 00000000..e94c27f6 --- /dev/null +++ b/jtag/src/flash/jedec.c @@ -0,0 +1,490 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Manufacturers */ +#define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F +#define MANUFACTURER_FUJITSU 0x0004 +#define MANUFACTURER_ST 0x0020 +#define MANUFACTURER_SST 0x00BF +#define MANUFACTURER_TOSHIBA 0x0098 +#define MANUFACTURER_MX 0x00C2 + +/* AMD */ +#define AM29F800BB 0x2258 +#define AM29F800BT 0x22D6 +#define AM29LV800BB 0x225B +#define AM29LV800BT 0x22DA +#define AM29LV160DT 0x22C4 +#define AM29LV160DB 0x2249 +#define AM29BDS323D 0x22D1 +#define AM29BDS643D 0x227E +#define AM29LV040B 0x004F + +/* Atmel */ +#define AT49xV16x 0x00C0 +#define AT49xV16xT 0x00C2 + +/* Fujitsu */ +#define MBM29LV160TE 0x22C4 +#define MBM29LV160BE 0x2249 +#define MBM29LV800BB 0x225B + +/* ST - www.st.com */ +#define M29W800T 0x00D7 +#define M29W160DT 0x22C4 +#define M29W160DB 0x2249 + +/* SST */ +#define SST39LF800 0x2781 +#define SST39LF160 0x2782 + +/* Toshiba */ +#define TC58FVT160 0x00C2 +#define TC58FVB160 0x0043 + +/* MX */ +#define MX29LV400T 0x22B9 + +/* Autoselect methods */ +#define AUTOSELECT_M1 0 +#define AUTOSELECT_M2 1 +#define AUTOSELECT_NUM 2 + +struct mtd_erase_region_info { + u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ + u_int32_t erasesize; /* For this region */ + u_int32_t numblocks; /* Number of blocks of erasesize in this region */ +}; + +struct amd_flash_info { + const int mfr_id; + const int dev_id; + const char *name; + const long size; + const u_int8_t interface_width; + const int as_method; + const int numeraseregions; + const struct mtd_erase_region_info regions[4]; +}; + +static const struct amd_flash_info table[] = { + { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DT, + .name = "AMD AM29LV160DT", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DB, + .name = "AMD AM29LV160DB", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT160, + .name = "Toshiba TC58FVT160", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160TE, + .name = "Fujitsu MBM29LV160TE", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB160, + .name = "Toshiba TC58FVB160", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160BE, + .name = "Fujitsu MBM29LV160BE", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BB, + .name = "AMD AM29F800BB", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BT, + .name = "AMD AM29LV800BT", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BT, + .name = "AMD AM29F800BT", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800BB, + .name = "Fujitsu MBM29LV800BB", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } + } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W800T, + .name = "ST M29W800T", + .size = 0x00100000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W160DT, + .name = "ST M29W160DT", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W160DB, + .name = "ST M29W160DB", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29BDS323D, + .name = "AMD AM29BDS323D", + .size = 0x00400000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 3, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, + { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, + { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29BDS643D, + .name = "AMD AM29BDS643D", + .size = 0x00800000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 3, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, + { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16x, + .name = "Atmel AT49xV16x", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16xT, + .name = "Atmel AT49xV16xT", + .size = 0x00200000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } + } + }, { + .mfr_id = MANUFACTURER_MX, + .dev_id = MX29LV400T, + .name = "MX 29LV400T", + .size = 0x0080000, + .interface_width = CFI_INTERFACE_X16, /* correct default? */ + .as_method = AUTOSELECT_M1, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 7 }, + { .offset = 0x070000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x078000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x07c000, .erasesize = 0x04000, .numblocks = 1 }, + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV040B, + .name = "AMD AM29LV040B", + .size = 0x0080000, + .interface_width = CFI_INTERFACE_X8, /* checked, ok */ + .as_method = AUTOSELECT_M2, + .numeraseregions = 1, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 8 }, + } + } +}; + +int +jedec_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ) +{ + /* Temporary containers for manufacturer and device id while + probing with different Autoselect methods. */ + int manid_as[AUTOSELECT_NUM], devid_as[AUTOSELECT_NUM]; + int manid = 0, devid = 0; + int ba, bw; + int i, j; + cfi_query_structure_t *cfi; + bus_area_t area; + + *cfi_array = calloc( 1, sizeof (cfi_array_t) ); + if (!*cfi_array) + return -2; /* out of memory */ + + (*cfi_array)->bus = bus; + (*cfi_array)->address = adr; + if (bus_area( bus, adr, &area ) != 0) + return -8; /* bus width detection failed */ + bw = area.width; + if (bw != 8 && bw != 16 && bw != 32) + return -3; /* invalid bus width */ + (*cfi_array)->bus_width = ba = bw / 8; + + (*cfi_array)->cfi_chips = calloc( 1, sizeof (cfi_chip_t *) ); + if (!(*cfi_array)->cfi_chips) + return -2; /* out of memory */ + + (*cfi_array)->cfi_chips[0] = calloc( 1, sizeof (cfi_chip_t) ); + if (!(*cfi_array)->cfi_chips[0]) + return -2; /* out of memory */ + + /* probe device with Autoselect method 1 */ + bus_write(bus, adr, 0xf0); + bus_write(bus, adr+0xaaa, 0xaa); + bus_write(bus, adr+0x555, 0x55); + bus_write(bus, adr+0xaaa, 0x90); + + manid_as[AUTOSELECT_M1] = bus_read(bus, adr+0); + devid_as[AUTOSELECT_M1] = bus_read(bus, adr+2); + bus_write(bus, adr, 0xf0); + + /* probe device with Autoselect method 2 */ + bus_write(bus, adr, 0xf0); + bus_write(bus, adr+0x555, 0xaa); + bus_write(bus, adr+0x2aa, 0x55); + bus_write(bus, adr+0x555, 0x90); + + manid_as[AUTOSELECT_M2] = bus_read(bus, adr+0); + devid_as[AUTOSELECT_M2] = bus_read(bus, adr+1); + bus_write(bus, adr, 0xf0); + + for(i=0 ; icfi_chips[0]->cfi; + + cfi->identification_string.pri_id_code = CFI_VENDOR_AMD_SCS; + cfi->identification_string.pri_vendor_tbl = NULL; + cfi->identification_string.alt_id_code = 0; + cfi->identification_string.alt_vendor_tbl = NULL; + + cfi->device_geometry.device_size = table[i].size; + /* annotate chip width */ + cfi->device_geometry.device_interface = table[i].interface_width; + switch (table[i].interface_width) { + case CFI_INTERFACE_X8: + (*cfi_array)->cfi_chips[0]->width = 1; + break; + case CFI_INTERFACE_X16: + (*cfi_array)->cfi_chips[0]->width = 2; + break; + case CFI_INTERFACE_X8_X16: + fprintf(stderr, "Warning: Unsupported interface geometry %s, falling back to %s\n", "CFI_INTERFACE_X8_X16", "CFI_INTERFACE_X16"); + (*cfi_array)->cfi_chips[0]->width = 2; + cfi->device_geometry.device_interface = CFI_INTERFACE_X16; + break; + case CFI_INTERFACE_X32: + (*cfi_array)->cfi_chips[0]->width = 4; + break; + case CFI_INTERFACE_X16_X32: + fprintf(stderr, "Warning: Unsupported interface geometry %s, falling back to %s\n", "CFI_INTERFACE_X16_X32", "CFI_INTERFACE_X32"); + (*cfi_array)->cfi_chips[0]->width = 4; + cfi->device_geometry.device_interface = CFI_INTERFACE_X32; + break; + default: + /* unsupported interface geometry */ + fprintf(stderr, "Error: Unsupported interface geometry %d, bailing out\n", table[i].interface_width); + (*cfi_array)->cfi_chips[0]->width = 1; + cfi->device_geometry.device_interface = CFI_INTERFACE_X8; + return -5; + break; + } + + cfi->device_geometry.number_of_erase_regions = table[i].numeraseregions; + + cfi->device_geometry.erase_block_regions = + malloc( cfi->device_geometry.number_of_erase_regions * sizeof (cfi_erase_block_region_t) ); + if (!cfi->device_geometry.erase_block_regions) + return -2; /* out of memory */ + + for(j=0;jdevice_geometry.number_of_erase_regions; j++) { + cfi->device_geometry.erase_block_regions[j].erase_block_size = + table[i].regions[j].erasesize; + cfi->device_geometry.erase_block_regions[j].number_of_erase_blocks = + table[i].regions[j].numblocks; + } + + fprintf(stderr, "Found %s flash, size = %li bytes.\n", table[i].name, table[i].size); + + return 0; +} + diff --git a/jtag/src/readmem.c b/jtag/src/readmem.c index 89c4f179..f6d8480b 100644 --- a/jtag/src/readmem.c +++ b/jtag/src/readmem.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "bus.h" #include "flash.h" diff --git a/jtag/src/svf/svf.c b/jtag/src/svf/svf.c index 8849d7a7..f9cd4af8 100644 --- a/jtag/src/svf/svf.c +++ b/jtag/src/svf/svf.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include "svf.h" #include "svf_bison.h" diff --git a/jtag/src/tap/cable/generic.c b/jtag/src/tap/cable/generic.c index 9a8b2349..38c21370 100644 --- a/jtag/src/tap/cable/generic.c +++ b/jtag/src/tap/cable/generic.c @@ -34,7 +34,7 @@ #include "generic.h" -#include +#include int generic_connect( char *params[], cable_t *cable ) diff --git a/jtag/src/tap/cable/vision_ep9307.c b/jtag/src/tap/cable/vision_ep9307.c index 7aefea1a..84aa5bfe 100644 --- a/jtag/src/tap/cable/vision_ep9307.c +++ b/jtag/src/tap/cable/vision_ep9307.c @@ -39,7 +39,7 @@ #include "generic.h" -#include +#include #define SYSCON_BASE 0x80930000 #define SYSCON_DEVICE_CONFIG 0x80 diff --git a/jtag/src/tap/cable/wiggler.c b/jtag/src/tap/cable/wiggler.c index 8c9d1058..75711f12 100644 --- a/jtag/src/tap/cable/wiggler.c +++ b/jtag/src/tap/cable/wiggler.c @@ -39,7 +39,7 @@ #include "generic.h" -#include +#include /* * Bit <-> pin mapping of an original Wiggler diff --git a/jtag/src/writemem.c b/jtag/src/writemem.c index 84149d25..1259b560 100644 --- a/jtag/src/writemem.c +++ b/jtag/src/writemem.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "bus.h" #include "flash.h"