diff -Naur ../org/configure ./configure --- ../org/configure 2004-10-16 13:40:04.000000000 +0200 +++ ./configure 2007-08-09 17:56:42.000000000 +0200 @@ -3064,13 +3064,13 @@ fi -echo "$as_me:$LINENO: checking for tputs in -ltermcap" >&5 -echo $ECHO_N "checking for tputs in -ltermcap... $ECHO_C" >&6 -if test "${ac_cv_lib_termcap_tputs+set}" = set; then +echo "$as_me:$LINENO: checking for tputs in -lncurses" >&5 +echo $ECHO_N "checking for tputs in -lncurses... $ECHO_C" >&6 +if test "${ac_cv_lib_tncurses_tputs+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-ltermcap $LIBS" +LIBS="-lncurses $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" /* confdefs.h. */ @@ -3106,24 +3106,24 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_termcap_tputs=yes + ac_cv_lib_tncurses_tputs=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_termcap_tputs=no +ac_cv_lib_ncurses_tputs=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_termcap_tputs" >&5 -echo "${ECHO_T}$ac_cv_lib_termcap_tputs" >&6 -if test $ac_cv_lib_termcap_tputs = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tputs" >&5 +echo "${ECHO_T}$ac_cv_lib_ncurses_tputs" >&6 +if test $ac_cv_lib_ncurses_tputs = yes; then cat >>confdefs.h <<_ACEOF -#define HAVE_LIBTERMCAP 1 +#define HAVE_LIBNCURSES 1 _ACEOF - LIBS="-ltermcap $LIBS" + LIBS="-lncurses $LIBS" fi diff -Naur ../org/configure.ac ./configure.ac --- ../org/configure.ac 2004-10-17 15:54:31.000000000 +0200 +++ ./configure.ac 2007-08-09 17:57:42.000000000 +0200 @@ -67,7 +67,7 @@ # AC_CHECK_LIB([m], [pow]) AC_CHECK_LIB([readline], [readline]) -AC_CHECK_LIB([termcap], [tputs]) +AC_CHECK_LIB([ncurses], [tputs]) # # [6] Checks for header files. diff -Naur ../org/include/config.h.in ./include/config.h.in --- ../org/include/config.h.in 2004-09-26 05:59:34.000000000 +0200 +++ ./include/config.h.in 2007-08-09 17:58:35.000000000 +0200 @@ -33,8 +33,8 @@ /* Define to 1 if you have the `readline' library (-lreadline). */ #undef HAVE_LIBREADLINE -/* Define to 1 if you have the `termcap' library (-ltermcap). */ -#undef HAVE_LIBTERMCAP +/* Define to 1 if you have the `ncurses' library (-lncurses). */ +#undef HAVE_LIBNCURSES /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ diff -Naur ../org/src/Makefile.am ./src/Makefile.am --- ../org/src/Makefile.am 2004-10-17 15:54:32.000000000 +0200 +++ ./src/Makefile.am 2007-08-09 17:59:07.000000000 +0200 @@ -27,7 +27,7 @@ target/libtarget.a jtager_LDADD = \ - -lm -lreadline -ltermcap \ + -lm -lreadline -lncurses \ -Lconf -lconf \ -Lcmdline -lcmdline \ -Ljtag -ljtag \ diff -Naur ../org/src/Makefile.in ./src/Makefile.in --- ../org/src/Makefile.in 2004-10-17 15:48:26.000000000 +0200 +++ ./src/Makefile.in 2007-08-09 17:59:20.000000000 +0200 @@ -104,7 +104,7 @@ jtager_LDADD = \ - -lm -lreadline -ltermcap \ + -lm -lreadline -lncurses \ -Lconf -lconf \ -Lcmdline -lcmdline \ -Ljtag -ljtag \ diff -Naur ../org/src/jtag/jtag.c ./src/jtag/jtag.c --- ../org/src/jtag/jtag.c 2004-10-17 10:04:28.000000000 +0200 +++ ./src/jtag/jtag.c 2007-08-09 17:53:31.000000000 +0200 @@ -427,7 +427,7 @@ outb(JTAG_TRST_MASK, par_dataport); /* LOW */ usleep(100); outb(0, par_dataport); /* HIGH */ - usleep(100); + sleep(2); /* * No matter what the original state of the TAP controller, it will diff -Naur ../org/src/mtd/Makefile.am ./src/mtd/Makefile.am --- ../org/src/mtd/Makefile.am 2004-09-26 05:59:41.000000000 +0200 +++ ./src/mtd/Makefile.am 2007-08-09 17:24:13.000000000 +0200 @@ -10,4 +10,6 @@ libmtd_a_SOURCES = \ flash.c \ sst39vf160.c \ + s29al016b.c \ + am29lv800bb.c \ mbm29lv650.c diff -Naur ../org/src/mtd/Makefile.in ./src/mtd/Makefile.in --- ../org/src/mtd/Makefile.in 2004-09-26 05:59:41.000000000 +0200 +++ ./src/mtd/Makefile.in 2007-08-09 17:24:55.000000000 +0200 @@ -84,6 +84,8 @@ libmtd_a_SOURCES = \ flash.c \ sst39vf160.c \ + s29al016b.c \ + am29lv800bb.c \ mbm29lv650.c subdir = src/mtd @@ -95,7 +97,7 @@ libmtd_a_AR = $(AR) cru libmtd_a_LIBADD = am_libmtd_a_OBJECTS = flash.$(OBJEXT) sst39vf160.$(OBJEXT) \ - mbm29lv650.$(OBJEXT) + s29al016b.$(OBJEXT) am29lv800bb.$(OBJEXT) mbm29lv650.$(OBJEXT) libmtd_a_OBJECTS = $(am_libmtd_a_OBJECTS) DEFS = @DEFS@ @@ -106,7 +108,8 @@ depcomp = $(SHELL) $(top_srcdir)/tools/depcomp am__depfiles_maybe = depfiles @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/flash.Po ./$(DEPDIR)/mbm29lv650.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/sst39vf160.Po +@AMDEP_TRUE@./$(DEPDIR)/s29al016b.Po ./$(DEPDIR)/am29lv800bb.Po ./$(DEPDIR)/sst39vf160.Po + COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -144,6 +147,8 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flash.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbm29lv650.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sst39vf160.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s29al016b.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/am29lv800bb.Po@am__quote@ distclean-depend: -rm -rf ./$(DEPDIR) diff -Naur ../org/src/mtd/am29lv800bb.c ./src/mtd/am29lv800bb.c --- ../org/src/mtd/am29lv800bb.c 1970-01-01 01:00:00.000000000 +0100 +++ ./src/mtd/am29lv800bb.c 2007-08-09 17:54:08.000000000 +0200 @@ -0,0 +1,280 @@ +/* + * mtd/am29lv800bb.c : implements the operations to mbm29lv650 flash chip. + * + * Copyright (C) 2003, Rongkai Zhan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "jtager.h" +#include "target.h" +#include "flash.h" + +#define MANU_ID 0x0001 /* AMD Manufacturer ID code */ +#define DEVICE_ID 0x225B /* am29lv800bb device code */ + +#define SECTOR_SIZE (32 * 1024 * 2) /* 32K words = 64K Bytes */ +#define CHIP_SIZE (1024 * 1024 * 1) /* 512K words = 1M Bytes */ +#define CHIP_BASE (am29lv800bb.base) +#define SECTOR_MASK (SECTOR_SIZE - 1) + +#define CMD_ADDR1 (am29lv800bb.base + (0x5555 << 1)) +#define CMD_ADDR2 (am29lv800bb.base + (0x2aaa << 1)) + +#define DQ5_MASK 0x20 +#define DQ6_MASK 0x40 +#define DQ7_MASK 0x80 + +flash_t am29lv800bb; + +static int chip_probe(u32 base) +{ + u16 id1 = 0, id2 = 0; + u16 softid_cmd[4] = {0xAAAA, 0x5555, 0x9090, 0xF0F0}; + u16 old1, old2; + u32 old_base = CHIP_BASE; + int ret; + + CHIP_BASE = base; /* update chip base address */ + + /* save the contents of these two memory units */ + old1 = read16(CMD_ADDR1); + old2 = read16(CMD_ADDR2); + + /* write ID commands */ + write16(softid_cmd[0], CMD_ADDR1); + write16(softid_cmd[1], CMD_ADDR2); + write16(softid_cmd[2], CMD_ADDR1); + + /* read MANU_ID & DEVICE_ID */ + id1 = read16(base + (0x00 << 1)); + id2 = read16(base + (0x01 << 1)); + + /* check Manufacture ID and Device ID */ + if ((id1 == MANU_ID) && (id2 == DEVICE_ID)) + ret = 0; + else + ret = -1; + + /* Software ID Exit / CFI Exit */ + write16(softid_cmd[0], CMD_ADDR1); + write16(softid_cmd[1], CMD_ADDR2); + write16(softid_cmd[3], CMD_ADDR1); + + if (ret) { + CHIP_BASE = old_base; + write16(old1, CMD_ADDR1); + write16(old2, CMD_ADDR2); + } + return ret; +} + +/* + * DQ6 is still toggling bit? + */ +static int chip_is_busy(u32 addr) +{ + u16 oldval, newval; + u32 count = 0; + int ret = -1, timeout = 0; + + addr = addr16_align(addr); + + while (1) { + oldval = read16(addr); + newval = read16(addr); + if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) { + /* DQ6 stops toggle */ + ret = 0; + break; + } + + /* DQ5 = 1? */ + if (newval & DQ5_MASK) { + /* exceed timing limits */ + timeout = 1; + break; + } + + count++; + if (count > 0xF0000000) { + timeout = 1; + break; + } + } + + if (timeout) { + /* + * oh, this is the last chance for success. + */ + oldval = read16(addr); + newval = read16(addr); + if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) + ret = 0; + else + ret = -1; + } + return ret; +} + +/* + * DQ7 Data Polling + */ +static int __attribute__((__unused__)) data_polling(u32 addr, u16 true_data) +{ + u16 value; + int ret; + u32 timeout = 0x10000000; + + ret = -1; + while (timeout) { + value = read16(addr); + if ((value & DQ7_MASK) == (true_data & DQ7_MASK)) { + ret = 0; + break; + } + timeout--; + } + return ret; +} /* end of data_polling(...) */ + +/** + * erase_sector - erase one sector + * @addr: any address in the sector to be erased. + * + * Return value: If success, return 0. Otherwise, return -1. + */ +static int erase_sector(u32 addr) +{ + u16 erase_sector_cmd[6] = {0xAAAA, 0x5555, 0x8080, + 0xAAAA, 0x5555, 0x3030}; + u32 sector_addr = addr & (~((u32)SECTOR_SIZE - 1)); + int ret; + + write16(erase_sector_cmd[0], CMD_ADDR1); + write16(erase_sector_cmd[1], CMD_ADDR2); + write16(erase_sector_cmd[2], CMD_ADDR1); + write16(erase_sector_cmd[3], CMD_ADDR1); + write16(erase_sector_cmd[4], CMD_ADDR2); + write16(erase_sector_cmd[5], sector_addr); + + /* chip is busy ? */ + sector_addr += (SECTOR_SIZE - 2); + ret = chip_is_busy(sector_addr); + return ret; +} /* end of erase_sector(...) */ + +static int erase_chip(void) +{ + u16 erase_chip_cmd[6] = {0xAAAA, 0x5555, 0x8080, + 0xAAAA, 0x5555, 0x1010}; + u32 base, wait = 500000; + int ret; + + write16(erase_chip_cmd[0], CMD_ADDR1); + write16(erase_chip_cmd[1], CMD_ADDR2); + write16(erase_chip_cmd[2], CMD_ADDR1); + write16(erase_chip_cmd[3], CMD_ADDR1); + write16(erase_chip_cmd[4], CMD_ADDR2); + write16(erase_chip_cmd[5], CMD_ADDR1); + + /* + * Chip erase is a long way, we just wait for a while. + */ + while (wait) + wait--; + + base = CHIP_BASE + (CHIP_SIZE - 2); + ret = chip_is_busy(base); + + return ret; +} /* end of erase_chip() */ + +/** + * flash_write - write flash memory with the source data from target memory or host buffer + * @start_address: The flash start address to be written. + * @bytenr: how many bytes are to be written. + * @source_address: The address of source data. + * @from_host: If from_host == 0, we read the source data from a target memory block + * If from_host != 0, we read the source data from a host buffer. + */ +static int flash_write(u32 start_address, u32 bytenr, u32 source_address, int from_host) +{ + u16 pgm_cmd[3] = {0xAAAA, 0x5555, 0xA0A0}; + u32 current_addr; + int i, retry, ret; + u16 data; + + if ((start_address < CHIP_BASE) + || (start_address + bytenr - 1) > (CHIP_BASE + CHIP_SIZE - 1)) + return -1; /* out of range */ + + /* align address with the 16-bit word boundary */ + current_addr = addr16_align(start_address); + + for (i = 0; i < (bytenr/2); i++) { + if (from_host) + data = *(u16 *)source_address; /* read data from host buffer */ + else + data = read16(source_address); + source_address += 2; + if (data == 0xFFFF) { + current_addr += 2; + continue; + } + retry = 0; +retry_pgm: + write16(pgm_cmd[0], CMD_ADDR1); + write16(pgm_cmd[1], CMD_ADDR2); + write16(pgm_cmd[2], CMD_ADDR1); + write16(data, current_addr); + + ret = chip_is_busy(current_addr); + if (ret && retry < 3) { + retry++; + goto retry_pgm; + } else if (ret) { + break; /* failure */ + } + + current_addr += 2; + if ((i + 1)%(2*1024) == 0) { + printf("."); + fflush(stdout); + } + } /* end of for (i = 0; ... ) */ + + return ret; +} /* end of flash_write(...) */ + +flash_t am29lv800bb = { + .name = "am29lv800bb", + .mfr_id = MANU_ID, + .dev_id = DEVICE_ID, + .base = 0x0L, /* start physical address */ + .chip_size = CHIP_SIZE, + .sector_size = SECTOR_SIZE, + .bus_width = 16, + + .probe = chip_probe, + .erase_sector = erase_sector, + .erase_chip = erase_chip, + .write = flash_write, +}; diff -Naur ../org/src/mtd/flash.c ./src/mtd/flash.c --- ../org/src/mtd/flash.c 2004-10-17 10:04:28.000000000 +0200 +++ ./src/mtd/flash.c 2007-08-09 17:33:54.000000000 +0200 @@ -31,11 +31,15 @@ extern flash_t sst39vf160; extern flash_t mbm29lv650; +extern flash_t am29lv800bb; +extern flash_t s29al016b; /* all supported flash chips */ flash_t * flashes[] = { &mbm29lv650, &sst39vf160, + &am29lv800bb, + &s29al016b, NULL /* the last element must be NULL */ }; diff -Naur ../org/src/mtd/s29al016b.c ./src/mtd/s29al016b.c --- ../org/src/mtd/s29al016b.c 1970-01-01 01:00:00.000000000 +0100 +++ ./src/mtd/s29al016b.c 2007-08-10 12:35:05.000000000 +0200 @@ -0,0 +1,266 @@ +/* + * mtd/s29al016b.c : implements the read/write ops of + * Spansion S29AL016 Bottom Bootblock flash chip. + * + * Copyright (C) 2003, Rongkai Zhan + * Copyright (C) 2007, Arne Fitzenreiter + * + * 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 + */ + +/* $Id: s29al016b.c,v 1.0 2007/08/10 10:00:00 arne Exp $ */ + +/* + * References: + * [1] <> + */ + +#include +#include +#include +#include + +#include "jtager.h" +#include "target.h" +#include "flash.h" + +#define MANU_ID 0x0001 /* Spansion Manufacturer code */ +#define DEVICE_ID 0x2249 /* S29AL016 Bootomboot device code */ +/* + * The bootblock sectors are not implementet yet. To overwrite this area you + * have to erase the whole chip + */ +#define SECTOR_SIZE (32 * 1024 * 2) /* 32K words = 64K Bytes */ +#define CHIP_SIZE (1024 * 1024 * 2) /* 1M words = 2M Bytes */ +#define CHIP_BASE (s29al016b.base) + +#define SECTOR_MASK (SECTOR_SIZE - 1) + +#define CMD_ADDR1 (s29al016b.base + (0x5555 << 1)) +#define CMD_ADDR2 (s29al016b.base + (0x2aaa << 1)) + +#define DQ6_MASK 0x40 +#define DQ7_MASK 0x80 + +flash_t s29al016b; + +static int chip_probe(u32 base) +{ + u16 id1 = 0, id2 = 0; + u16 softid_cmd[4] = {0xAAAA, 0x5555, 0x9090, 0xF0F0}; + u16 old1, old2; + u32 old_base = CHIP_BASE; + int ret; + + CHIP_BASE = base; /* update chip base address */ + + /* save the contents of these two memory units */ + old1 = read16(CMD_ADDR1); + old2 = read16(CMD_ADDR2); + + /* write ID commands */ + write16(softid_cmd[0], CMD_ADDR1); + write16(softid_cmd[1], CMD_ADDR2); + write16(softid_cmd[2], CMD_ADDR1); + + /* read MANU_ID & DEVICE_ID */ + id1 = read16(base + (0x00 << 1)); + id2 = read16(base + (0x01 << 1)); + +// printf("ID1:%X ID2:%X ",id1,id2); + + /* check Manufacture ID and Device ID */ + if ((id1 == MANU_ID) && (id2 == DEVICE_ID)) + ret = 0; + else + ret = -1; + + /* Software ID Exit / CFI Exit */ + write16(softid_cmd[0], CMD_ADDR1); + write16(softid_cmd[1], CMD_ADDR2); + write16(softid_cmd[3], CMD_ADDR1); + + if (ret) { + CHIP_BASE = old_base; + write16(old1, CMD_ADDR1); + write16(old2, CMD_ADDR2); + } + return ret; +} /* end of chip_probe (...) */ + +/* + * DQ6 is still toggling bit? + */ +static int chip_is_busy(u32 addr) +{ + u16 oldval, newval; + u32 count = 0; + int ret = -1, timeout = 0; + + addr = addr16_align(addr); + + while (1) { + oldval = read16(addr); + newval = read16(addr); + if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) { + /* DQ6 stops toggle */ + ret = 0; + break; + } + + count++; + if (count > 0xF0000000) { + timeout = 1; + break; + } + } + + if (timeout) { + /* + * oh, this is the last chance for success. + */ + oldval = read16(addr); + newval = read16(addr); + if ((oldval & DQ6_MASK) == (newval & DQ6_MASK)) + ret = 0; + else + ret = -1; + } + return ret; +} + +/** + * erase_sector - erase one sector + * @addr: any address in the sector to be erased. + * + * Return value: If success, return 0. Otherwise, return -1. + */ +static int erase_sector(u32 addr) +{ + u16 erase_sector_cmd[6] = {0xAAAA, 0x5555, 0x8080, + 0xAAAA, 0x5555, 0x3030}; + u32 sector_addr = addr & (~((u32)SECTOR_SIZE - 1)); + int ret; + + write16(erase_sector_cmd[0], CMD_ADDR1); + write16(erase_sector_cmd[1], CMD_ADDR2); + write16(erase_sector_cmd[2], CMD_ADDR1); + write16(erase_sector_cmd[3], CMD_ADDR1); + write16(erase_sector_cmd[4], CMD_ADDR2); + write16(erase_sector_cmd[5], sector_addr); + + /* chip is busy ? */ + sector_addr += (SECTOR_SIZE - 2); + ret = chip_is_busy(sector_addr); + return ret; +} /* end of erase_sector(...) */ + +static int erase_chip(void) +{ + u16 erase_chip_cmd[6] = {0xAAAA, 0x5555, 0x8080, + 0xAAAA, 0x5555, 0x1010}; + u32 base, wait = 500000; + int ret; + + write16(erase_chip_cmd[0], CMD_ADDR1); + write16(erase_chip_cmd[1], CMD_ADDR2); + write16(erase_chip_cmd[2], CMD_ADDR1); + write16(erase_chip_cmd[3], CMD_ADDR1); + write16(erase_chip_cmd[4], CMD_ADDR2); + write16(erase_chip_cmd[5], CMD_ADDR1); + + /* + * Chip erase is a long way, we just wait for a while. + */ + while (wait) + wait--; + + base = CHIP_BASE + (CHIP_SIZE - 2); + ret = chip_is_busy(base); + + return ret; +} /* end of erase_chip() */ + +/** + * flash_write - write flash memory with the source data from target memory or host buffer + * @start_address: The flash start address to be written. + * @bytenr: how many bytes are to be written. + * @source_address: The address of source data. + * @from_host: If from_host == 0, we read the source data from a target memory block + * If from_host != 0, we read the source data from a host buffer. + */ +static int flash_write(u32 start_address, u32 bytenr, u32 source_address, int from_host) +{ + u16 pgm_cmd[3] = {0xAAAA, 0x5555, 0xA0A0}; + u32 current_addr; + int i, retry, ret; + u16 data; + + if ((start_address < CHIP_BASE) + || (start_address + bytenr - 1) > (CHIP_BASE + CHIP_SIZE - 1)) + return -1; /* out of range */ + + /* align address with the 16-bit word boundary */ + current_addr = addr16_align(start_address); + + for (i = 0; i < (bytenr/2); i++) { + if (from_host) + data = *(u16 *)source_address; /* read data from host buffer */ + else + data = read16(source_address); + source_address += 2; + if (data == 0xFFFF) { + current_addr += 2; + continue; + } + retry = 0; +retry_pgm: + write16(pgm_cmd[0], CMD_ADDR1); + write16(pgm_cmd[1], CMD_ADDR2); + write16(pgm_cmd[2], CMD_ADDR1); + write16(data, current_addr); + + ret = chip_is_busy(current_addr); + if (ret && retry < 3) { + retry++; + goto retry_pgm; + } else if (ret) { + break; /* failure */ + } + + current_addr += 2; + if ((i + 1)%(2*1024) == 0) { + printf("."); + fflush(stdout); + } + } /* end of for (i = 0; ... ) */ + + return ret; +} /* end of flash_write(...) */ + +flash_t s29al016b = { + .name = "s29al016b", + .mfr_id = MANU_ID, + .dev_id = DEVICE_ID, + .base = 0x0L, /* start physical address */ + .chip_size = CHIP_SIZE, + .sector_size = SECTOR_SIZE, + .bus_width = 16, + + .probe = chip_probe, + .erase_sector = erase_sector, + .erase_chip = erase_chip, + .write = flash_write, +};