diff --git a/.cvsignore b/.cvsignore index 2636fe9..700b2c8 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -flashrom-0.9.1.tar.bz2 +flashrom-0.9.2.tar.bz2 diff --git a/flashrom-0.9.1.tar.bz2.asc b/flashrom-0.9.1.tar.bz2.asc deleted file mode 100644 index 57c82a2..0000000 --- a/flashrom-0.9.1.tar.bz2.asc +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN PGP SIGNATURE----- -Version: GnuPG v2.0.4-svn0 (GNU/Linux) - -iD8DBQBKnov8RdNMz2eF/AERAr2mAJ9mkXCumIdebw0OsjUe+pghuo3huwCg81Pj -lPXfOR1NtZWm/R9G8JN0WWA= -=e1RW ------END PGP SIGNATURE----- diff --git a/flashrom-0.9.2.tar.bz2.asc b/flashrom-0.9.2.tar.bz2.asc new file mode 100644 index 0000000..beb8db6 --- /dev/null +++ b/flashrom-0.9.2.tar.bz2.asc @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.4-svn0 (GNU/Linux) + +iD8DBQBMBr4iRdNMz2eF/AERApwwAKDmS3Vic3XoKJ8AfcheBy39wNcWGwCgzMK/ +EmgHzE4fu1YkkTi1zfpnO9g= +=U3pC +-----END PGP SIGNATURE----- diff --git a/flashrom-r710-r995.diff b/flashrom-r710-r995.diff deleted file mode 100644 index 602dca0..0000000 --- a/flashrom-r710-r995.diff +++ /dev/null @@ -1,23477 +0,0 @@ -diff --git a/82802ab.c b/82802ab.c -index 28fa177..c9d1a75 100644 ---- a/82802ab.c -+++ b/82802ab.c -@@ -29,51 +29,63 @@ - #include - #include - #include "flash.h" -+#include "chipdrivers.h" - - // I need that Berkeley bit-map printer --void print_82802ab_status(uint8_t status) -+void print_status_82802ab(uint8_t status) - { -- printf("%s", status & 0x80 ? "Ready:" : "Busy:"); -- printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); -- printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); -- printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); -- printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); -- printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); -- printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); -+ msg_cdbg("%s", status & 0x80 ? "Ready:" : "Busy:"); -+ msg_cdbg("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); -+ msg_cdbg("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); -+ msg_cdbg("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); -+ msg_cdbg("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); -+ msg_cdbg("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); -+ msg_cdbg("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); - } - - int probe_82802ab(struct flashchip *flash) - { - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; -+ uint8_t flashcontent1, flashcontent2; -+ int shifted = (flash->feature_bits & FEATURE_ADDR_SHIFTED) != 0; - --#if 0 -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x90, bios + 0x5555); --#endif -- -- chip_writeb(0xff, bios); -+ /* Reset to get a clean state */ -+ chip_writeb(0xFF, bios); - programmer_delay(10); -+ -+ /* Enter ID mode */ - chip_writeb(0x90, bios); - programmer_delay(10); - -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -+ id1 = chip_readb(bios + (0x00 << shifted)); -+ id2 = chip_readb(bios + (0x01 << shifted)); - - /* Leave ID mode */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); -+ chip_writeb(0xFF, bios); - - programmer_delay(10); - -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2); -+ -+ if (!oddparity(id1)) -+ msg_cdbg(", id1 parity violation"); - -+ /* Read the product ID location again. We should now see normal flash contents. */ -+ flashcontent1 = chip_readb(bios + (0x00 << shifted)); -+ flashcontent2 = chip_readb(bios + (0x01 << shifted)); -+ -+ if (id1 == flashcontent1) -+ msg_cdbg(", id1 is normal flash content"); -+ if (id2 == flashcontent2) -+ msg_cdbg(", id2 is normal flash content"); -+ -+ msg_cdbg("\n"); - if (id1 != flash->manufacture_id || id2 != flash->model_id) - return 0; - -- map_flash_registers(flash); -+ if (flash->feature_bits & FEATURE_REGISTERMAP) -+ map_flash_registers(flash); - - return 1; - } -@@ -81,7 +93,6 @@ int probe_82802ab(struct flashchip *flash) - uint8_t wait_82802ab(chipaddr bios) - { - uint8_t status; -- uint8_t id1, id2; - - chip_writeb(0x70, bios); - if ((chip_readb(bios) & 0x80) == 0) { // it's busy -@@ -90,49 +101,47 @@ uint8_t wait_82802ab(chipaddr bios) - - status = chip_readb(bios); - -- // put another command to get out of status register mode -+ /* Reset to get a clean state */ -+ chip_writeb(0xFF, bios); - -- chip_writeb(0x90, bios); -- programmer_delay(10); -+ return status; -+} - -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -+int unlock_82802ab(struct flashchip *flash) -+{ -+ int i; -+ //chipaddr wrprotect = flash->virtual_registers + page + 2; - -- // this is needed to jam it out of "read id" mode -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); -+ for (i = 0; i < flash->total_size * 1024; i+= flash->page_size) -+ { -+ chip_writeb(0, flash->virtual_registers + i + 2); -+ } - -- return status; -+ return 0; - } - --int erase_82802ab_block(struct flashchip *flash, int offset) -+int erase_block_82802ab(struct flashchip *flash, unsigned int page, unsigned int pagesize) - { -- chipaddr bios = flash->virtual_memory + offset; -- chipaddr wrprotect = flash->virtual_registers + offset + 2; -+ chipaddr bios = flash->virtual_memory; - uint8_t status; - - // clear status register -- chip_writeb(0x50, bios); -- //printf("Erase at %p\n", bios); -- // clear write protect -- //printf("write protect is at %p\n", (wrprotect)); -- //printf("write protect is 0x%x\n", *(wrprotect)); -- chip_writeb(0, wrprotect); -- //printf("write protect is 0x%x\n", *(wrprotect)); -+ chip_writeb(0x50, bios + page); - - // now start it -- chip_writeb(0x20, bios); -- chip_writeb(0xd0, bios); -+ chip_writeb(0x20, bios + page); -+ chip_writeb(0xd0, bios + page); - programmer_delay(10); -+ - // now let's see what the register is -- status = wait_82802ab(flash->virtual_memory); -- //print_82802ab_status(status); -- if (check_erased_range(flash, offset, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ status = wait_82802ab(bios); -+ print_status_82802ab(status); -+ -+ if (check_erased_range(flash, page, pagesize)) { -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } -- printf("DONE BLOCK 0x%x\n", offset); -+ msg_cinfo("DONE BLOCK 0x%x\n", page); - - return 0; - } -@@ -142,14 +151,14 @@ int erase_82802ab(struct flashchip *flash) - int i; - unsigned int total_size = flash->total_size * 1024; - -- printf("total_size is %d; flash->page_size is %d\n", -+ msg_cspew("total_size is %d; flash->page_size is %d\n", - total_size, flash->page_size); - for (i = 0; i < total_size; i += flash->page_size) -- if (erase_82802ab_block(flash, i)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ if (erase_block_82802ab(flash, i, flash->page_size)) { -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } -- printf("DONE ERASE\n"); -+ msg_cinfo("DONE ERASE\n"); - - return 0; - } -@@ -170,45 +179,76 @@ void write_page_82802ab(chipaddr bios, uint8_t *src, - int write_82802ab(struct flashchip *flash, uint8_t *buf) - { - int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; -- uint8_t *tmpbuf = malloc(page_size); - -- if (!tmpbuf) { -- printf("Could not allocate memory!\n"); -- exit(1); -+ if (erase_flash(flash)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; - } -- printf("Programming page: \n"); -- for (i = 0; i < total_size / page_size; i++) { -- printf -- ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- printf("%04d at address: 0x%08x", i, i * page_size); -- -- /* Auto Skip Blocks, which already contain the desired data -- * Faster, because we only write, what has changed -- * More secure, because blocks, which are excluded -- * (with the exclude or layout feature) -- * or not erased and rewritten; their data is retained also in -- * sudden power off situations -- */ -- chip_readn(tmpbuf, bios + i * page_size, page_size); -- if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { -- printf("SKIPPED\n"); -- continue; -- } - -- /* erase block by block and write block by block; this is the most secure way */ -- if (erase_82802ab_block(flash, i * page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -+ msg_cinfo("Programming at: "); -+ for (i = 0; i < flash->total_size; i++) { -+ if ((i & 0x3) == 0) -+ msg_cinfo("address: 0x%08lx", (unsigned long)i * 1024); -+ -+ write_page_82802ab(bios, buf + i * 1024, bios + i * 1024, 1024); -+ -+ if ((i & 0x3) == 0) -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ } -+ -+ msg_cinfo("DONE!\n"); -+ return 0; -+} -+ -+int unlock_28f004s5(struct flashchip *flash) -+{ -+ chipaddr bios = flash->virtual_memory; -+ uint8_t mcfg, bcfg, need_unlock = 0, can_unlock = 0; -+ int i; -+ -+ /* Clear status register */ -+ chip_writeb(0x50, bios); -+ -+ /* Read identifier codes */ -+ chip_writeb(0x90, bios); -+ -+ /* Read master lock-bit */ -+ mcfg = chip_readb(bios + 0x3); -+ msg_cdbg("master lock is "); -+ if (mcfg) { -+ msg_cdbg("locked!\n"); -+ } else { -+ msg_cdbg("unlocked!\n"); -+ can_unlock = 1; -+ } -+ -+ /* Read block lock-bits */ -+ for (i = 0; i < flash->total_size * 1024; i+= (64 * 1024)) { -+ bcfg = chip_readb(bios + i + 2); // read block lock config -+ msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un"); -+ if (bcfg) { -+ need_unlock = 1; - } -- write_page_82802ab(bios, buf + i * page_size, -- bios + i * page_size, page_size); - } -- printf("\n"); -- protect_jedec(bios); -- free(tmpbuf); -+ -+ /* Reset chip */ -+ chip_writeb(0xFF, bios); -+ -+ /* Unlock: clear block lock-bits, if needed */ -+ if (can_unlock && need_unlock) { -+ msg_cdbg("Unlock: "); -+ chip_writeb(0x60, bios); -+ chip_writeb(0xD0, bios); -+ chip_writeb(0xFF, bios); -+ msg_cdbg("Done!\n"); -+ } -+ -+ /* Error: master locked or a block is locked */ -+ if (!can_unlock && need_unlock) { -+ msg_cerr("At least one block is locked and lockdown is active!\n"); -+ return -1; -+ } - - return 0; - } -diff --git a/Makefile b/Makefile -index 881c8f2..31fc858 100644 ---- a/Makefile -+++ b/Makefile -@@ -2,6 +2,7 @@ - # This file is part of the flashrom project. - # - # Copyright (C) 2005 coresystems GmbH -+# Copyright (C) 2009,2010 Carl-Daniel Hailfinger - # - # 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 -@@ -20,37 +21,49 @@ - PROGRAM = flashrom - - CC ?= gcc --STRIP = strip -+STRIP ?= strip - INSTALL = install - DIFF = diff - PREFIX ?= /usr/local - MANDIR ?= $(PREFIX)/share/man --CFLAGS ?= -Os -Wall -Werror -+CFLAGS ?= -Os -Wall -Wshadow - EXPORTDIR ?= . - --OS_ARCH = $(shell uname) -+WARNERROR ?= yes -+ -+ifeq ($(WARNERROR), yes) -+CFLAGS += -Werror -+endif -+ -+# FIXME We have to differentiate between host and target arch. -+OS_ARCH ?= $(shell uname) - ifneq ($(OS_ARCH), SunOS) - STRIP_ARGS = -s - endif - ifeq ($(OS_ARCH), Darwin) --CFLAGS += -I/usr/local/include --LDFLAGS += -framework IOKit -framework DirectIO -L/usr/local/lib -+CPPFLAGS += -I/opt/local/include -I/usr/local/include -+LDFLAGS += -framework IOKit -framework DirectIO -L/opt/local/lib -L/usr/local/lib - endif - ifeq ($(OS_ARCH), FreeBSD) --CFLAGS += -I/usr/local/include -+CPPFLAGS += -I/usr/local/include - LDFLAGS += -L/usr/local/lib - endif -+ifeq ($(OS_ARCH), DOS) -+CPPFLAGS += -I../libgetopt -I../libpci/include -+# Bus Pirate and Serprog are not supported under DOS. -+CONFIG_BUSPIRATESPI = no -+CONFIG_SERPROG = no -+endif -+ -+CHIP_OBJS = jedec.o stm50flw0x0x.o w39v040c.o w39v080fa.o w29ee011.o \ -+ sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \ -+ sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o - --LIBS += -lpci -lz -+LIB_OBJS = layout.o - --OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \ -- sst28sf040.o am29f040b.o mx29f002.o m29f400bt.o pm29f002.o \ -- w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \ -- sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \ -- flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ -- ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \ -- dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o \ -- print.o -+CLI_OBJS = flashrom.o cli_classic.o cli_output.o print.o -+ -+PROGRAMMER_OBJS = udelay.o programmer.o - - all: pciutils features dep $(PROGRAM) - -@@ -58,7 +71,7 @@ all: pciutils features dep $(PROGRAM) - # of the checked out flashrom files. - # Note to packagers: Any tree exported with "make export" or "make tarball" - # will not require subversion. The downloadable snapshots are already exported. --SVNVERSION := 710 -+SVNVERSION := 995 - - RELEASE := 0.9.1 - VERSION := $(RELEASE)-r$(SVNVERSION) -@@ -66,23 +79,162 @@ RELEASENAME ?= $(VERSION) - - SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"' - -+# Always enable internal/onboard support for now. -+CONFIG_INTERNAL ?= yes -+ - # Always enable serprog for now. Needs to be disabled on Windows. --CONFIG_SERPROG = yes -+CONFIG_SERPROG ?= yes -+ -+# Bitbanging SPI infrastructure is not used yet. -+CONFIG_BITBANG_SPI ?= no -+ -+# Always enable 3Com NICs for now. -+CONFIG_NIC3COM ?= yes -+ -+# Disable NVIDIA graphics cards for now, write/erase don't work properly. -+CONFIG_GFXNVIDIA ?= no -+ -+# Always enable SiI SATA controllers for now. -+CONFIG_SATASII ?= yes -+ -+# Highpoint (HPT) ATA/RAID controller support. -+# IMPORTANT: This code is not yet working! -+CONFIG_ATAHPT ?= no -+ -+# Always enable FT2232 SPI dongles for now. -+CONFIG_FT2232SPI ?= yes -+ -+# Always enable dummy tracing for now. -+CONFIG_DUMMY ?= yes -+ -+# Always enable Dr. Kaiser for now. -+CONFIG_DRKAISER ?= yes -+ -+# Always enable Bus Pirate SPI for now. -+CONFIG_BUSPIRATESPI ?= yes -+ -+# Disable Dediprog SF100 until support is complete and tested. -+CONFIG_DEDIPROG ?= no -+ -+# Disable wiki printing by default. It is only useful if you have wiki access. -+CONFIG_PRINT_WIKI ?= no -+ -+ifeq ($(CONFIG_INTERNAL), yes) -+FEATURE_CFLAGS += -D'INTERNAL_SUPPORT=1' -+PROGRAMMER_OBJS += chipset_enable.o board_enable.o cbtable.o dmi.o it87spi.o ichspi.o sb600spi.o wbsio_spi.o internal.o -+NEED_PCI := yes -+endif - - ifeq ($(CONFIG_SERPROG), yes) - FEATURE_CFLAGS += -D'SERPROG_SUPPORT=1' --OBJS += serprog.o -+PROGRAMMER_OBJS += serprog.o - ifeq ($(OS_ARCH), SunOS) - LIBS += -lsocket - endif - endif - -+ifeq ($(CONFIG_BITBANG_SPI), yes) -+FEATURE_CFLAGS += -D'BITBANG_SPI_SUPPORT=1' -+PROGRAMMER_OBJS += bitbang_spi.o -+endif -+ -+ifeq ($(CONFIG_NIC3COM), yes) -+FEATURE_CFLAGS += -D'NIC3COM_SUPPORT=1' -+PROGRAMMER_OBJS += nic3com.o -+NEED_PCI := yes -+endif -+ -+ifeq ($(CONFIG_GFXNVIDIA), yes) -+FEATURE_CFLAGS += -D'GFXNVIDIA_SUPPORT=1' -+PROGRAMMER_OBJS += gfxnvidia.o -+NEED_PCI := yes -+endif -+ -+ifeq ($(CONFIG_SATASII), yes) -+FEATURE_CFLAGS += -D'SATASII_SUPPORT=1' -+PROGRAMMER_OBJS += satasii.o -+NEED_PCI := yes -+endif -+ -+ifeq ($(CONFIG_ATAHPT), yes) -+FEATURE_CFLAGS += -D'ATAHPT_SUPPORT=1' -+PROGRAMMER_OBJS += atahpt.o -+NEED_PCI := yes -+endif -+ -+ifeq ($(CONFIG_FT2232SPI), yes) -+FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") -+# This is a totally ugly hack. - FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'FT2232_SPI_SUPPORT=1'") -+FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -+PROGRAMMER_OBJS += ft2232_spi.o -+endif - --FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-lftdi") -+ifeq ($(CONFIG_DUMMY), yes) -+FEATURE_CFLAGS += -D'DUMMY_SUPPORT=1' -+PROGRAMMER_OBJS += dummyflasher.o -+endif -+ -+ifeq ($(CONFIG_DRKAISER), yes) -+FEATURE_CFLAGS += -D'DRKAISER_SUPPORT=1' -+PROGRAMMER_OBJS += drkaiser.o -+NEED_PCI := yes -+endif -+ -+ifeq ($(CONFIG_BUSPIRATESPI), yes) -+FEATURE_CFLAGS += -D'BUSPIRATE_SPI_SUPPORT=1' -+PROGRAMMER_OBJS += buspirate_spi.o -+endif -+ -+ifeq ($(CONFIG_DEDIPROG), yes) -+FEATURE_CFLAGS += -D'DEDIPROG_SUPPORT=1' -+FEATURE_LIBS += -lusb -+PROGRAMMER_OBJS += dediprog.o -+endif -+ -+# Ugly, but there's no elif/elseif. -+ifeq ($(CONFIG_SERPROG), yes) -+LIB_OBJS += serial.o -+else -+ifeq ($(CONFIG_BUSPIRATESPI), yes) -+LIB_OBJS += serial.o -+endif -+endif -+ -+ifeq ($(NEED_PCI), yes) -+CHECK_LIBPCI = yes -+endif -+ -+ifeq ($(NEED_PCI), yes) -+FEATURE_CFLAGS += -D'NEED_PCI=1' -+PROGRAMMER_OBJS += pcidev.o physmap.o hwaccess.o -+ifeq ($(OS_ARCH), NetBSD) -+LIBS += -lpciutils # The libpci we want. -+LIBS += -l$(shell uname -p) # For (i386|x86_64)_iopl(2). -+else -+ifeq ($(OS_ARCH), DOS) -+# FIXME There needs to be a better way to do this -+LIBS += ../libpci/lib/libpci.a ../libgetopt/libgetopt.a -+else -+LIBS += -lpci -+endif -+endif -+endif -+ -+ifeq ($(CONFIG_PRINT_WIKI), yes) -+FEATURE_CFLAGS += -D'PRINT_WIKI_SUPPORT=1' -+CLI_OBJS += print_wiki.o -+endif -+ -+FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "UTSNAME := yes" .features && printf "%s" "-D'HAVE_UTSNAME=1'") -+ -+# We could use PULLED_IN_LIBS, but that would be ugly. -+FEATURE_LIBS += $(shell LC_ALL=C grep -q "NEEDLIBZ := yes" .libdeps && printf "%s" "-lz") -+ -+OBJS = $(CHIP_OBJS) $(CLI_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS) - - $(PROGRAM): $(OBJS) -- $(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(LIBS) $(FEATURE_LIBS) -+ $(CC) $(LDFLAGS) -o $(PROGRAM) $(OBJS) $(FEATURE_LIBS) $(LIBS) - - # TAROPTIONS reduces information leakage from the packager's system. - # If other tar programs support command line arguments for setting uid/gid of -@@ -96,7 +248,7 @@ clean: - rm -f $(PROGRAM) *.o - - distclean: clean -- rm -f .dependencies .features -+ rm -f .dependencies .features .libdeps - - dep: - @$(CC) $(CPPFLAGS) $(SVNDEF) -MM *.c > .dependencies -@@ -108,26 +260,42 @@ compiler: - @printf "Checking for a C compiler... " - @$(shell ( echo "int main(int argc, char **argv)"; \ - echo "{ return 0; }"; ) > .test.c ) -- @$(CC) $(CFLAGS) $(LDFLAGS) .test.c -o .test >/dev/null && \ -+ @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .test.c -o .test >/dev/null && \ - echo "found." || ( echo "not found."; \ - rm -f .test.c .test; exit 1) - @rm -f .test.c .test - -+ifeq ($(CHECK_LIBPCI), yes) - pciutils: compiler -- @printf "Checking for pciutils and zlib... " -+ @printf "Checking for libpci headers... " - @$(shell ( echo "#include "; \ - echo "struct pci_access *pacc;"; \ - echo "int main(int argc, char **argv)"; \ - echo "{ pacc = pci_alloc(); return 0; }"; ) > .test.c ) -- @$(CC) $(CFLAGS) $(LDFLAGS) .test.c -o .test $(LIBS) >/dev/null 2>&1 && \ -- echo "found." || ( echo "not found."; echo; \ -- echo "Please install pciutils-devel and zlib-devel."; \ -- echo "See README for more information."; echo; \ -- rm -f .test.c .test; exit 1) -- @rm -f .test.c .test -+ @$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >/dev/null 2>&1 && \ -+ echo "found." || ( echo "not found."; echo; \ -+ echo "Please install libpci headers (package pciutils-devel)."; \ -+ echo "See README for more information."; echo; \ -+ rm -f .test.c .test.o; exit 1) -+ @printf "Checking if libpci is present and sufficient... " -+ @printf "" > .libdeps -+ @$(CC) $(LDFLAGS) .test.o -o .test $(LIBS) >/dev/null 2>&1 && \ -+ echo "yes." || ( echo "no."; \ -+ printf "Checking if libz+libpci are present and sufficient..."; \ -+ $(CC) $(LDFLAGS) .test.o -o .test $(LIBS) -lz >/dev/null 2>&1 && \ -+ ( echo "yes."; echo "NEEDLIBZ := yes" > .libdeps ) || ( echo "no."; echo; \ -+ echo "Please install libpci (package pciutils) and/or libz."; \ -+ echo "See README for more information."; echo; \ -+ rm -f .test.c .test.o .test; exit 1) ) -+ @rm -f .test.c .test.o .test -+else -+pciutils: compiler -+ @printf "" > .libdeps -+endif - - .features: features - -+ifeq ($(CONFIG_FT2232SPI), yes) - features: compiler - @echo "FEATURES := yes" > .features.tmp - @printf "Checking for FTDI support... " -@@ -135,11 +303,33 @@ features: compiler - echo "struct ftdi_context *ftdic = NULL;"; \ - echo "int main(int argc, char **argv)"; \ - echo "{ return ftdi_init(ftdic); }"; ) > .featuretest.c ) -- @$(CC) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest $(LIBS) -lftdi >/dev/null 2>&1 && \ -+ @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ - ( echo "found."; echo "FTDISUPPORT := yes" >> .features.tmp ) || \ - ( echo "not found."; echo "FTDISUPPORT := no" >> .features.tmp ) -+ @printf "Checking for utsname support... " -+ @$(shell ( echo "#include "; \ -+ echo "struct utsname osinfo;"; \ -+ echo "int main(int argc, char **argv)"; \ -+ echo "{ uname (&osinfo); return 0; }"; ) > .featuretest.c ) -+ @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest >/dev/null 2>&1 && \ -+ ( echo "found."; echo "UTSNAME := yes" >> .features.tmp ) || \ -+ ( echo "not found."; echo "UTSNAME := no" >> .features.tmp ) -+ @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features -+ @rm -f .featuretest.c .featuretest -+else -+features: compiler -+ @echo "FEATURES := yes" > .features.tmp -+ @printf "Checking for utsname support... " -+ @$(shell ( echo "#include "; \ -+ echo "struct utsname osinfo;"; \ -+ echo "int main(int argc, char **argv)"; \ -+ echo "{ uname (&osinfo); return 0; }"; ) > .featuretest.c ) -+ @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest >/dev/null 2>&1 && \ -+ ( echo "found."; echo "UTSNAME := yes" >> .features.tmp ) || \ -+ ( echo "not found."; echo "UTSNAME := no" >> .features.tmp ) - @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features - @rm -f .featuretest.c .featuretest -+endif - - install: $(PROGRAM) - mkdir -p $(DESTDIR)$(PREFIX)/sbin -@@ -159,6 +349,9 @@ tarball: export - @rm -rf $(EXPORTDIR)/flashrom-$(RELEASENAME) - @echo Created $(EXPORTDIR)/flashrom-$(RELEASENAME).tar.bz2 - --.PHONY: all clean distclean dep compiler pciutils features export tarball -+djgpp-dos: clean -+ make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip WARNERROR=no OS_ARCH=DOS -+ -+.PHONY: all clean distclean dep compiler pciutils features export tarball dos - - -include .dependencies -diff --git a/README b/README -index b6a0792..8ccfc2f 100644 ---- a/README -+++ b/README -@@ -11,6 +11,8 @@ program flash chips. - It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, and TSOP40 - chips, which use various protocols such as LPC, FWH, parallel flash, or SPI. - -+Please see the flashrom(8) manpage. -+ - - Packaging - --------- -@@ -38,9 +40,9 @@ To build flashrom you need to install the following packages or ports: - - Linux et al: - -- * pciutils -+ * pciutils / libpci - * pciutils-devel / pciutils-dev / libpci-dev -- * zlib-devel / zlib1g-dev (only needed if libpci is static) -+ * zlib-devel / zlib1g-dev (needed if libpci was compiled with libz support) - - On FreeBSD, you need the following ports: - -@@ -63,58 +65,49 @@ To compile on Solaris, use: - - gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2 - --To compile on DragonFly BSD, use: -+To compile on NetBSD or DragonFly BSD, use: - - ln -s /usr/pkg/include/pciutils pci -- gmake CFLAGS=-I. LDFLAGS="-L/usr/pkg/lib" -+ gmake CPPFLAGS=-I. LDFLAGS="-L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib" - - To compile and run on Darwin/Mac OS X: - - Install DirectIO from coresystems GmbH. - DirectIO is available at http://www.coresystems.de/en/directio. - -+To cross-compile on Linux for DOS: -+ -+ Get RPMs of the cross compiler from the DJGPP site and install them: -+ djcross-binutils-2.19.1-10ap.i386.rpm -+ djcross-gcc-tools-4.4.1-1ap.i686.rpm -+ djcross-gcc-4.3.2-8ap.i686.rpm -+ Download pciutils 3.1.5 and apply http://assembler.cz/flashrom/pciutils.patch -+ Download and compile http://assembler.cz/flashrom/libgetopt/ -+ Compile pciutils, see README.DJGPP for instructions. -+ Enter the flashrom directory. -+ ../libpci should contain pciutils source and binaries. -+ ../libgetopt should contain getopt.a from libgetopt. -+ Run either (change settings where appropriate) -+ make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip OS_ARCH=DOS -+ or (above settings hardcoded) -+ make djgpp-dos -+ You might have to add WARNERROR=no to the make command line. -+ To run flashrom.exe, download http://clio.rice.edu/djgpp/csdpmi7b.zip and -+ make sure CWSDPMI.EXE is in the current directory. - - Installation - ------------ - - In order to install flashrom and the manpage into /usr/local, type: - -- sudo make install -+ make install - - For installation in a different directory use DESTDIR, e.g. like this: - -- sudo make DESTDIR=/usr install -- -- --Usage / Options ----------------- -- --Please see the flashrom(8) manpage. -- -- --Exit status ------------- -- --Please see the flashrom(8) manpage. -- -- --coreboot Table and Mainboard Identification ---------------------------------------------- -- --Please see the flashrom(8) manpage. -- -- --ROM Layout Support -------------------- -- --Please see the flashrom(8) manpage. -- -- --Supported Flash Chips / Chipsets / Mainboards ----------------------------------------------- -+ make DESTDIR=/usr install - --Please check the output of 'flashrom -L' for the list of supported --flash chips, chipsets/southbridges, mainboards, and flash programmers. -+If you have insufficient permissions for the destination directory, use sudo -+by adding sudo in front of the commands above. - - - Contact -@@ -128,6 +121,6 @@ The IRC channel is - - #flashrom at irc.freenode.net - --The Mailing list addess is -+The mailing list address is - - flashrom@flashrom.org -diff --git a/am29f040b.c b/am29f040b.c -deleted file mode 100644 -index 7f1269c..0000000 ---- a/am29f040b.c -+++ /dev/null -@@ -1,140 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2000 Silicon Integrated System Corporation -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --static int erase_sector_29f040b(struct flashchip *flash, unsigned long address) --{ -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x80, bios + 0x555); -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x30, bios + address); -- -- programmer_delay(2 * 1000 * 1000); -- -- /* wait for Toggle bit ready */ -- toggle_ready_jedec(bios + address); -- -- if (check_erased_range(flash, address, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --static int write_sector_29f040b(chipaddr bios, uint8_t *src, chipaddr dst, -- unsigned int page_size) --{ -- int i; -- -- for (i = 0; i < page_size; i++) { -- if ((i & 0xfff) == 0xfff) -- printf("0x%08lx", dst - bios); -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0xA0, bios + 0x555); -- chip_writeb(*src++, dst++); -- -- /* wait for Toggle bit ready */ -- toggle_ready_jedec(bios); -- -- if ((i & 0xfff) == 0xfff) -- printf("\b\b\b\b\b\b\b\b\b\b"); -- } -- -- return 0; --} -- --int probe_29f040b(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x90, bios + 0x555); -- -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- chip_writeb(0xF0, bios); -- -- programmer_delay(10); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- if (id1 == flash->manufacture_id && id2 == flash->model_id) -- return 1; -- -- return 0; --} -- --int erase_29f040b(struct flashchip *flash) --{ -- int total_size = flash->total_size * 1024; -- chipaddr bios = flash->virtual_memory; -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x80, bios + 0x555); -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x10, bios + 0x555); -- -- programmer_delay(10); -- toggle_ready_jedec(bios); -- -- if (check_erased_range(flash, 0, total_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int write_29f040b(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- printf("Programming page "); -- for (i = 0; i < total_size / page_size; i++) { -- /* erase the page before programming */ -- if (erase_sector_29f040b(flash, i * page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- /* write to the sector */ -- printf("%04d at address: ", i); -- write_sector_29f040b(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/atahpt.c b/atahpt.c -new file mode 100644 -index 0000000..c87bc36 ---- /dev/null -+++ b/atahpt.c -@@ -0,0 +1,85 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2010 Uwe Hermann -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include "flash.h" -+ -+#define BIOS_ROM_ADDR 0x90 -+#define BIOS_ROM_DATA 0x94 -+ -+#define REG_FLASH_ACCESS 0x58 -+ -+#define PCI_VENDOR_ID_HPT 0x1103 -+ -+struct pcidev_status ata_hpt[] = { -+ {0x1103, 0x0004, NT, "Highpoint", "HPT366/368/370/370A/372/372N"}, -+ {0x1103, 0x0005, NT, "Highpoint", "HPT372A/372N"}, -+ {0x1103, 0x0006, NT, "Highpoint", "HPT302/302N"}, -+ -+ {}, -+}; -+ -+int atahpt_init(void) -+{ -+ uint32_t reg32; -+ -+ get_io_perms(); -+ -+ io_base_addr = pcidev_init(PCI_VENDOR_ID_HPT, PCI_BASE_ADDRESS_4, -+ ata_hpt, programmer_param); -+ -+ /* Enable flash access. */ -+ reg32 = pci_read_long(pcidev_dev, REG_FLASH_ACCESS); -+ reg32 |= (1 << 24); -+ pci_write_long(pcidev_dev, REG_FLASH_ACCESS, reg32); -+ -+ buses_supported = CHIP_BUSTYPE_PARALLEL; -+ -+ return 0; -+} -+ -+int atahpt_shutdown(void) -+{ -+ uint32_t reg32; -+ -+ /* Disable flash access again. */ -+ reg32 = pci_read_long(pcidev_dev, REG_FLASH_ACCESS); -+ reg32 &= ~(1 << 24); -+ pci_write_long(pcidev_dev, REG_FLASH_ACCESS, reg32); -+ -+ free(programmer_param); -+ pci_cleanup(pacc); -+ release_io_perms(); -+ return 0; -+} -+ -+void atahpt_chip_writeb(uint8_t val, chipaddr addr) -+{ -+ OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); -+ OUTB(val, io_base_addr + BIOS_ROM_DATA); -+} -+ -+uint8_t atahpt_chip_readb(const chipaddr addr) -+{ -+ OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR); -+ return INB(io_base_addr + BIOS_ROM_DATA); -+} -diff --git a/bitbang_spi.c b/bitbang_spi.c -new file mode 100644 -index 0000000..8d6a9a1 ---- /dev/null -+++ b/bitbang_spi.c -@@ -0,0 +1,165 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Carl-Daniel Hailfinger -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "flash.h" -+#include "chipdrivers.h" -+#include "spi.h" -+ -+/* Length of half a clock period in usecs */ -+int bitbang_spi_half_period = 0; -+ -+enum bitbang_spi_master bitbang_spi_master = BITBANG_SPI_INVALID; -+ -+const struct bitbang_spi_master_entry bitbang_spi_master_table[] = { -+ {}, /* This entry corresponds to BITBANG_SPI_INVALID. */ -+}; -+ -+const int bitbang_spi_master_count = ARRAY_SIZE(bitbang_spi_master_table); -+ -+void bitbang_spi_set_cs(int val) -+{ -+ bitbang_spi_master_table[bitbang_spi_master].set_cs(val); -+} -+ -+void bitbang_spi_set_sck(int val) -+{ -+ bitbang_spi_master_table[bitbang_spi_master].set_sck(val); -+} -+ -+void bitbang_spi_set_mosi(int val) -+{ -+ bitbang_spi_master_table[bitbang_spi_master].set_mosi(val); -+} -+ -+int bitbang_spi_get_miso(void) -+{ -+ return bitbang_spi_master_table[bitbang_spi_master].get_miso(); -+} -+ -+int bitbang_spi_init(void) -+{ -+ bitbang_spi_set_cs(1); -+ bitbang_spi_set_sck(0); -+ buses_supported = CHIP_BUSTYPE_SPI; -+ return 0; -+} -+ -+uint8_t bitbang_spi_readwrite_byte(uint8_t val) -+{ -+ uint8_t ret = 0; -+ int i; -+ -+ for (i = 7; i >= 0; i--) { -+ bitbang_spi_set_mosi((val >> i) & 1); -+ programmer_delay(bitbang_spi_half_period); -+ bitbang_spi_set_sck(1); -+ ret <<= 1; -+ ret |= bitbang_spi_get_miso(); -+ programmer_delay(bitbang_spi_half_period); -+ bitbang_spi_set_sck(0); -+ } -+ return ret; -+} -+ -+int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, -+ const unsigned char *writearr, unsigned char *readarr) -+{ -+ static unsigned char *bufout = NULL; -+ static unsigned char *bufin = NULL; -+ static int oldbufsize = 0; -+ int bufsize; -+ int i; -+ -+ /* Arbitrary size limitation here. We're only constrained by memory. */ -+ if (writecnt > 65536 || readcnt > 65536) -+ return SPI_INVALID_LENGTH; -+ -+ bufsize = max(writecnt + readcnt, 260); -+ /* Never shrink. realloc() calls are expensive. */ -+ if (bufsize > oldbufsize) { -+ bufout = realloc(bufout, bufsize); -+ if (!bufout) { -+ msg_perr("Out of memory!\n"); -+ if (bufin) -+ free(bufin); -+ exit(1); -+ } -+ bufin = realloc(bufout, bufsize); -+ if (!bufin) { -+ msg_perr("Out of memory!\n"); -+ if (bufout) -+ free(bufout); -+ exit(1); -+ } -+ oldbufsize = bufsize; -+ } -+ -+ memcpy(bufout, writearr, writecnt); -+ /* Shift out 0x00 while reading data. */ -+ memset(bufout + writecnt, 0x00, readcnt); -+ /* Make sure any non-read data is 0xff. */ -+ memset(bufin + writecnt, 0xff, readcnt); -+ -+ bitbang_spi_set_cs(0); -+ for (i = 0; i < readcnt + writecnt; i++) { -+ bufin[i] = bitbang_spi_readwrite_byte(bufout[i]); -+ } -+ programmer_delay(bitbang_spi_half_period); -+ bitbang_spi_set_cs(1); -+ programmer_delay(bitbang_spi_half_period); -+ memcpy(readarr, bufin + writecnt, readcnt); -+ -+ return 0; -+} -+ -+int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -+{ -+ /* Maximum read length is unlimited, use 64k bytes. */ -+ return spi_read_chunked(flash, buf, start, len, 64 * 1024); -+} -+ -+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf) -+{ -+ int total_size = 1024 * flash->total_size; -+ int i; -+ -+ msg_pdbg("total_size is %d\n", total_size); -+ for (i = 0; i < total_size; i += 256) { -+ int l, r; -+ if (i + 256 <= total_size) -+ l = 256; -+ else -+ l = total_size - i; -+ -+ if ((r = spi_nbyte_program(i, &buf[i], l))) { -+ msg_perr("%s: write fail %d\n", __func__, r); -+ return 1; -+ } -+ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ /* loop */; -+ } -+ -+ return 0; -+} -diff --git a/board_enable.c b/board_enable.c -index c87e782..f1f7953 100644 ---- a/board_enable.c -+++ b/board_enable.c -@@ -66,6 +66,35 @@ void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask) - OUTB(tmp | (data & mask), port + 1); - } - -+/* Not used yet. */ -+#if 0 -+static int enable_flash_decode_superio(void) -+{ -+ int ret; -+ uint8_t tmp; -+ -+ switch (superio.vendor) { -+ case SUPERIO_VENDOR_NONE: -+ ret = -1; -+ break; -+ case SUPERIO_VENDOR_ITE: -+ enter_conf_mode_ite(superio.port); -+ /* Enable flash mapping. Works for most old ITE style Super I/O. */ -+ tmp = sio_read(superio.port, 0x24); -+ tmp |= 0xfc; -+ sio_write(superio.port, 0x24, tmp); -+ exit_conf_mode_ite(superio.port); -+ ret = 0; -+ break; -+ default: -+ printf_debug("Unhandled Super I/O type!\n"); -+ ret = -1; -+ break; -+ } -+ return ret; -+} -+#endif -+ - /** - * Winbond W83627HF: Raise GPIO24. - * -@@ -162,25 +191,118 @@ static void w836xx_memw_enable(uint16_t port) - } - - /** -- * Common routine for several VT823x based boards. -+ * Suited for: -+ * - EPoX EP-8K5A2: VIA KT333 + VT8235. -+ * - Albatron PM266A Pro: VIA P4M266A + VT8235. -+ * - Shuttle AK31 (all versions): VIA KT266 + VT8233. -+ * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235 -+ * - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237. - */ --static void vt823x_set_all_writes_to_lpc(struct pci_dev *dev) -+static int w836xx_memw_enable_2e(const char *name) - { -- uint8_t val; -+ w836xx_memw_enable(0x2E); - -- /* All memory cycles, not just ROM ones, go to LPC. */ -- val = pci_read_byte(dev, 0x59); -- val &= ~0x80; -- pci_write_byte(dev, 0x59, val); -+ return 0; -+} -+ -+/** -+ * Suited for: -+ * - Termtek TK-3370 (rev. 2.5b) -+ */ -+static int w836xx_memw_enable_4e(const char *name) -+{ -+ w836xx_memw_enable(0x4E); -+ -+ return 0; -+} -+ -+/** -+ * -+ */ -+static int it8705f_write_enable(uint8_t port, const char *name) -+{ -+ enter_conf_mode_ite(port); -+ sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */ -+ exit_conf_mode_ite(port); -+ -+ return 0; -+} -+ -+/** -+ * Suited for: -+ * - AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F. -+ * - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF -+ * - Elitegroup K7S6A: SiS745 + ITE IT8705F -+ * - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F -+ * - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705 -+ * - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F -+ * -+ * The SIS950 Super I/O probably requires the same flash write enable. -+ */ -+static int it8705f_write_enable_2e(const char *name) -+{ -+ return it8705f_write_enable(0x2e, name); -+} -+ -+static int pc87360_gpio_set(uint8_t gpio, int raise) -+{ -+ static const int bankbase[] = {0, 4, 8, 10, 12}; -+ int gpio_bank = gpio / 8; -+ int gpio_pin = gpio % 8; -+ uint16_t baseport; -+ uint8_t id, val; -+ -+ if (gpio_bank > 4) { -+ fprintf(stderr, "PC87360: Invalid GPIO %d\n", gpio); -+ return -1; -+ } -+ -+ id = sio_read(0x2E, 0x20); -+ if (id != 0xE1) { -+ fprintf(stderr, "PC87360: unexpected ID %02x\n", id); -+ return -1; -+ } -+ -+ sio_write(0x2E, 0x07, 0x07); /* Select GPIO device */ -+ baseport = (sio_read(0x2E, 0x60) << 8) | sio_read(0x2E, 0x61); -+ if ((baseport & 0xFFF0) == 0xFFF0 || baseport == 0) { -+ fprintf (stderr, "PC87360: invalid GPIO base address %04x\n", -+ baseport); -+ return -1; -+ } -+ sio_mask (0x2E, 0x30, 0x01, 0x01); /* Enable logical device */ -+ sio_write(0x2E, 0xF0, gpio_bank * 16 + gpio_pin); -+ sio_mask (0x2E, 0xF1, 0x01, 0x01); /* Make pin output */ -+ -+ val = INB(baseport + bankbase[gpio_bank]); -+ if (raise) -+ val |= 1 << gpio_pin; -+ else -+ val &= ~(1 << gpio_pin); -+ OUTB(val, baseport + bankbase[gpio_bank]); -+ -+ return 0; - } - - /** - * VT823x: Set one of the GPIO pins. - */ --static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise) -+static int via_vt823x_gpio_set(uint8_t gpio, int raise) - { -+ struct pci_dev *dev; - uint16_t base; -- uint8_t val, bit; -+ uint8_t val, bit, offset; -+ -+ dev = pci_dev_find_vendorclass(0x1106, 0x0601); -+ switch (dev->device_id) { -+ case 0x3177: /* VT8235 */ -+ case 0x3227: /* VT8237R */ -+ case 0x3337: /* VT8237A */ -+ break; -+ default: -+ fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); -+ return -1; -+ } - - if ((gpio >= 12) && (gpio <= 15)) { - /* GPIO12-15 -> output */ -@@ -192,126 +314,75 @@ static void vt823x_gpio_set(struct pci_dev *dev, uint8_t gpio, int raise) - val = pci_read_byte(dev, 0xE4); - val |= 0x20; - pci_write_byte(dev, 0xE4, val); -+ } else if (gpio == 5) { -+ val = pci_read_byte(dev, 0xE4); -+ val |= 0x01; -+ pci_write_byte(dev, 0xE4, val); - } else { - fprintf(stderr, "\nERROR: " - "VT823x GPIO%02d is not implemented.\n", gpio); -- return; -+ return -1; - } - -- /* Now raise/drop the GPIO line itself. */ -- bit = 0x01 << (gpio - 8); -- - /* We need the I/O Base Address for this board's flash enable. */ - base = pci_read_word(dev, 0x88) & 0xff80; - -- val = INB(base + 0x4D); -+ offset = 0x4C + gpio / 8; -+ bit = 0x01 << (gpio % 8); -+ -+ val = INB(base + offset); - if (raise) - val |= bit; - else - val &= ~bit; -- OUTB(val, base + 0x4D); --} -- --/** -- * Suited for VIAs EPIA M and MII, and maybe other CLE266 based EPIAs. -- * -- * We don't need to do this when using coreboot, GPIO15 is never lowered there. -- */ --static int board_via_epia_m(const char *name) --{ -- struct pci_dev *dev; -- -- dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n"); -- return -1; -- } -- -- /* GPIO15 is connected to write protect. */ -- vt823x_gpio_set(dev, 15, 1); -+ OUTB(val, base + offset); - - return 0; - } - - /** -- * Suited for: -- * - ASUS A7V8X-MX SE and A7V400-MX: AMD K7 + VIA KM400A + VT8235 -- * - Tyan S2498 (Tomcat K7M): AMD Geode NX + VIA KM400 + VT8237. -+ * Suited for ASUS M2V-MX: VIA K8M890 + VT8237A + IT8716F - */ --static int board_asus_a7v8x_mx(const char *name) -+static int via_vt823x_gpio5_raise(const char *name) - { -- struct pci_dev *dev; -- -- dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ -- if (!dev) -- dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); -- return -1; -- } -- -- vt823x_set_all_writes_to_lpc(dev); -- w836xx_memw_enable(0x2E); -- -- return 0; -+ /* On M2V-MX: GPO5 is connected to WP# and TBL#. */ -+ return via_vt823x_gpio_set(5, 1); - } - - /** -- * Suited for VIAs EPIA SP and EPIA CN. -+ * Suited for VIA EPIA N & NL. - */ --static int board_via_epia_sp(const char *name) -+static int via_vt823x_gpio9_raise(const char *name) - { -- struct pci_dev *dev; -- -- dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); -- return -1; -- } -- -- vt823x_set_all_writes_to_lpc(dev); -- -- return 0; -+ return via_vt823x_gpio_set(9, 1); - } - - /** -- * Suited for VIAs EPIA N & NL. -+ * Suited for VIA EPIA M and MII, and maybe other CLE266 based EPIAs. -+ * -+ * We don't need to do this for EPIA M when using coreboot, GPIO15 is never -+ * lowered there. - */ --static int board_via_epia_n(const char *name) -+static int via_vt823x_gpio15_raise(const char *name) - { -- struct pci_dev *dev; -- -- dev = pci_dev_find(0x1106, 0x3227); /* VT8237R ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT8237R ISA bridge not found.\n"); -- return -1; -- } -- -- /* All memory cycles, not just ROM ones, go to LPC */ -- vt823x_set_all_writes_to_lpc(dev); -- -- /* GPIO9 -> output */ -- vt823x_gpio_set(dev, 9, 1); -- -- return 0; -+ return via_vt823x_gpio_set(15, 1); - } - - /** -- * Suited for EPoX EP-8K5A2 and Albatron PM266A Pro. -+ * Winbond W83697HF Super I/O + VIA VT8235 southbridge -+ * -+ * Suited for: -+ * - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235 -+ * - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235 - */ --static int board_epox_ep_8k5a2(const char *name) -+static int board_msi_kt4v(const char *name) - { -- struct pci_dev *dev; -- -- dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT8235 ISA bridge not found.\n"); -- return -1; -- } -+ int ret; - -+ ret = via_vt823x_gpio_set(12, 1); - w836xx_memw_enable(0x2E); - -- return 0; -+ return ret; - } - - /** -@@ -390,94 +461,152 @@ static int board_asus_p5a(const char *name) - return 0; - } - -+/* -+ * Set GPIO lines in the Broadcom HT-1000 southbridge. -+ * -+ * It's not a Super I/O but it uses the same index/data port method. -+ */ -+static int board_hp_dl145_g3_enable(const char *name) -+{ -+ /* GPIO 0 reg from PM regs */ -+ /* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */ -+ sio_mask(0xcd6, 0x44, 0x24, 0x24); -+ -+ return 0; -+} -+ - static int board_ibm_x3455(const char *name) - { -- /* Set GPIO lines in the Broadcom HT-1000 southbridge. */ -- /* It's not a Super I/O but it uses the same index/data port method. */ -+ /* raise gpio13 */ - sio_mask(0xcd6, 0x45, 0x20, 0x20); - - return 0; - } - - /** -- * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge. -+ * Suited for Shuttle FN25 (SN25P): AMD S939 + NVIDIA CK804 (nForce4). - */ --static int board_ga_k8n_sli(const char *name) -+static int board_shuttle_fn25(const char *name) - { - struct pci_dev *dev; -- uint32_t base; -- uint8_t tmp; - -- dev = pci_dev_find(0x10DE, 0x0050); /* NVIDIA CK804 LPC */ -+ dev = pci_dev_find(0x10DE, 0x0050); /* NVIDIA CK804 ISA Bridge. */ - if (!dev) { -- fprintf(stderr, "\nERROR: NVIDIA LPC bridge not found.\n"); -+ fprintf(stderr, -+ "\nERROR: NVIDIA nForce4 ISA bridge not found.\n"); - return -1; - } - -- base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */ -- -- /* if anyone knows more about nvidia lpcs, feel free to explain this */ -- tmp = INB(base + 0xE1); -- tmp |= 0x05; -- OUTB(tmp, base + 0xE1); -- -- return 0; --} -- --static int board_hp_dl145_g3_enable(const char *name) --{ -- /* Set GPIO lines in the Broadcom HT-1000 southbridge. */ -- /* GPIO 0 reg from PM regs */ -- /* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */ -- /* It's not a Super I/O but it uses the same index/data port method. */ -- sio_mask(0xcd6, 0x44, 0x24, 0x24); -+ /* one of those bits seems to be connected to TBL#, but -ENOINFO. */ -+ pci_write_byte(dev, 0x92, 0); - - return 0; - } - - /** -- * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards. -+ * Very similar to AMD 8111 IO Hub. - */ --static int board_epox_ep_bx3(const char *name) -+static int nvidia_mcp_gpio_set(int gpio, int raise) - { -+ struct pci_dev *dev; -+ uint16_t base; - uint8_t tmp; - -- /* Raise GPIO22. */ -- tmp = INB(0x4036); -- OUTB(tmp, 0xEB); -+ if ((gpio < 0) || (gpio >= 0x40)) { -+ fprintf(stderr, "\nERROR: unsupported GPIO: %d.\n", gpio); -+ return -1; -+ } -+ -+ /* First, check the ISA Bridge */ -+ dev = pci_dev_find_vendorclass(0x10DE, 0x0601); -+ switch (dev->device_id) { -+ case 0x0030: /* CK804 */ -+ case 0x0050: /* MCP04 */ -+ case 0x0060: /* MCP2 */ -+ break; -+ default: -+ /* Newer MCPs use the SMBus Controller */ -+ dev = pci_dev_find_vendorclass(0x10DE, 0x0C05); -+ switch (dev->device_id) { -+ case 0x0264: /* MCP51 */ -+ break; -+ default: -+ fprintf(stderr, -+ "\nERROR: no NVIDIA LPC/SMBus controller found.\n"); -+ return -1; -+ } -+ break; -+ } - -- tmp |= 0x40; -+ base = pci_read_long(dev, 0x64) & 0x0000FF00; /* System control area */ -+ base += 0xC0; - -- OUTB(tmp, 0x4036); -- OUTB(tmp, 0xEB); -+ tmp = INB(base + gpio); -+ tmp &= ~0x0F; /* null lower nibble */ -+ tmp |= 0x04; /* gpio -> output. */ -+ if (raise) -+ tmp |= 0x01; -+ OUTB(tmp, base + gpio); - - return 0; - } - - /** -- * Suited for Acorp 6A815EPD. -+ * Suited for ASUS A8N-LA: nVidia MCP51. -+ * Suited for ASUS M2NBP-VM CSM: NVIDIA MCP51. - */ --static int board_acorp_6a815epd(const char *name) -+static int nvidia_mcp_gpio0_raise(const char *name) - { -- struct pci_dev *dev; -- uint16_t port; -- uint8_t val; -+ return nvidia_mcp_gpio_set(0x00, 1); -+} - -- dev = pci_dev_find(0x8086, 0x2440); /* Intel ICH2 LPC */ -- if (!dev) { -- fprintf(stderr, "\nERROR: ICH2 LPC bridge not found.\n"); -- return -1; -- } -+/** -+ * Suited for Abit KN8 Ultra: nVidia CK804. -+ */ -+static int nvidia_mcp_gpio2_lower(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x02, 0); -+} - -- /* Use GPIOBASE register to find where the GPIO is mapped. */ -- port = (pci_read_word(dev, 0x58) & 0xFFC0) + 0xE; -+/** -+ * Suited for MSI K8N Neo4: NVIDIA CK804. -+ * Suited for MSI K8N GM2-L: NVIDIA MCP51. -+ */ -+static int nvidia_mcp_gpio2_raise(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x02, 1); -+} - -- val = INB(port); -- val |= 0x80; /* Top Block Lock -- pin 8 of PLCC32 */ -- val |= 0x40; /* Lower Blocks Lock -- pin 7 of PLCC32 */ -- OUTB(val, port); -+/** -+ * Suited for Abit NF7-S: NVIDIA CK804. -+ */ -+static int nvidia_mcp_gpio8_raise(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x08, 1); -+} - -- return 0; -+/** -+ * Suited for ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04. -+ */ -+static int nvidia_mcp_gpio10_raise(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x10, 1); -+} -+ -+/** -+ * Suited for the Gigabyte GA-K8N-SLI: CK804 southbridge. -+ */ -+static int nvidia_mcp_gpio21_raise(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x21, 0x01); -+} -+ -+/** -+ * Suited for EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2. -+ */ -+static int nvidia_mcp_gpio31_raise(const char *name) -+{ -+ return nvidia_mcp_gpio_set(0x31, 0x01); - } - - /** -@@ -522,175 +651,402 @@ static int board_artecgroup_dbe6x(const char *name) - } - - /** -- * Set the specified GPIO on the specified ICHx southbridge to high. -- * -- * @param name The name of this board. -- * @param ich_vendor PCI vendor ID of the specified ICHx southbridge. -- * @param ich_device PCI device ID of the specified ICHx southbridge. -- * @param gpiobase_reg GPIOBASE register offset in the LPC bridge. -- * @param gp_lvl Offset of GP_LVL register in I/O space, relative to GPIOBASE. -- * @param gp_lvl_bitmask GP_LVL bitmask (set GPIO bits to 1, all others to 0). -- * @param gpio_bit The bit (GPIO) which shall be set to high. -- * @return If the write-enable was successful return 0, otherwise return -1. -+ * Helper function to raise/drop a given gpo line on Intel PIIX4{,E,M}. - */ --static int ich_gpio_raise(const char *name, uint16_t ich_vendor, -- uint16_t ich_device, uint8_t gpiobase_reg, -- uint8_t gp_lvl, uint32_t gp_lvl_bitmask, -- unsigned int gpio_bit) -+static int intel_piix4_gpo_set(unsigned int gpo, int raise) - { -+ unsigned int gpo_byte, gpo_bit; - struct pci_dev *dev; -- uint16_t gpiobar; -- uint32_t reg32; -+ uint32_t tmp, base; - -- dev = pci_dev_find(ich_vendor, ich_device); /* Intel ICHx LPC */ -+ dev = pci_dev_find(0x8086, 0x7110); /* Intel PIIX4 ISA bridge */ - if (!dev) { -- fprintf(stderr, "\nERROR: ICHx LPC dev %4x:%4x not found.\n", -- ich_vendor, ich_device); -+ fprintf(stderr, "\nERROR: Intel PIIX4 ISA bridge not found.\n"); -+ return -1; -+ } -+ -+ /* sanity check */ -+ if (gpo > 30) { -+ fprintf(stderr, "\nERROR: Intel PIIX4 has no GPO%d.\n", gpo); - return -1; - } - -- /* Use GPIOBASE register to find the I/O space for GPIO. */ -- gpiobar = pci_read_word(dev, gpiobase_reg) & gp_lvl_bitmask; -+ /* these are dual function pins which are most likely in use already */ -+ if (((gpo >= 1) && (gpo <= 7)) || -+ ((gpo >= 9) && (gpo <= 21)) || (gpo == 29)) { -+ fprintf(stderr, "\nERROR: Unsupported PIIX4 GPO%d.\n", gpo); -+ return -1; -+ } - -- /* Set specified GPIO to high. */ -- reg32 = INL(gpiobar + gp_lvl); -- reg32 |= (1 << gpio_bit); -- OUTL(reg32, gpiobar + gp_lvl); -+ /* dual function that need special enable. */ -+ if ((gpo >= 22) && (gpo <= 26)) { -+ tmp = pci_read_long(dev, 0xB0); /* GENCFG */ -+ switch (gpo) { -+ case 22: /* XBUS: XDIR#/GPO22 */ -+ case 23: /* XBUS: XOE#/GPO23 */ -+ tmp |= 1 << 28; -+ break; -+ case 24: /* RTCSS#/GPO24 */ -+ tmp |= 1 << 29; -+ break; -+ case 25: /* RTCALE/GPO25 */ -+ tmp |= 1 << 30; -+ break; -+ case 26: /* KBCSS#/GPO26 */ -+ tmp |= 1 << 31; -+ break; -+ } -+ pci_write_long(dev, 0xB0, tmp); -+ } -+ -+ /* GPO {0,8,27,28,30} are always available. */ -+ -+ dev = pci_dev_find(0x8086, 0x7113); /* Intel PIIX4 PM */ -+ if (!dev) { -+ fprintf(stderr, "\nERROR: Intel PIIX4 PM not found.\n"); -+ return -1; -+ } -+ -+ /* PM IO base */ -+ base = pci_read_long(dev, 0x40) & 0x0000FFC0; -+ -+ gpo_byte = gpo >> 3; -+ gpo_bit = gpo & 7; -+ tmp = INB(base + 0x34 + gpo_byte); /* GPO register */ -+ if (raise) -+ tmp |= 0x01 << gpo_bit; -+ else -+ tmp &= ~(0x01 << gpo_bit); -+ OUTB(tmp, base + 0x34 + gpo_byte); - - return 0; - } - - /** -- * Suited for ASUS P4B266. -+ * Suited for EPoX EP-BX3, and maybe some other Intel 440BX based boards. - */ --static int ich2_gpio22_raise(const char *name) -+static int board_epox_ep_bx3(const char *name) - { -- return ich_gpio_raise(name, 0x8086, 0x2440, 0x58, 0x0c, 0xffc0, 22); -+ return intel_piix4_gpo_set(22, 1); - } - - /** -- * Suited for MSI MS-7046. -+ * Suited for Intel SE440BX-2 - */ --static int ich6_gpio19_raise(const char *name) -+static int intel_piix4_gpo27_lower(const char *name) - { -- return ich_gpio_raise(name, 0x8086, 0x2640, 0x48, 0x0c, 0xffc0, 19); -+ return intel_piix4_gpo_set(27, 0); - } - --static int board_kontron_986lcd_m(const char *name) -+/** -+ * Set a GPIO line on a given Intel ICH LPC controller. -+ */ -+static int intel_ich_gpio_set(int gpio, int raise) - { -- struct pci_dev *dev; -- uint16_t gpiobar; -- uint32_t val; -+ /* Table mapping the different Intel ICH LPC chipsets. */ -+ static struct { -+ uint16_t id; -+ uint8_t base_reg; -+ uint32_t bank0; -+ uint32_t bank1; -+ uint32_t bank2; -+ } intel_ich_gpio_table[] = { -+ {0x2410, 0x58, 0x0FE30000, 0, 0}, /* 82801AA (ICH) */ -+ {0x2420, 0x58, 0x0FE30000, 0, 0}, /* 82801AB (ICH0) */ -+ {0x2440, 0x58, 0x1BFF391B, 0, 0}, /* 82801BA (ICH2) */ -+ {0x244C, 0x58, 0x1A23399B, 0, 0}, /* 82801BAM (ICH2M) */ -+ {0x2450, 0x58, 0x1BFF0000, 0, 0}, /* 82801E (C-ICH) */ -+ {0x2480, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801CA (ICH3-S) */ -+ {0x248C, 0x58, 0x1A230000, 0x00000FFF, 0}, /* 82801CAM (ICH3-M) */ -+ {0x24C0, 0x58, 0x1BFF0000, 0x00000FFF, 0}, /* 82801DB/DBL (ICH4/ICH4-L) */ -+ {0x24CC, 0x58, 0x1A030000, 0x00000FFF, 0}, /* 82801DBM (ICH4-M) */ -+ {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */ -+ {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */ -+ {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */ -+ {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */ -+ {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */ -+ {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */ -+ {0x2810, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HB/HR (ICH8/R) */ -+ {0x2811, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HBM (ICH8M-E) */ -+ {0x2812, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HH (ICH8DH) */ -+ {0x2814, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HO (ICH8DO) */ -+ {0x2815, 0x48, 0xFFFFFFFF, 0x00FF0FFF, 0}, /* 82801HEM (ICH8M) */ -+ {0x2912, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IH (ICH9DH) */ -+ {0x2914, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IO (ICH9DO) */ -+ {0x2916, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IR (ICH9R) */ -+ {0x2917, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IEM (ICH9M-E) */ -+ {0x2918, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IB (ICH9) */ -+ {0x2919, 0x48, 0xFFFFFFFF, 0x00FFFFFF, 0}, /* 82801IBM (ICH9M) */ -+ {0x3A14, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JDO (ICH10DO) */ -+ {0x3A16, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIR (ICH10R) */ -+ {0x3A18, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JIB (ICH10) */ -+ {0x3A1A, 0x48, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000100}, /* 82801JD (ICH10D) */ -+ {0, 0, 0, 0, 0} /* end marker */ -+ }; - --#define ICH7_GPIO_LVL2 0x38 -+ struct pci_dev *dev; -+ uint16_t base; -+ uint32_t tmp; -+ int i, allowed; -+ -+ /* First, look for a known LPC bridge */ -+ for (dev = pacc->devices; dev; dev = dev->next) { -+ pci_fill_info(dev, PCI_FILL_CLASS); -+ if ((dev->vendor_id == 0x8086) && -+ (dev->device_class == 0x0601)) { /* ISA Bridge */ -+ /* Is this device in our list? */ -+ for (i = 0; intel_ich_gpio_table[i].id; i++) -+ if (dev->device_id == intel_ich_gpio_table[i].id) -+ break; -+ -+ if (intel_ich_gpio_table[i].id) -+ break; -+ } -+ } - -- dev = pci_dev_find(0x8086, 0x27b8); /* Intel ICH7 LPC */ - if (!dev) { -- // This will never happen on this board -- fprintf(stderr, "\nERROR: ICH7 LPC bridge not found.\n"); -+ fprintf(stderr, "\nERROR: No Known Intel LPC Bridge found.\n"); -+ return -1; -+ } -+ -+ /* According to the datasheets, all Intel ICHs have the GPIO bar 5:1 -+ strapped to zero. From some mobile ICH9 version on, this becomes -+ 6:1. The mask below catches all. */ -+ base = pci_read_word(dev, intel_ich_gpio_table[i].base_reg) & 0xFFC0; -+ -+ /* check whether the line is allowed */ -+ if (gpio < 32) -+ allowed = (intel_ich_gpio_table[i].bank0 >> gpio) & 0x01; -+ else if (gpio < 64) -+ allowed = (intel_ich_gpio_table[i].bank1 >> (gpio - 32)) & 0x01; -+ else -+ allowed = (intel_ich_gpio_table[i].bank2 >> (gpio - 64)) & 0x01; -+ -+ if (!allowed) { -+ fprintf(stderr, "\nERROR: This Intel LPC Bridge does not allow" -+ " setting GPIO%02d\n", gpio); - return -1; - } - -- /* Use GPIOBASE register to find where the GPIO is mapped. */ -- gpiobar = pci_read_word(dev, 0x48) & 0xfffc; -+ printf("\nIntel ICH LPC Bridge: %sing GPIO%02d.\n", -+ raise ? "Rais" : "Dropp", gpio); -+ -+ if (gpio < 32) { -+ /* Set line to GPIO */ -+ tmp = INL(base); -+ /* ICH/ICH0 multiplexes 27/28 on the line set. */ -+ if ((gpio == 28) && -+ ((dev->device_id == 0x2410) || (dev->device_id == 0x2420))) -+ tmp |= 1 << 27; -+ else -+ tmp |= 1 << gpio; -+ OUTL(tmp, base); -+ -+ /* As soon as we are talking to ICH8 and above, this register -+ decides whether we can set the gpio or not. */ -+ if (dev->device_id > 0x2800) { -+ tmp = INL(base); -+ if (!(tmp & (1 << gpio))) { -+ fprintf(stderr, "\nERROR: This Intel LPC Bridge" -+ " does not allow setting GPIO%02d\n", -+ gpio); -+ return -1; -+ } -+ } -+ -+ /* Set GPIO to OUTPUT */ -+ tmp = INL(base + 0x04); -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x04); -+ -+ /* Raise GPIO line */ -+ tmp = INL(base + 0x0C); -+ if (raise) -+ tmp |= 1 << gpio; -+ else -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x0C); -+ } else if (gpio < 64) { -+ gpio -= 32; -+ -+ /* Set line to GPIO */ -+ tmp = INL(base + 0x30); -+ tmp |= 1 << gpio; -+ OUTL(tmp, base + 0x30); -+ -+ /* As soon as we are talking to ICH8 and above, this register -+ decides whether we can set the gpio or not. */ -+ if (dev->device_id > 0x2800) { -+ tmp = INL(base + 30); -+ if (!(tmp & (1 << gpio))) { -+ fprintf(stderr, "\nERROR: This Intel LPC Bridge" -+ " does not allow setting GPIO%02d\n", -+ gpio + 32); -+ return -1; -+ } -+ } -+ -+ /* Set GPIO to OUTPUT */ -+ tmp = INL(base + 0x34); -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x34); - -- val = INL(gpiobar + ICH7_GPIO_LVL2); /* GP_LVL2 */ -- printf_debug("\nGPIOBAR=0x%04x GP_LVL: 0x%08x\n", gpiobar, val); -+ /* Raise GPIO line */ -+ tmp = INL(base + 0x38); -+ if (raise) -+ tmp |= 1 << gpio; -+ else -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x38); -+ } else { -+ gpio -= 64; -+ -+ /* Set line to GPIO */ -+ tmp = INL(base + 0x40); -+ tmp |= 1 << gpio; -+ OUTL(tmp, base + 0x40); -+ -+ tmp = INL(base + 40); -+ if (!(tmp & (1 << gpio))) { -+ fprintf(stderr, "\nERROR: This Intel LPC Bridge does " -+ "not allow setting GPIO%02d\n", gpio + 64); -+ return -1; -+ } - -- /* bit 2 (0x04) = 0 #TBL --> bootblock locking = 1 -- * bit 2 (0x04) = 1 #TBL --> bootblock locking = 0 -- * bit 3 (0x08) = 0 #WP --> block locking = 1 -- * bit 3 (0x08) = 1 #WP --> block locking = 0 -- * -- * To enable full block locking, you would do: -- * val &= ~ ((1 << 2) | (1 << 3)); -- */ -- val |= (1 << 2) | (1 << 3); -+ /* Set GPIO to OUTPUT */ -+ tmp = INL(base + 0x44); -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x44); - -- OUTL(val, gpiobar + ICH7_GPIO_LVL2); -+ /* Raise GPIO line */ -+ tmp = INL(base + 0x48); -+ if (raise) -+ tmp |= 1 << gpio; -+ else -+ tmp &= ~(1 << gpio); -+ OUTL(tmp, base + 0x48); -+ } - - return 0; - } - - /** -- * Suited for: -- * - Biostar P4M80-M4: VIA P4M800 + VT8237 + IT8705AF -- * - GIGABYTE GA-7VT600: VIA KT600 + VT8237 + IT8705 -+ * Suited for Abit IP35: Intel P35 + ICH9R. -+ * Suited for Abit IP35 Pro: Intel P35 + ICH9R. - */ --static int it8705_rom_write_enable(const char *name) -+static int intel_ich_gpio16_raise(const char *name) - { -- /* enter IT87xx conf mode */ -- enter_conf_mode_ite(0x2e); -- -- /* select right flash chip */ -- sio_mask(0x2e, 0x22, 0x80, 0x80); -- -- /* bit 3: flash chip write enable -- * bit 7: map flash chip at 1MB-128K (why though? ignoring this.) -- */ -- sio_mask(0x2e, 0x24, 0x04, 0x04); -+ return intel_ich_gpio_set(16, 1); -+} - -- /* exit IT87xx conf mode */ -- exit_conf_mode_ite(0x2e); -+/** -+ * Suited for ASUS A8JM: Intel 945 + ICH7 -+ */ -+static int intel_ich_gpio34_raise(const char *name) -+{ -+ return intel_ich_gpio_set(34, 1); -+} - -- return 0; -+/** -+ * Suited for MSI MS-7046: LGA775 + 915P + ICH6. -+ */ -+static int intel_ich_gpio19_raise(const char *name) -+{ -+ return intel_ich_gpio_set(19, 1); - } - - /** -- * Suited for AOpen vKM400Am-S: VIA KM400 + VT8237 + IT8705F. -+ * Suited for: -+ * - ASUS P4B266LM (Sony Vaio PCV-RX650): socket478 + 845D + ICH2. -+ * - ASUS P4C800-E Deluxe: socket478 + 875P + ICH5. -+ * - ASUS P4P800-E Deluxe: Intel socket478 + 865PE + ICH5R. - */ --static int board_aopen_vkm400(const char *name) -+static int intel_ich_gpio21_raise(const char *name) - { -- struct pci_dev *dev; -+ return intel_ich_gpio_set(21, 1); -+} - -- dev = pci_dev_find(0x1106, 0x3227); /* VT8237 ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT8237 ISA bridge not found.\n"); -- return -1; -- } -+/** -+ * Suited for: -+ * - ASUS P4B266: socket478 + Intel 845D + ICH2. -+ * - ASUS P4B533-E: socket478 + 845E + ICH4 -+ * - ASUS P4B-MX variant in HP Vectra VL420 SFF: socket478 + 845D + ICH2 -+ */ -+static int intel_ich_gpio22_raise(const char *name) -+{ -+ return intel_ich_gpio_set(22, 1); -+} - -- vt823x_set_all_writes_to_lpc(dev); -+/** -+ * Suited for HP Vectra VL400: 815 + ICH + PC87360. -+ */ - -- return it8705_rom_write_enable(name); -+static int board_hp_vl400(const char *name) -+{ -+ int ret; -+ ret = intel_ich_gpio_set(25, 1); /* Master write enable ? */ -+ if (!ret) -+ ret = pc87360_gpio_set(0x09, 1); /* #WP ? */ -+ if (!ret) -+ ret = pc87360_gpio_set(0x27, 1); /* #TBL */ -+ return ret; - } - - /** -- * Winbond W83697HF Super I/O + VIA VT8235 southbridge -- * - * Suited for: -- * - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235 -- * - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235 -- * - MSI KT3 Ultra2: AMD K7 + VIA KT333 + VT8235 -+ * - Dell PowerEdge 1850: Intel PPGA604 + E7520 + ICH5R. -+ * - ASRock P4i65GV: Intel Socket478 + 865GV + ICH5R. - */ --static int board_msi_kt4v(const char *name) -+static int intel_ich_gpio23_raise(const char *name) - { -- struct pci_dev *dev; -- uint8_t val; -+ return intel_ich_gpio_set(23, 1); -+} - -- dev = pci_dev_find(0x1106, 0x3177); /* VT8235 ISA bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: VT823x ISA bridge not found.\n"); -- return -1; -- } -+/** -+ * Suited for IBase MB899: i945GM + ICH7. -+ */ -+static int intel_ich_gpio26_raise(const char *name) -+{ -+ return intel_ich_gpio_set(26, 1); -+} - -- val = pci_read_byte(dev, 0x59); -- val &= 0x0c; -- pci_write_byte(dev, 0x59, val); -+/** -+ * Suited for Acorp 6A815EPD: socket 370 + intel 815 + ICH2. -+ */ -+static int board_acorp_6a815epd(const char *name) -+{ -+ int ret; - -- vt823x_gpio_set(dev, 12, 1); -- w836xx_memw_enable(0x2E); -+ /* Lower Blocks Lock -- pin 7 of PLCC32 */ -+ ret = intel_ich_gpio_set(22, 1); -+ if (!ret) /* Top Block Lock -- pin 8 of PLCC32 */ -+ ret = intel_ich_gpio_set(23, 1); - -- return 0; -+ return ret; -+} -+ -+/** -+ * Suited for Kontron 986LCD-M: socket478 + 915GM + ICH7R. -+ */ -+static int board_kontron_986lcd_m(const char *name) -+{ -+ int ret; -+ -+ ret = intel_ich_gpio_set(34, 1); /* #TBL */ -+ if (!ret) -+ ret = intel_ich_gpio_set(35, 1); /* #WP */ -+ -+ return ret; - } - - /** - * Suited for Soyo SY-7VCA: Pro133A + VT82C686. - */ --static int board_soyo_sy_7vca(const char *name) -+static int via_apollo_gpo_set(int gpio, int raise) - { -- struct pci_dev *dev; -+ struct pci_dev *dev; - uint32_t base; -- uint8_t tmp; -+ uint32_t tmp; - - /* VT82C686 Power management */ - dev = pci_dev_find(0x1106, 0x3057); -@@ -699,39 +1055,86 @@ static int board_soyo_sy_7vca(const char *name) - return -1; - } - -- /* GPO0 output from PM IO base + 0x4C */ -+ printf("\nVIA Apollo ACPI: %sing GPIO%02d.\n", -+ raise ? "Rais" : "Dropp", gpio); -+ -+ /* select GPO function on multiplexed pins */ - tmp = pci_read_byte(dev, 0x54); -- tmp &= ~0x03; -+ switch(gpio) -+ { -+ case 0: -+ tmp &= ~0x03; -+ break; -+ case 1: -+ tmp |= 0x04; -+ break; -+ case 2: -+ tmp |= 0x08; -+ break; -+ case 3: -+ tmp |= 0x10; -+ break; -+ } - pci_write_byte(dev, 0x54, tmp); - - /* PM IO base */ - base = pci_read_long(dev, 0x48) & 0x0000FF00; - - /* Drop GPO0 */ -- tmp = INB(base + 0x4C); -- tmp &= ~0x01; -- OUTB(tmp, base + 0x4C); -+ tmp = INL(base + 0x4C); -+ if (raise) -+ tmp |= 1U << gpio; -+ else -+ tmp &= ~(1U << gpio); -+ OUTL(tmp, base + 0x4C); - - return 0; - } - --static int it8705f_write_enable(uint8_t port, const char *name) -+/** -+ * Suited for Abit VT6X4: Pro133x + VT82C686A -+ */ -+static int via_apollo_gpo4_lower(const char *name) - { -- enter_conf_mode_ite(port); -- sio_mask(port, 0x24, 0x04, 0x04); /* Flash ROM I/F Writes Enable */ -- exit_conf_mode_ite(port); -+ return via_apollo_gpo_set(4, 0); -+} - -- return 0; -+/** -+ * Suited for Soyo SY-7VCA: Pro133A + VT82C686. -+ */ -+static int via_apollo_gpo0_lower(const char *name) -+{ -+ return via_apollo_gpo_set(0, 0); - } - - /** -- * Suited for: -- * - Shuttle AK38N: VIA KT333CF + VIA VT8235 + ITE IT8705F -- * - Elitegroup K7VTA3: VIA Apollo KT266/A/333 + VIA VT8235 + ITE IT8705F -+ * Enable some GPIO pin on SiS southbridge. -+ * Suited for MSI 651M-L: SiS651 / SiS962 - */ --static int it8705f_write_enable_2e(const char *name) -+static int board_msi_651ml(const char *name) - { -- return it8705f_write_enable(0x2e, name); -+ struct pci_dev *dev; -+ uint16_t base, temp; -+ -+ dev = pci_dev_find(0x1039, 0x0962); -+ if (!dev) { -+ fprintf(stderr, "Expected south bridge not found\n"); -+ return 1; -+ } -+ -+ /* Registers 68 and 64 seem like bitmaps */ -+ base = pci_read_word(dev, 0x74); -+ temp = INW(base + 0x68); -+ temp &= ~(1 << 0); /* Make pin output? */ -+ OUTW(temp, base + 0x68); -+ -+ temp = INW(base + 0x64); -+ temp |= (1 << 0); /* Raise output? */ -+ OUTW(temp, base + 0x64); -+ -+ w836xx_memw_enable(0x2E); -+ -+ return 0; - } - - /** -@@ -802,33 +1205,7 @@ static int board_mitac_6513wu(const char *name) - } - - /** -- * Suited for Abit IP35: Intel P35 + ICH9R. -- */ --static int board_abit_ip35(const char *name) --{ -- struct pci_dev *dev; -- uint16_t base; -- uint8_t tmp; -- -- dev = pci_dev_find(0x8086, 0x2916); /* Intel ICH9R LPC Interface */ -- if (!dev) { -- fprintf(stderr, "\nERROR: Intel ICH9R LPC not found.\n"); -- return -1; -- } -- -- /* get LPC GPIO base */ -- base = pci_read_long(dev, 0x48) & 0x0000FFC0; -- -- /* Raise GPIO 16 */ -- tmp = INB(base + 0x0E); -- tmp |= 0x01; -- OUTB(tmp, base + 0x0E); -- -- return 0; --} -- --/** -- * Suited for Asus A7V8X: VIA KT400 + VT8235 + IT8703F-A -+ * Suited for ASUS A7V8X: VIA KT400 + VT8235 + IT8703F-A - */ - static int board_asus_a7v8x(const char *name) - { -@@ -841,7 +1218,7 @@ static int board_asus_a7v8x(const char *name) - w836xx_ext_leave(0x2E); - - if (id != 0x8701) { -- fprintf(stderr, "\nERROR: IT8703F SuperIO not found.\n"); -+ fprintf(stderr, "\nERROR: IT8703F Super I/O not found.\n"); - return -1; - } - -@@ -852,7 +1229,7 @@ static int board_asus_a7v8x(const char *name) - w836xx_ext_leave(0x2E); - - if (!base) { -- fprintf(stderr, "\nERROR: Failed to read IT8703F SuperIO GPIO" -+ fprintf(stderr, "\nERROR: Failed to read IT8703F Super I/O GPIO" - " Base.\n"); - return -1; - } -@@ -869,8 +1246,7 @@ static int board_asus_a7v8x(const char *name) - * General routine for raising/dropping GPIO lines on the ITE IT8712F. - * There is only some limited checking on the port numbers. - */ --static int --it8712f_gpio_set(unsigned int line, int raise) -+static int it8712f_gpio_set(unsigned int line, int raise) - { - unsigned int port; - uint16_t id, base; -@@ -894,7 +1270,7 @@ it8712f_gpio_set(unsigned int line, int raise) - exit_conf_mode_ite(0x2E); - - if (id != 0x8712) { -- fprintf(stderr, "\nERROR: IT8712F SuperIO not found.\n"); -+ fprintf(stderr, "\nERROR: IT8712F Super I/O not found.\n"); - return -1; - } - -@@ -905,7 +1281,7 @@ it8712f_gpio_set(unsigned int line, int raise) - exit_conf_mode_ite(0x2E); - - if (!base) { -- fprintf(stderr, "\nERROR: Failed to read IT8712F SuperIO GPIO" -+ fprintf(stderr, "\nERROR: Failed to read IT8712F Super I/O GPIO" - " Base.\n"); - return -1; - } -@@ -922,49 +1298,44 @@ it8712f_gpio_set(unsigned int line, int raise) - } - - /** -- * Suited for Asus A7V600-X: VIA KT600 + VT8237 + IT8712F -+ * Suited for: -+ * - ASUS A7V600-X: VIA KT600 + VT8237 + IT8712F -+ * - ASUS A7V8X-X: VIA KT400 + VT8235 + IT8712F - */ --static int board_asus_a7v600x(const char *name) -+static int it8712f_gpio3_1_raise(const char *name) - { - return it8712f_gpio_set(32, 1); - } - - /** -- * Suited for Asus P4P800-E Deluxe: Intel Intel 865PE + ICH5R. -- */ --static int board_asus_p4p800(const char *name) --{ -- struct pci_dev *dev; -- uint16_t base; -- uint8_t tmp; -- -- dev = pci_dev_find(0x8086, 0x24D0); /* Intel ICH5R ISA Bridge */ -- if (!dev) { -- fprintf(stderr, "\nERROR: Intel ICH5R ISA Bridge not found.\n"); -- return -1; -- } -- -- /* get PM IO base */ -- base = pci_read_long(dev, 0x58) & 0x0000FFC0; -- -- /* Raise GPIO 21 */ -- tmp = INB(base + 0x0E); -- tmp |= 0x20; -- OUTB(tmp, base + 0x0E); -- -- return 0; --} -- --/** -+ * Below is the list of boards which need a special "board enable" code in -+ * flashrom before their ROM chip can be accessed/written to. -+ * -+ * NOTE: Please add boards that _don't_ need such enables or don't work yet -+ * to the respective tables in print.c. Thanks! -+ * - * We use 2 sets of IDs here, you're free to choose which is which. This - * is to provide a very high degree of certainty when matching a board on - * the basis of subsystem/card IDs. As not every vendor handles - * subsystem/card IDs in a sane manner. - * - * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs -- * NULLed if they don't identify the board fully. But please take care to -- * provide an as complete set of pci ids as possible; autodetection is the -- * preferred behaviour and we would like to make sure that matches are unique. -+ * NULLed if they don't identify the board fully and if you can't use DMI. -+ * But please take care to provide an as complete set of pci ids as possible; -+ * autodetection is the preferred behaviour and we would like to make sure that -+ * matches are unique. -+ * -+ * If PCI IDs are not sufficient for board matching, the match can be further -+ * constrained by a string that has to be present in the DMI database for -+ * the baseboard or the system entry. The pattern is matched by case sensitive -+ * substring match, unless it is anchored to the beginning (with a ^ in front) -+ * or the end (with a $ at the end). Both anchors may be specified at the -+ * same time to match the full field. -+ * -+ * When a board is matched through DMI, the first and second main PCI IDs -+ * and the first subsystem PCI ID have to match as well. If you specify the -+ * first subsystem ID as 0x0:0x0, the DMI matching code expects that the -+ * subsystem ID of that device is indeed zero. - * - * The coreboot ids are used two fold. When running with a coreboot firmware, - * the ids uniquely matches the coreboot board identification string. When a -@@ -977,195 +1348,76 @@ static int board_asus_p4p800(const char *name) - - /* Please keep this list alphabetically ordered by vendor/board name. */ - struct board_pciid_enable board_pciid_enables[] = { -- /* first pci-id set [4], second pci-id set [4], coreboot id [2], vendor name board name flash enable */ -- {0x8086, 0x2926, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, "Abit", "IP35", board_abit_ip35}, -- {0x8086, 0x1130, 0, 0, 0x105a, 0x0d30, 0x105a, 0x4d33, "acorp", "6a815epd", "Acorp", "6A815EPD", board_acorp_6a815epd}, -- {0x1022, 0x746B, 0x1022, 0x36C0, 0, 0, 0, 0, "AGAMI", "ARUMA", "agami", "Aruma", w83627hf_gpio24_raise_2e}, -- {0x1106, 0x3177, 0x17F2, 0x3177, 0x1106, 0x3148, 0x17F2, 0x3148, NULL, NULL, "Albatron", "PM266A*", board_epox_ep_8k5a2}, -- {0x1106, 0x3205, 0x1106, 0x3205, 0x10EC, 0x8139, 0xA0A0, 0x0477, NULL, NULL, "AOpen", "vKM400Am-S", board_aopen_vkm400}, -- {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe61", "Artec Group", "DBE61", board_artecgroup_dbe6x}, -- {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, "artecgroup", "dbe62", "Artec Group", "DBE62", board_artecgroup_dbe6x}, -- {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, "ASUS", "A7V600-X", board_asus_a7v600x}, -- {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, "ASUS", "A7V8X", board_asus_a7v8x}, -- {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, "ASUS", "A7V8X-MX SE", board_asus_a7v8x_mx}, -- {0x8086, 0x1a30, 0x1043, 0x8070, 0x8086, 0x244b, 0x1043, 0x8028, NULL, NULL, "ASUS", "P4B266", ich2_gpio22_raise}, -- {0x8086, 0x2570, 0x1043, 0x80F2, 0x105A, 0x3373, 0x1043, 0x80F5, NULL, NULL, "ASUS", "P4P800-E Deluxe", board_asus_p4p800}, -- {0x10B9, 0x1541, 0, 0, 0x10B9, 0x1533, 0, 0, "asus", "p5a", "ASUS", "P5A", board_asus_p5a}, -- {0x1106, 0x3149, 0x1565, 0x3206, 0x1106, 0x3344, 0x1565, 0x1202, NULL, NULL, "Biostar", "P4M80-M4", it8705_rom_write_enable}, -- {0x1106, 0x3038, 0x1019, 0x0996, 0x1106, 0x3177, 0x1019, 0x0996, NULL, NULL, "Elitegroup", "K7VTA3", it8705f_write_enable_2e}, -- {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3059, 0x1695, 0x3005, NULL, NULL, "EPoX", "EP-8K5A2", board_epox_ep_8k5a2}, -- {0x8086, 0x7110, 0, 0, 0x8086, 0x7190, 0, 0, "epox", "ep-bx3", "EPoX", "EP-BX3", board_epox_ep_bx3}, -- {0x1039, 0x0761, 0, 0, 0, 0, 0, 0, "gigabyte", "2761gxdk", "GIGABYTE", "GA-2761GXDK", it87xx_probe_spi_flash}, -- {0x1106, 0x3227, 0x1458, 0x5001, 0x10ec, 0x8139, 0x1458, 0xe000, NULL, NULL, "GIGABYTE", "GA-7VT600", it8705_rom_write_enable}, -- {0x10DE, 0x0050, 0x1458, 0x0C11, 0x10DE, 0x005e, 0x1458, 0x5000, NULL, NULL, "GIGABYTE", "GA-K8N-SLI", board_ga_k8n_sli}, -- {0x10de, 0x0360, 0, 0, 0, 0, 0, 0, "gigabyte", "m57sli", "GIGABYTE", "GA-M57SLI-S4", it87xx_probe_spi_flash}, -- {0x10de, 0x03e0, 0, 0, 0, 0, 0, 0, "gigabyte", "m61p", "GIGABYTE", "GA-M61P-S3", it87xx_probe_spi_flash}, -- {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb000, NULL, NULL, "GIGABYTE", "GA-MA78G-DS3H", it87xx_probe_spi_flash}, -- {0x1002, 0x4398, 0x1458, 0x5004, 0x1002, 0x4391, 0x1458, 0xb002, NULL, NULL, "GIGABYTE", "GA-MA78GM-S2H", it87xx_probe_spi_flash}, -- /* SB600 LPC, RD790 North. Neither are specific to the GA-MA790FX-DQ6. The coreboot ID is here to be able to trigger the board enable more easily. */ -- {0x1002, 0x438d, 0x1458, 0x5001, 0x1002, 0x5956, 0x1002, 0x5956, "gigabyte", "ma790fx-dq6", "GIGABYTE", "GA-MA790FX-DQ6", it87xx_probe_spi_flash}, -- {0x1166, 0x0223, 0x103c, 0x320d, 0x102b, 0x0522, 0x103c, 0x31fa, "hp", "dl145_g3", "HP", "DL145 G3", board_hp_dl145_g3_enable}, -- {0x1166, 0x0205, 0x1014, 0x0347, 0, 0, 0, 0, "ibm", "x3455", "IBM", "x3455", board_ibm_x3455}, -- {0x1039, 0x5513, 0x8086, 0xd61f, 0x1039, 0x6330, 0x8086, 0xd61f, NULL, NULL, "Intel", "D201GLY", wbsio_check_for_spi}, -- {0x1022, 0x7468, 0, 0, 0, 0, 0, 0, "iwill", "dk8_htx", "IWILL", "DK8-HTX", w83627hf_gpio24_raise_2e}, -- /* Note: There are >= 2 version of the Kontron 986LCD-M/mITX! */ -- {0x8086, 0x27b8, 0, 0, 0, 0, 0, 0, "kontron", "986lcd-m", "Kontron", "986LCD-M", board_kontron_986lcd_m}, -- {0x10ec, 0x8168, 0x10ec, 0x8168, 0x104c, 0x8023, 0x104c, 0x8019, "kontron", "986lcd-m", "Kontron", "986LCD-M", board_kontron_986lcd_m}, -- {0x8086, 0x2411, 0x8086, 0x2411, 0x8086, 0x7125, 0x0e11, 0xb165, NULL, NULL, "Mitac", "6513WU", board_mitac_6513wu}, -- {0x13f6, 0x0111, 0x1462, 0x5900, 0x1106, 0x3177, 0x1106, 0, "msi", "kt4ultra", "MSI", "MS-6590 (KT4 Ultra)",board_msi_kt4v}, -- {0x1106, 0x3149, 0x1462, 0x7094, 0x10ec, 0x8167, 0x1462, 0x094c, NULL, NULL, "MSI", "MS-6702E (K8T Neo2-F)",w83627thf_gpio4_4_raise_2e}, -- {0x1106, 0x0571, 0x1462, 0x7120, 0, 0, 0, 0, "msi", "kt4v", "MSI", "MS-6712 (KT4V)", board_msi_kt4v}, -- {0x8086, 0x2658, 0x1462, 0x7046, 0x1106, 0x3044, 0x1462, 0x046d, NULL, NULL, "MSI", "MS-7046", ich6_gpio19_raise}, -- {0x10de, 0x005e, 0, 0, 0, 0, 0, 0, "msi", "k8n-neo3", "MSI", "MS-7135 (K8N Neo3)", w83627thf_gpio4_4_raise_4e}, -- {0x1106, 0x3104, 0x1297, 0xa238, 0x1106, 0x3059, 0x1297, 0xc063, NULL, NULL, "Shuttle", "AK38N", it8705f_write_enable_2e}, -- {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x3058, 0x15DD, 0x7609, NULL, NULL, "Soyo", "SY-7VCA", board_soyo_sy_7vca}, -- {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498, NULL, NULL, "Tyan", "S2498 (Tomcat K7M)", board_asus_a7v8x_mx}, -- {0x1106, 0x0314, 0x1106, 0xaa08, 0x1106, 0x3227, 0x1106, 0xAA08, NULL, NULL, "VIA", "EPIA-CN", board_via_epia_sp}, -- {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA M/MII/...", board_via_epia_m}, -- {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, "via", "epia-n", "VIA", "EPIA-N/NL", board_via_epia_n}, /* TODO: remove coreboot ids */ -- {0x1106, 0x3227, 0x1106, 0xAA01, 0x1106, 0x0259, 0x1106, 0xAA01, NULL, NULL, "VIA", "EPIA SP", board_via_epia_sp}, -- {0x1106, 0x5337, 0x1458, 0xb003, 0x1106, 0x287e, 0x1106, 0x337e, "via", "pc3500g", "VIA", "PC3500G", it87xx_probe_spi_flash}, -- -- { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}, /* end marker */ --}; -- --/* Please keep this list alphabetically ordered by vendor/board. */ --const struct board_info boards_ok[] = { -- /* Verified working boards that don't need write-enables. */ -- { "Abit", "AX8", }, -- { "Abit", "Fatal1ty F-I90HD", }, -- { "Advantech", "PCM-5820", }, -- { "ASI", "MB-5BLMP", }, -- { "ASRock", "A770CrossFire", }, -- { "ASUS", "A7N8X Deluxe", }, -- { "ASUS", "A7N8X-E Deluxe", }, -- { "ASUS", "A7V400-MX", }, -- { "ASUS", "A7V8X-MX", }, -- { "ASUS", "A8N-E", }, -- { "ASUS", "A8NE-FM/S", }, -- { "ASUS", "A8N-SLI", }, -- { "ASUS", "A8N-SLI Premium", }, -- { "ASUS", "A8V Deluxe", }, -- { "ASUS", "A8V-E Deluxe", }, -- { "ASUS", "A8V-E SE", }, -- { "ASUS", "M2A-MX", }, -- { "ASUS", "M2A-VM", }, -- { "ASUS", "M2N-E", }, -- { "ASUS", "M2V", }, -- { "ASUS", "P2B", }, -- { "ASUS", "P2B-D", }, -- { "ASUS", "P2B-DS", }, -- { "ASUS", "P2B-F", }, -- { "ASUS", "P2L97-S", }, -- { "ASUS", "P5B-Deluxe", }, -- { "ASUS", "P5KC", }, -- { "ASUS", "P5L-MX", }, -- { "ASUS", "P6T Deluxe V2", }, -- { "A-Trend", "ATC-6220", }, -- { "BCOM", "WinNET100", }, -- { "GIGABYTE", "GA-6BXC", }, -- { "GIGABYTE", "GA-6BXDU", }, -- { "GIGABYTE", "GA-6ZMA", }, -- { "GIGABYTE", "GA-7ZM", }, -- { "GIGABYTE", "GA-EP35-DS3L", }, -- { "GIGABYTE", "GA-EX58-UD4P", }, -- { "GIGABYTE", "GA-MA78GPM-DS2H", }, -- { "GIGABYTE", "GA-MA790GP-DS4H", }, -- { "Intel", "EP80759", }, -- { "Jetway", "J7F4K1G5D-PB", }, -- { "MSI", "MS-6570 (K7N2)", }, -- { "MSI", "MS-7065", }, -- { "MSI", "MS-7168 (Orion)", }, -- { "MSI", "MS-7236 (945PL Neo3)", }, -- { "MSI", "MS-7255 (P4M890M)", }, -- { "MSI", "MS-7345 (P35 Neo2-FIR)", }, -- { "NEC", "PowerMate 2000", }, -- { "PC Engines", "Alix.1c", }, -- { "PC Engines", "Alix.2c2", }, -- { "PC Engines", "Alix.2c3", }, -- { "PC Engines", "Alix.3c3", }, -- { "PC Engines", "Alix.3d3", }, -- { "RCA", "RM4100", }, -- { "Sun", "Blade x6250", }, -- { "Supermicro", "H8QC8", }, -- { "Thomson", "IP1000", }, -- { "TriGem", "Lomita", }, -- { "T-Online", "S-100", }, -- { "Tyan", "iS5375-1U", }, -- { "Tyan", "S1846", }, -- { "Tyan", "S2466", }, -- { "Tyan", "S2881", }, -- { "Tyan", "S2882", }, -- { "Tyan", "S2882-D", }, -- { "Tyan", "S2891", }, -- { "Tyan", "S2892", }, -- { "Tyan", "S2895", }, -- { "Tyan", "S3095", }, -- { "Tyan", "S5180", }, -- { "Tyan", "S5191", }, -- { "Tyan", "S5197", }, -- { "Tyan", "S5211", }, -- { "Tyan", "S5211-1U", }, -- { "Tyan", "S5220", }, -- { "Tyan", "S5375", }, -- { "Tyan", "S5376G2NR/S5376WAG2NR", }, -- { "Tyan", "S5377", }, -- { "Tyan", "S5397", }, -- { "VIA", "EPIA-EX15000G", }, -- { "VIA", "EPIA-LN", }, -- { "VIA", "EPIA-M700", }, -- { "VIA", "EPIA-NX15000G", }, -- { "VIA", "NAB74X0", }, -- { "VIA", "pc2500e", }, -- { "VIA", "VB700X", }, -- -- {}, --}; -- --/* Please keep this list alphabetically ordered by vendor/board. */ --const struct board_info boards_bad[] = { -- /* Verified non-working boards (for now). */ -- { "Abit", "IS-10", }, -- { "ASRock", "K7VT4A+", }, -- { "ASUS", "MEW-AM", }, -- { "ASUS", "MEW-VM", }, -- { "ASUS", "P3B-F", }, -- { "ASUS", "P5B", }, -- { "ASUS", "P5BV-M", }, -- { "Biostar", "M6TBA", }, -- { "Boser", "HS-6637", }, -- { "DFI", "855GME-MGF", }, -- { "FIC", "VA-502", }, -- { "MSI", "MS-6178", }, -- { "MSI", "MS-7260 (K9N Neo)", }, -- { "Soyo", "SY-5VD", }, -- { "Sun", "Fire x4150", }, -- { "Sun", "Fire x4200", }, -- { "Sun", "Fire x4540", }, -- { "Sun", "Fire x4600", }, -- -- {}, --}; -- --/* Please keep this list alphabetically ordered by vendor/board. */ --const struct board_info laptops_ok[] = { -- /* Verified working laptops. */ -- { "Lenovo", "3000 V100 TF05Cxx", }, - -- {}, --}; -- --/* Please keep this list alphabetically ordered by vendor/board. */ --const struct board_info laptops_bad[] = { -- /* Verified non-working laptops (for now). */ -- { "Acer", "Aspire One", }, -- { "ASUS", "Eee PC 701 4G", }, -- { "Dell", "Latitude CPi A366XT", }, -- { "HP/Compaq", "nx9010", }, -- { "IBM/Lenovo", "Thinkpad T40p", }, -- { "IBM/Lenovo", "240", }, -- -- {}, -+ /* first pci-id set [4], second pci-id set [4], dmi identifier coreboot id [2], vendor name board name max_rom_... OK? flash enable */ -+ {0x10DE, 0x0547, 0x147B, 0x1C2F, 0x10DE, 0x0548, 0x147B, 0x1C2F, NULL, NULL, NULL, "Abit", "AN-M2", 0, NT, nvidia_mcp_gpio2_raise}, -+ {0x8086, 0x2926, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, NULL, "Abit", "IP35", 0, OK, intel_ich_gpio16_raise}, -+ {0x8086, 0x2930, 0x147b, 0x1083, 0x10ec, 0x8167, 0x147b, 0x1083, NULL, NULL, NULL, "Abit", "IP35 Pro", 0, OK, intel_ich_gpio16_raise}, -+ {0x10de, 0x0050, 0x147b, 0x1c1a, 0, 0, 0, 0, NULL, NULL, NULL, "Abit", "KN8 Ultra", 0, NT, nvidia_mcp_gpio2_lower}, -+ {0x10de, 0x01e0, 0x147b, 0x1c00, 0x10de, 0x0060, 0x147B, 0x1c00, NULL, NULL, NULL, "Abit", "NF7-S", 0, OK, nvidia_mcp_gpio8_raise}, -+ {0x1106, 0x0691, 0, 0, 0x1106, 0x3057, 0, 0, NULL, "abit", "vt6x4", "Abit", "VT6X4", 0, OK, via_apollo_gpo4_lower}, -+ {0x105a, 0x0d30, 0x105a, 0x4d33, 0x8086, 0x1130, 0x8086, 0, NULL, NULL, NULL, "Acorp", "6A815EPD", 0, OK, board_acorp_6a815epd}, -+ {0x8086, 0x24D4, 0x1849, 0x24D0, 0x8086, 0x24D5, 0x1849, 0x9739, NULL, NULL, NULL, "ASRock", "P4i65GV", 0, OK, intel_ich_gpio23_raise}, -+ {0x1022, 0x746B, 0, 0, 0, 0, 0, 0, NULL, "AGAMI", "ARUMA", "agami", "Aruma", 0, OK, w83627hf_gpio24_raise_2e}, -+ {0x1106, 0x3177, 0x17F2, 0x3177, 0x1106, 0x3148, 0x17F2, 0x3148, NULL, NULL, NULL, "Albatron", "PM266A", 0, OK, w836xx_memw_enable_2e}, -+ {0x1106, 0x3205, 0x1106, 0x3205, 0x10EC, 0x8139, 0xA0A0, 0x0477, NULL, NULL, NULL, "AOpen", "vKM400Am-S", 0, OK, it8705f_write_enable_2e}, -+ {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, NULL, "artecgroup", "dbe61", "Artec Group", "DBE61", 0, OK, board_artecgroup_dbe6x}, -+ {0x1022, 0x2090, 0, 0, 0x1022, 0x2080, 0, 0, NULL, "artecgroup", "dbe62", "Artec Group", "DBE62", 0, OK, board_artecgroup_dbe6x}, -+ {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, NULL, "ASUS", "A7V600-X", 0, OK, it8712f_gpio3_1_raise}, -+ {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, NULL, "ASUS", "A7V8X", 0, OK, board_asus_a7v8x}, -+ {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x80A1, NULL, NULL, NULL, "ASUS", "A7V8X-X", 0, OK, it8712f_gpio3_1_raise}, -+ {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, NULL, "ASUS", "A7V8X-MX SE", 0, OK, w836xx_memw_enable_2e}, -+ {0x8086, 0x27A0, 0x1043, 0x1287, 0x8086, 0x27DF, 0x1043, 0x1287, "^A8J", NULL, NULL, "ASUS", "A8JM", 0, NT, intel_ich_gpio34_raise}, -+ {0x10DE, 0x005E, 0x1043, 0x815A, 0x10DE, 0x0054, 0x1043, 0x815A, NULL, NULL, NULL, "ASUS", "A8N", 0, NT, board_shuttle_fn25}, -+ {0x10DE, 0x0260, 0x103c, 0x2a3e, 0x10DE, 0x0264, 0x103c, 0x2a3e, "NAGAMI", NULL, NULL, "ASUS", "A8N-LA", 0, NT, nvidia_mcp_gpio0_raise}, -+ {0x10DE, 0x0264, 0x1043, 0x81C0, 0x10DE, 0x0260, 0x1043, 0x81C0, NULL, NULL, NULL, "ASUS", "M2NBP-VM CSM", 0, OK, nvidia_mcp_gpio0_raise}, -+ {0x1106, 0x1336, 0x1043, 0x80ed, 0x1106, 0x3288, 0x1043, 0x8249, NULL, NULL, NULL, "ASUS", "M2V-MX", 0, OK, via_vt823x_gpio5_raise}, -+ {0x8086, 0x1a30, 0x1043, 0x8070, 0x8086, 0x244b, 0x1043, 0x8028, NULL, NULL, NULL, "ASUS", "P4B266", 0, OK, intel_ich_gpio22_raise}, -+ {0x8086, 0x1A30, 0x1043, 0x8025, 0x8086, 0x244B, 0x104D, 0x80F0, NULL, NULL, NULL, "ASUS", "P4B266-LM", 0, OK, intel_ich_gpio21_raise}, -+ {0x8086, 0x1A30, 0x1043, 0x8088, 0x8086, 0x24C3, 0x1043, 0x8089, NULL, NULL, NULL, "ASUS", "P4B533-E", 0, NT, intel_ich_gpio22_raise}, -+ {0x8086, 0x24D3, 0x1043, 0x80A6, 0x8086, 0x2578, 0x1043, 0x80F6, NULL, NULL, NULL, "ASUS", "P4C800-E Deluxe", 0, OK, intel_ich_gpio21_raise}, -+ {0x8086, 0x2570, 0x1043, 0x80F2, 0x105A, 0x3373, 0x1043, 0x80F5, NULL, NULL, NULL, "ASUS", "P4P800-E Deluxe", 0, OK, intel_ich_gpio21_raise}, -+ {0x10B9, 0x1541, 0, 0, 0x10B9, 0x1533, 0, 0, "^P5A$", "asus", "p5a", "ASUS", "P5A", 0, OK, board_asus_p5a}, -+ {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, NULL, "ASUS", "P5ND2-SLI Deluxe", 0, OK, nvidia_mcp_gpio10_raise}, -+ {0x1106, 0x3149, 0x1565, 0x3206, 0x1106, 0x3344, 0x1565, 0x1202, NULL, NULL, NULL, "Biostar", "P4M80-M4", 0, OK, it8705f_write_enable_2e}, -+ {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, NULL, "Dell", "PowerEdge 1850", 0, OK, intel_ich_gpio23_raise}, -+ {0x1039, 0x5513, 0x1019, 0x0A41, 0x1039, 0x0018, 0, 0, NULL, NULL, NULL, "Elitegroup", "K7S6A", 0, OK, it8705f_write_enable_2e}, -+ {0x1106, 0x3038, 0x1019, 0x0996, 0x1106, 0x3177, 0x1019, 0x0996, NULL, NULL, NULL, "Elitegroup", "K7VTA3", 256, OK, it8705f_write_enable_2e}, -+ {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3059, 0x1695, 0x3005, NULL, NULL, NULL, "EPoX", "EP-8K5A2", 0, OK, w836xx_memw_enable_2e}, -+ {0x10EC, 0x8139, 0x1695, 0x9001, 0x11C1, 0x5811, 0x1695, 0x9015, NULL, NULL, NULL, "EPoX", "EP-8RDA3+", 0, OK, nvidia_mcp_gpio31_raise}, -+ {0x8086, 0x7110, 0, 0, 0x8086, 0x7190, 0, 0, NULL, "epox", "ep-bx3", "EPoX", "EP-BX3", 0, OK, board_epox_ep_bx3}, -+ {0x1106, 0x0686, 0x1106, 0x0686, 0x1106, 0x3058, 0x1458, 0xa000, NULL, NULL, NULL, "GIGABYTE", "GA-7ZM", 512, OK, NULL}, -+ {0x1106, 0x3227, 0x1458, 0x5001, 0x10ec, 0x8139, 0x1458, 0xe000, NULL, NULL, NULL, "GIGABYTE", "GA-7VT600", 0, OK, it8705f_write_enable_2e}, -+ {0x10DE, 0x0050, 0x1458, 0x0C11, 0x10DE, 0x005e, 0x1458, 0x5000, NULL, NULL, NULL, "GIGABYTE", "GA-K8N-SLI", 0, OK, nvidia_mcp_gpio21_raise}, -+ {0x1166, 0x0223, 0x103c, 0x320d, 0x102b, 0x0522, 0x103c, 0x31fa, NULL, "hp", "dl145_g3", "HP", "DL145 G3", 0, OK, board_hp_dl145_g3_enable}, -+ {0x8086, 0x2415, 0x103c, 0x1249, 0x10b7, 0x9200, 0x103c, 0x1246, NULL, NULL, NULL, "HP", "Vectra VL400", 0, OK, board_hp_vl400}, -+ {0x8086, 0x1a30, 0x103c, 0x1a30, 0x8086, 0x2443, 0x103c, 0x2440, "^VL420$", NULL, NULL, "HP", "VL420 SFF", 0, OK, intel_ich_gpio22_raise}, -+ {0x8086, 0x27A0, 0, 0, 0x8086, 0x27B9, 0, 0, NULL, "ibase", "mb899", "iBASE", "MB899", 0, NT, intel_ich_gpio26_raise}, -+ {0x1166, 0x0205, 0x1014, 0x0347, 0x1002, 0x515E, 0x1014, 0x0325, NULL, NULL, NULL, "IBM", "x3455", 0, OK, board_ibm_x3455}, -+ {0x1039, 0x5513, 0x8086, 0xd61f, 0x1039, 0x6330, 0x8086, 0xd61f, NULL, NULL, NULL, "Intel", "D201GLY", 0, OK, wbsio_check_for_spi}, -+ {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^SE440BX-2$", NULL, NULL, "Intel", "SE440BX-2", 0, NT, intel_piix4_gpo27_lower}, -+ {0x1022, 0x7468, 0, 0, 0, 0, 0, 0, NULL, "iwill", "dk8_htx", "IWILL", "DK8-HTX", 0, OK, w83627hf_gpio24_raise_2e}, -+ {0x8086, 0x27A0, 0x8086, 0x27a0, 0x8086, 0x27b8, 0x8086, 0x27b8, NULL, "kontron", "986lcd-m", "Kontron", "986LCD-M", 0, OK, board_kontron_986lcd_m}, -+ {0x8086, 0x2411, 0x8086, 0x2411, 0x8086, 0x7125, 0x0e11, 0xb165, NULL, NULL, NULL, "Mitac", "6513WU", 0, OK, board_mitac_6513wu}, -+ {0x13f6, 0x0111, 0x1462, 0x5900, 0x1106, 0x3177, 0x1106, 0, NULL, NULL, NULL, "MSI", "MS-6590 (KT4 Ultra)", 0, OK, board_msi_kt4v}, -+ {0x1106, 0x3149, 0x1462, 0x7094, 0x10ec, 0x8167, 0x1462, 0x094c, NULL, NULL, NULL, "MSI", "MS-6702E (K8T Neo2-F)", 0, OK, w83627thf_gpio4_4_raise_2e}, -+ {0x1106, 0x0571, 0x1462, 0x7120, 0x1106, 0x3065, 0x1462, 0x7120, NULL, NULL, NULL, "MSI", "MS-6712 (KT4V)", 0, OK, board_msi_kt4v}, -+ {0x1039, 0x7012, 0x1462, 0x0050, 0x1039, 0x6325, 0x1462, 0x0058, NULL, NULL, NULL, "MSI", "MS-7005 (651M-L)", 0, OK, board_msi_651ml}, -+ {0x8086, 0x2658, 0x1462, 0x7046, 0x1106, 0x3044, 0x1462, 0x046d, NULL, NULL, NULL, "MSI", "MS-7046", 0, OK, intel_ich_gpio19_raise}, -+ {0x10DE, 0x005E, 0x1462, 0x7135, 0x10DE, 0x0050, 0x1462, 0x7135, NULL, "msi", "k8n-neo3", "MSI", "MS-7135 (K8N Neo3)", 0, OK, w83627thf_gpio4_4_raise_4e}, -+ {0x10DE, 0x0270, 0x1462, 0x7207, 0x10DE, 0x0264, 0x1462, 0x7207, NULL, NULL, NULL, "MSI", "MS-7207 (K8N GM2-L)", 0, NT, nvidia_mcp_gpio2_raise}, -+ {0x10DE, 0x005E, 0x1462, 0x7125, 0x10DE, 0x0052, 0x1462, 0x7125, NULL, NULL, NULL, "MSI", "K8N Neo4-F", 0, OK, nvidia_mcp_gpio2_raise}, -+ {0x1106, 0x3099, 0, 0, 0x1106, 0x3074, 0, 0, NULL, "shuttle", "ak31", "Shuttle", "AK31", 0, OK, w836xx_memw_enable_2e}, -+ {0x1106, 0x3104, 0x1297, 0xa238, 0x1106, 0x3059, 0x1297, 0xc063, NULL, NULL, NULL, "Shuttle", "AK38N", 256, OK, it8705f_write_enable_2e}, -+ {0x10DE, 0x0050, 0x1297, 0x5036, 0x1412, 0x1724, 0x1297, 0x5036, NULL, NULL, NULL, "Shuttle", "FN25", 0, OK, board_shuttle_fn25}, -+ {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x3058, 0x15DD, 0x7609, NULL, NULL, NULL, "Soyo", "SY-7VCA", 0, OK, via_apollo_gpo0_lower}, -+ {0x8086, 0x1076, 0x8086, 0x1176, 0x1106, 0x3059, 0x10f1, 0x2498, NULL, NULL, NULL, "Tyan", "S2498 (Tomcat K7M)", 0, OK, w836xx_memw_enable_2e}, -+ {0x1106, 0x3038, 0x0925, 0x1234, 0x1106, 0x0596, 0x1106, 0, NULL, NULL, NULL, "Tekram", "P6Pro-A5", 256, OK, NULL}, -+ {0x1106, 0x3123, 0x1106, 0x3123, 0x1106, 0x3059, 0x1106, 0x4161, NULL, NULL, NULL, "Termtek", "TK-3370 (Rev:2.5B)", 0, OK, w836xx_memw_enable_4e}, -+ {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, NULL, "VIA", "EPIA M/MII/...", 0, OK, via_vt823x_gpio15_raise}, -+ {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, NULL, "VIA", "EPIA-N/NL", 0, OK, via_vt823x_gpio9_raise}, -+ -+ { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 0, NT, NULL}, /* end marker */ - }; - - /** -@@ -1230,7 +1482,8 @@ static struct board_pciid_enable *board_match_pci_card_ids(void) - struct board_pciid_enable *board = board_pciid_enables; - - for (; board->vendor_name; board++) { -- if (!board->first_card_vendor || !board->first_card_device) -+ if ((!board->first_card_vendor || !board->first_card_device) && -+ !board->dmi_pattern) - continue; - - if (!pci_card_find(board->first_vendor, board->first_device, -@@ -1252,6 +1505,18 @@ static struct board_pciid_enable *board_match_pci_card_ids(void) - } - } - -+ if (board->dmi_pattern) { -+ if (!has_dmi_support) { -+ fprintf(stderr, "WARNING: Can't autodetect %s %s," -+ " DMI info unavailable.\n", -+ board->vendor_name, board->board_name); -+ continue; -+ } else { -+ if (!dmi_match(board->dmi_pattern)) -+ continue; -+ } -+ } -+ - return board; - } - -@@ -1269,15 +1534,38 @@ int board_flash_enable(const char *vendor, const char *part) - if (!board) - board = board_match_pci_card_ids(); - -- if (board) { -- printf("Disabling flash write protection for board \"%s %s\"... ", -- board->vendor_name, board->board_name); -+ if (board && board->status == NT) { -+ if (!force_boardenable) { -+ printf("WARNING: Your mainboard is %s %s, but the mainboard-specific\n" -+ "code has not been tested, and thus will not not be executed by default.\n" -+ "Depending on your hardware environment, erasing, writing or even probing\n" -+ "can fail without running the board specific code.\n\n" -+ "Please see the man page (section PROGRAMMER SPECIFIC INFO, subsection\n" -+ "\"internal programmer\") for details.\n", -+ board->vendor_name, board->board_name); -+ board = NULL; -+ } else { -+ printf("NOTE: Running an untested board enable procedure.\n" -+ "Please report success/failure to flashrom@flashrom.org.\n"); -+ } -+ } - -- ret = board->enable(board->vendor_name); -- if (ret) -- printf("FAILED!\n"); -- else -- printf("OK.\n"); -+ if (board) { -+ if (board->max_rom_decode_parallel) -+ max_rom_decode.parallel = -+ board->max_rom_decode_parallel * 1024; -+ -+ if (board->enable != NULL) { -+ printf("Disabling flash write protection for " -+ "board \"%s %s\"... ", board->vendor_name, -+ board->board_name); -+ -+ ret = board->enable(board->vendor_name); -+ if (ret) -+ printf("FAILED!\n"); -+ else -+ printf("OK.\n"); -+ } - } - - return ret; -diff --git a/buspirate_spi.c b/buspirate_spi.c -new file mode 100644 -index 0000000..dc491e2 ---- /dev/null -+++ b/buspirate_spi.c -@@ -0,0 +1,354 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Carl-Daniel Hailfinger -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "flash.h" -+#include "chipdrivers.h" -+#include "spi.h" -+ -+/* Change this to #define if you want to test without a serial implementation */ -+#undef FAKE_COMMUNICATION -+ -+#ifndef FAKE_COMMUNICATION -+int buspirate_serialport_setup(char *dev) -+{ -+ /* 115200bps, 8 databits, no parity, 1 stopbit */ -+ sp_fd = sp_openserport(dev, 115200); -+ return 0; -+} -+#else -+#define buspirate_serialport_setup(...) 0 -+#define serialport_shutdown(...) 0 -+#define serialport_write(...) 0 -+#define serialport_read(...) 0 -+#define sp_flush_incoming(...) 0 -+#endif -+ -+int buspirate_sendrecv(unsigned char *buf, unsigned int writecnt, unsigned int readcnt) -+{ -+ int i, ret = 0; -+ -+ msg_pspew("%s: write %i, read %i ", __func__, writecnt, readcnt); -+ if (!writecnt && !readcnt) { -+ msg_perr("Zero length command!\n"); -+ return 1; -+ } -+ msg_pspew("Sending"); -+ for (i = 0; i < writecnt; i++) -+ msg_pspew(" 0x%02x", buf[i]); -+#ifdef FAKE_COMMUNICATION -+ /* Placate the caller for now. */ -+ if (readcnt) { -+ buf[0] = 0x01; -+ memset(buf + 1, 0xff, readcnt - 1); -+ } -+ ret = 0; -+#else -+ if (writecnt) -+ ret = serialport_write(buf, writecnt); -+ if (ret) -+ return ret; -+ if (readcnt) -+ ret = serialport_read(buf, readcnt); -+ if (ret) -+ return ret; -+#endif -+ msg_pspew(", receiving"); -+ for (i = 0; i < readcnt; i++) -+ msg_pspew(" 0x%02x", buf[i]); -+ msg_pspew("\n"); -+ return 0; -+} -+ -+static const struct buspirate_spispeeds spispeeds[] = { -+ {"30k", 0x0}, -+ {"125k", 0x1}, -+ {"250k", 0x2}, -+ {"1M", 0x3}, -+ {"2M", 0x4}, -+ {"2.6M", 0x5}, -+ {"4M", 0x6}, -+ {"8M", 0x7}, -+ {NULL, 0x0} -+}; -+ -+int buspirate_spi_init(void) -+{ -+ unsigned char buf[512]; -+ int ret = 0; -+ int i; -+ char *dev = NULL; -+ char *speed = NULL; -+ int spispeed = 0x7; -+ -+ if (programmer_param && !strlen(programmer_param)) { -+ free(programmer_param); -+ programmer_param = NULL; -+ } -+ if (programmer_param) { -+ dev = extract_param(&programmer_param, "dev=", ",:"); -+ speed = extract_param(&programmer_param, "spispeed=", ",:"); -+ if (strlen(programmer_param)) -+ msg_perr("Unhandled programmer parameters: %s\n", -+ programmer_param); -+ free(programmer_param); -+ programmer_param = NULL; -+ } -+ if (!dev) { -+ msg_perr("No serial device given. Use flashrom -p " -+ "buspiratespi:dev=/dev/ttyUSB0\n"); -+ return 1; -+ } -+ if (speed) { -+ for (i = 0; spispeeds[i].name; i++) -+ if (!strncasecmp(spispeeds[i].name, speed, -+ strlen(spispeeds[i].name))) { -+ spispeed = spispeeds[i].speed; -+ break; -+ } -+ if (!spispeeds[i].name) -+ msg_perr("Invalid SPI speed, using default.\n"); -+ } -+ /* This works because speeds numbering starts at 0 and is contiguous. */ -+ msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed].name); -+ -+ ret = buspirate_serialport_setup(dev); -+ if (ret) -+ return ret; -+ -+ /* This is the brute force version, but it should work. */ -+ for (i = 0; i < 19; i++) { -+ /* Enter raw bitbang mode */ -+ buf[0] = 0x00; -+ /* Send the command, don't read the response. */ -+ ret = buspirate_sendrecv(buf, 1, 0); -+ if (ret) -+ return ret; -+ /* Read any response and discard it. */ -+ sp_flush_incoming(); -+ } -+ /* Enter raw bitbang mode */ -+ buf[0] = 0x00; -+ ret = buspirate_sendrecv(buf, 1, 5); -+ if (ret) -+ return ret; -+ if (memcmp(buf, "BBIO", 4)) { -+ msg_perr("Entering raw bitbang mode failed!\n"); -+ return 1; -+ } -+ msg_pdbg("Raw bitbang mode version %c\n", buf[4]); -+ if (buf[4] != '1') { -+ msg_perr("Can't handle raw bitbang mode version %c!\n", -+ buf[4]); -+ return 1; -+ } -+ /* Enter raw SPI mode */ -+ buf[0] = 0x01; -+ ret = buspirate_sendrecv(buf, 1, 4); -+ if (memcmp(buf, "SPI", 3)) { -+ msg_perr("Entering raw SPI mode failed!\n"); -+ return 1; -+ } -+ msg_pdbg("Raw SPI mode version %c\n", buf[3]); -+ if (buf[3] != '1') { -+ msg_perr("Can't handle raw SPI mode version %c!\n", -+ buf[3]); -+ return 1; -+ } -+ -+ /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */ -+ buf[0] = 0x40 | 0xb; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return 1; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while setting power/CS/AUX!\n"); -+ return 1; -+ } -+ -+ /* Set SPI speed */ -+ buf[0] = 0x60 | spispeed; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return 1; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while setting SPI speed!\n"); -+ return 1; -+ } -+ -+ /* Set SPI config: output type, idle, clock edge, sample */ -+ buf[0] = 0x80 | 0xa; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return 1; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while setting SPI config!\n"); -+ return 1; -+ } -+ -+ /* De-assert CS# */ -+ buf[0] = 0x03; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return 1; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while raising CS#!\n"); -+ return 1; -+ } -+ -+ buses_supported = CHIP_BUSTYPE_SPI; -+ spi_controller = SPI_CONTROLLER_BUSPIRATE; -+ -+ return 0; -+} -+ -+int buspirate_spi_shutdown(void) -+{ -+ unsigned char buf[5]; -+ int ret = 0; -+ -+ /* Exit raw SPI mode (enter raw bitbang mode) */ -+ buf[0] = 0x00; -+ ret = buspirate_sendrecv(buf, 1, 5); -+ if (ret) -+ return ret; -+ if (memcmp(buf, "BBIO", 4)) { -+ msg_perr("Entering raw bitbang mode failed!\n"); -+ return 1; -+ } -+ msg_pdbg("Raw bitbang mode version %c\n", buf[4]); -+ if (buf[4] != '1') { -+ msg_perr("Can't handle raw bitbang mode version %c!\n", -+ buf[4]); -+ return 1; -+ } -+ /* Reset Bus Pirate (return to user terminal) */ -+ buf[0] = 0x0f; -+ ret = buspirate_sendrecv(buf, 1, 0); -+ if (ret) -+ return ret; -+ -+ /* Shut down serial port communication */ -+ ret = serialport_shutdown(); -+ if (ret) -+ return ret; -+ msg_pdbg("Bus Pirate shutdown completed.\n"); -+ -+ return 0; -+} -+ -+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, -+ const unsigned char *writearr, unsigned char *readarr) -+{ -+ static unsigned char *buf = NULL; -+ int i = 0, ret = 0; -+ -+ if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16) -+ return SPI_INVALID_LENGTH; -+ -+ /* +2 is pretty arbitrary. */ -+ buf = realloc(buf, writecnt + readcnt + 2); -+ if (!buf) { -+ msg_perr("Out of memory!\n"); -+ exit(1); // -1 -+ } -+ -+ /* Assert CS# */ -+ buf[i++] = 0x02; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return SPI_GENERIC_ERROR; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while lowering CS#!\n"); -+ return SPI_GENERIC_ERROR; -+ } -+ -+ i = 0; -+ buf[i++] = 0x10 | (writecnt + readcnt - 1); -+ memcpy(buf + i, writearr, writecnt); -+ i += writecnt; -+ memset(buf + i, 0, readcnt); -+ ret = buspirate_sendrecv(buf, i + readcnt, i + readcnt); -+ if (ret) -+ return SPI_GENERIC_ERROR; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while reading/writing SPI!\n"); -+ return SPI_GENERIC_ERROR; -+ } -+ memcpy(readarr, buf + i, readcnt); -+ -+ i = 0; -+ /* De-assert CS# */ -+ buf[i++] = 0x03; -+ ret = buspirate_sendrecv(buf, 1, 1); -+ if (ret) -+ return SPI_GENERIC_ERROR; -+ if (buf[0] != 0x01) { -+ msg_perr("Protocol error while raising CS#!\n"); -+ return SPI_GENERIC_ERROR; -+ } -+ -+ return ret; -+} -+ -+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -+{ -+ return spi_read_chunked(flash, buf, start, len, 12); -+} -+ -+int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf) -+{ -+ int total_size = 1024 * flash->total_size; -+ int i; -+ -+ spi_disable_blockprotect(); -+ /* Erase first. */ -+ msg_pinfo("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ msg_perr("ERASE FAILED!\n"); -+ return -1; -+ } -+ msg_pinfo("done.\n"); -+ -+ /* FIXME: We could do 12 byte writes, but then we'd have to make sure -+ * not to cross a 256 byte page boundary. This problem only applies to -+ * writes, reads can cross page boundaries just fine. -+ */ -+ for (i = 0; i < total_size; i += 8) { -+ int l, r; -+ if (i + 8 <= total_size) -+ l = 8; -+ else -+ l = total_size - i; -+ -+ if ((r = spi_nbyte_program(i, &buf[i], l))) { -+ msg_perr("%s: write fail %d\n", __func__, r); -+ return 1; -+ } -+ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ /* loop */; -+ } -+ -+ return 0; -+} -diff --git a/cbtable.c b/cbtable.c -index 9d7e758..c12354c 100644 ---- a/cbtable.c -+++ b/cbtable.c -@@ -6,6 +6,7 @@ - * (Written by Eric Biederman for Linux Networx) - * Copyright (C) 2006-2009 coresystems GmbH - * (Written by Stefan Reinauer for coresystems GmbH) -+ * Copyright (C) 2010 Carl-Daniel Hailfinger - * - * 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 -@@ -30,13 +31,27 @@ - char *lb_part = NULL, *lb_vendor = NULL; - int partvendor_from_cbtable = 0; - -+void lb_vendor_dev_from_string(char *boardstring) -+{ -+ char *tempstr2 = NULL; -+ strtok(boardstring, ":"); -+ tempstr2 = strtok(NULL, ":"); -+ if (tempstr2) { -+ lb_vendor = boardstring; -+ lb_part = tempstr2; -+ } else { -+ lb_vendor = NULL; -+ lb_part = boardstring; -+ } -+} -+ - static unsigned long compute_checksum(void *addr, unsigned long length) - { - uint8_t *ptr; - volatile union { - uint8_t byte[2]; - uint16_t word; -- } value; -+ } chksum; - unsigned long sum; - unsigned long i; - -@@ -58,10 +73,10 @@ static unsigned long compute_checksum(void *addr, unsigned long length) - sum = (sum + (sum >> 16)) & 0xFFFF; - } - } -- value.byte[0] = sum & 0xff; -- value.byte[1] = (sum >> 8) & 0xff; -+ chksum.byte[0] = sum & 0xff; -+ chksum.byte[1] = (sum >> 8) & 0xff; - -- return (~value.word) & 0xFFFF; -+ return (~chksum.word) & 0xFFFF; - } - - #define for_each_lbrec(head, rec) \ -@@ -193,11 +208,15 @@ int coreboot_init(void) - #else - start = 0x0; - #endif -- table_area = physmap("low megabyte", start, BYTES_TO_MAP); -+ table_area = physmap_try_ro("low megabyte", start, BYTES_TO_MAP - start); -+ if (!table_area) { -+ msg_perr("Failed getting access to coreboot low tables.\n"); -+ return -1; -+ } - - lb_table = find_lb_table(table_area, 0x00000, 0x1000); - if (!lb_table) -- lb_table = find_lb_table(table_area, 0xf0000, BYTES_TO_MAP); -+ lb_table = find_lb_table(table_area, 0xf0000 - start, BYTES_TO_MAP - start); - if (lb_table) { - struct lb_forward *forward = (struct lb_forward *) - (((char *)lb_table) + lb_table->header_bytes); -@@ -205,7 +224,12 @@ int coreboot_init(void) - start = forward->forward; - start &= ~(getpagesize() - 1); - physunmap(table_area, BYTES_TO_MAP); -- table_area = physmap("high tables", start, BYTES_TO_MAP); -+ table_area = physmap_try_ro("high tables", start, BYTES_TO_MAP); -+ if (!table_area) { -+ msg_perr("Failed getting access to coreboot " -+ "high tables.\n"); -+ return -1; -+ } - lb_table = find_lb_table(table_area, 0x00000, 0x1000); - } - } -diff --git a/chipdrivers.h b/chipdrivers.h -new file mode 100644 -index 0000000..6d5cef0 ---- /dev/null -+++ b/chipdrivers.h -@@ -0,0 +1,125 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Carl-Daniel Hailfinger -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ * -+ * -+ * Header file for flash chip drivers. Included from flash.h. -+ * As a general rule, every function listed here should take a pointer to -+ * struct flashchip as first parameter. -+ */ -+ -+#ifndef __CHIPDRIVERS_H__ -+#define __CHIPDRIVERS_H__ 1 -+ -+/* spi.c, should probably be in spi_chip.c */ -+int probe_spi_rdid(struct flashchip *flash); -+int probe_spi_rdid4(struct flashchip *flash); -+int probe_spi_rems(struct flashchip *flash); -+int probe_spi_res(struct flashchip *flash); -+int spi_write_enable(void); -+int spi_write_disable(void); -+int spi_chip_erase_60(struct flashchip *flash); -+int spi_chip_erase_c7(struct flashchip *flash); -+int spi_chip_erase_60_c7(struct flashchip *flash); -+int spi_chip_erase_d8(struct flashchip *flash); -+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_block_erase_d7(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int spi_chip_write_1(struct flashchip *flash, uint8_t *buf); -+int spi_chip_write_256(struct flashchip *flash, uint8_t *buf); -+int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); -+uint8_t spi_read_status_register(void); -+int spi_disable_blockprotect(void); -+int spi_byte_program(int addr, uint8_t databyte); -+int spi_nbyte_program(int addr, uint8_t *bytes, int len); -+int spi_nbyte_read(int addr, uint8_t *bytes, int len); -+int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize); -+int spi_aai_write(struct flashchip *flash, uint8_t *buf); -+ -+/* 82802ab.c */ -+uint8_t wait_82802ab(chipaddr bios); -+int probe_82802ab(struct flashchip *flash); -+int erase_82802ab(struct flashchip *flash); -+int erase_block_82802ab(struct flashchip *flash, unsigned int page, unsigned int pagesize); -+int write_82802ab(struct flashchip *flash, uint8_t *buf); -+void print_status_82802ab(uint8_t status); -+void write_page_82802ab(chipaddr bios, uint8_t *src, chipaddr dst, int page_size); -+int unlock_82802ab(struct flashchip *flash); -+int unlock_28f004s5(struct flashchip *flash); -+ -+/* jedec.c */ -+uint8_t oddparity(uint8_t val); -+void toggle_ready_jedec(chipaddr dst); -+void data_polling_jedec(chipaddr dst, uint8_t data); -+int write_byte_program_jedec(chipaddr bios, uint8_t *src, -+ chipaddr dst); -+int probe_jedec(struct flashchip *flash); -+int erase_chip_jedec(struct flashchip *flash); -+int write_jedec(struct flashchip *flash, uint8_t *buf); -+int write_jedec_1(struct flashchip *flash, uint8_t *buf); -+int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int pagesize); -+int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize); -+int erase_chip_block_jedec(struct flashchip *flash, unsigned int page, unsigned int blocksize); -+int write_sector_jedec_common(struct flashchip *flash, uint8_t *src, chipaddr dst, unsigned int page_size, unsigned int mask); -+ -+/* m29f400bt.c */ -+int probe_m29f400bt(struct flashchip *flash); -+int erase_m29f400bt(struct flashchip *flash); -+int block_erase_m29f400bt(struct flashchip *flash, unsigned int start, unsigned int len); -+int block_erase_chip_m29f400bt(struct flashchip *flash, unsigned int start, unsigned int len); -+int write_m29f400bt(struct flashchip *flash, uint8_t *buf); -+int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf); -+void protect_m29f400bt(chipaddr bios); -+void write_page_m29f400bt(chipaddr bios, uint8_t *src, -+ chipaddr dst, int page_size); -+ -+/* pm49fl00x.c */ -+int unlock_49fl00x(struct flashchip *flash); -+int lock_49fl00x(struct flashchip *flash); -+ -+/* sst28sf040.c */ -+int erase_chip_28sf040(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int erase_sector_28sf040(struct flashchip *flash, unsigned int address, unsigned int sector_size); -+int write_28sf040(struct flashchip *flash, uint8_t *buf); -+ -+/* sst49lfxxxc.c */ -+int erase_sector_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size); -+int write_49lfxxxc(struct flashchip *flash, uint8_t *buf); -+int unlock_49lfxxxc(struct flashchip *flash); -+ -+/* sst_fwhub.c */ -+int printlock_sst_fwhub(struct flashchip *flash); -+int unlock_sst_fwhub(struct flashchip *flash); -+ -+/* w39v040c.c */ -+int printlock_w39v040c(struct flashchip *flash); -+ -+/* w39V080fa.c */ -+int unlock_winbond_fwhub(struct flashchip *flash); -+ -+/* w29ee011.c */ -+int probe_w29ee011(struct flashchip *flash); -+ -+/* stm50flw0x0x.c */ -+int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int block, unsigned int blocksize); -+int erase_chip_stm50flw0x0x(struct flashchip *flash, unsigned int addr, unsigned int blocklen); -+int unlock_stm50flw0x0x(struct flashchip *flash); -+ -+#endif /* !__CHIPDRIVERS_H__ */ -diff --git a/chipset_enable.c b/chipset_enable.c -index 8dcaf0b..fc60484 100644 ---- a/chipset_enable.c -+++ b/chipset_enable.c -@@ -4,6 +4,8 @@ - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005-2009 coresystems GmbH - * Copyright (C) 2006 Uwe Hermann -+ * Copyright (C) 2007,2008,2009 Carl-Daniel Hailfinger -+ * Copyright (C) 2009 Kontron Modular Computers GmbH - * - * 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 -@@ -32,16 +34,6 @@ - #include - #include "flash.h" - --unsigned long flashbase = 0; -- --/** -- * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host -- * controller is found, the init routine sets the buses_supported bitfield to -- * contain the supported buses for that controller. -- */ -- --enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI; -- - extern int ichspi_lock; - - static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) -@@ -59,56 +51,151 @@ static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) - return 0; - } - --static int enable_flash_sis630(struct pci_dev *dev, const char *name) -+static int enable_flash_sis85c496(struct pci_dev *dev, const char *name) - { -- uint8_t b; -- -- /* Enable 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */ -- b = pci_read_byte(dev, 0x40); -- pci_write_byte(dev, 0x40, b | 0xb); -- -- /* Flash write enable on SiS 540/630. */ -- b = pci_read_byte(dev, 0x45); -- pci_write_byte(dev, 0x45, b | 0x40); -- -- /* The same thing on SiS 950 Super I/O side... */ -- -- /* First probe for Super I/O on config port 0x2e. */ -- OUTB(0x87, 0x2e); -- OUTB(0x01, 0x2e); -- OUTB(0x55, 0x2e); -- OUTB(0x55, 0x2e); -- -- if (INB(0x2f) != 0x87) { -- /* If that failed, try config port 0x4e. */ -- OUTB(0x87, 0x4e); -- OUTB(0x01, 0x4e); -- OUTB(0x55, 0x4e); -- OUTB(0xaa, 0x4e); -- if (INB(0x4f) != 0x87) { -- printf("Can not access SiS 950\n"); -- return -1; -- } -- OUTB(0x24, 0x4e); -- b = INB(0x4f) | 0xfc; -- OUTB(0x24, 0x4e); -- OUTB(b, 0x4f); -- OUTB(0x02, 0x4e); -- OUTB(0x02, 0x4f); -- } -+ uint8_t tmp; -+ -+ tmp = pci_read_byte(dev, 0xd0); -+ tmp |= 0xf8; -+ pci_write_byte(dev, 0xd0, tmp); - -- OUTB(0x24, 0x2e); -- printf_debug("2f is %#x\n", INB(0x2f)); -- b = INB(0x2f) | 0xfc; -- OUTB(0x24, 0x2e); -- OUTB(b, 0x2f); -+ return 0; -+} - -- OUTB(0x02, 0x2e); -- OUTB(0x02, 0x2f); -+static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name) -+{ -+ uint8_t new, newer; - -+ /* Extended BIOS enable = 1, Lower BIOS Enable = 1 */ -+ /* This is 0xFFF8000~0xFFFF0000 decoding on SiS 540/630. */ -+ new = pci_read_byte(dev, 0x40); -+ new &= (~0x04); /* No idea why we clear bit 2. */ -+ new |= 0xb; /* 0x3 for some chipsets, bit 7 seems to be don't care. */ -+ pci_write_byte(dev, 0x40, new); -+ newer = pci_read_byte(dev, 0x40); -+ if (newer != new) { -+ printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); -+ printf_debug("Stuck at 0x%x\n", newer); -+ return -1; -+ } - return 0; - } - -+static struct pci_dev *find_southbridge(uint16_t vendor, const char *name) -+{ -+ struct pci_dev *sbdev; -+ -+ sbdev = pci_dev_find_vendorclass(vendor, 0x0601); -+ if (!sbdev) -+ sbdev = pci_dev_find_vendorclass(vendor, 0x0680); -+ if (!sbdev) -+ sbdev = pci_dev_find_vendorclass(vendor, 0x0000); -+ if (!sbdev) -+ fprintf(stderr, "No southbridge found for %s!\n", name); -+ if (sbdev) -+ printf_debug("Found southbridge %04x:%04x at %02x:%02x:%01x\n", -+ sbdev->vendor_id, sbdev->device_id, -+ sbdev->bus, sbdev->dev, sbdev->func); -+ return sbdev; -+} -+ -+static int enable_flash_sis501(struct pci_dev *dev, const char *name) -+{ -+ uint8_t tmp; -+ int ret = 0; -+ struct pci_dev *sbdev; -+ -+ sbdev = find_southbridge(dev->vendor_id, name); -+ if (!sbdev) -+ return -1; -+ -+ ret = enable_flash_sis_mapping(sbdev, name); -+ -+ tmp = sio_read(0x22, 0x80); -+ tmp &= (~0x20); -+ tmp |= 0x4; -+ sio_write(0x22, 0x80, tmp); -+ -+ tmp = sio_read(0x22, 0x70); -+ tmp &= (~0x20); -+ tmp |= 0x4; -+ sio_write(0x22, 0x70, tmp); -+ -+ return ret; -+} -+ -+static int enable_flash_sis5511(struct pci_dev *dev, const char *name) -+{ -+ uint8_t tmp; -+ int ret = 0; -+ struct pci_dev *sbdev; -+ -+ sbdev = find_southbridge(dev->vendor_id, name); -+ if (!sbdev) -+ return -1; -+ -+ ret = enable_flash_sis_mapping(sbdev, name); -+ -+ tmp = sio_read(0x22, 0x50); -+ tmp &= (~0x20); -+ tmp |= 0x4; -+ sio_write(0x22, 0x50, tmp); -+ -+ return ret; -+} -+ -+static int enable_flash_sis530(struct pci_dev *dev, const char *name) -+{ -+ uint8_t new, newer; -+ int ret = 0; -+ struct pci_dev *sbdev; -+ -+ sbdev = find_southbridge(dev->vendor_id, name); -+ if (!sbdev) -+ return -1; -+ -+ ret = enable_flash_sis_mapping(sbdev, name); -+ -+ new = pci_read_byte(sbdev, 0x45); -+ new &= (~0x20); -+ new |= 0x4; -+ pci_write_byte(sbdev, 0x45, new); -+ newer = pci_read_byte(sbdev, 0x45); -+ if (newer != new) { -+ printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); -+ printf_debug("Stuck at 0x%x\n", newer); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ -+static int enable_flash_sis540(struct pci_dev *dev, const char *name) -+{ -+ uint8_t new, newer; -+ int ret = 0; -+ struct pci_dev *sbdev; -+ -+ sbdev = find_southbridge(dev->vendor_id, name); -+ if (!sbdev) -+ return -1; -+ -+ ret = enable_flash_sis_mapping(sbdev, name); -+ -+ new = pci_read_byte(sbdev, 0x45); -+ new &= (~0x80); -+ new |= 0x40; -+ pci_write_byte(sbdev, 0x45, new); -+ newer = pci_read_byte(sbdev, 0x45); -+ if (newer != new) { -+ printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); -+ printf_debug("Stuck at 0x%x\n", newer); -+ ret = -1; -+ } -+ -+ return ret; -+} -+ - /* Datasheet: - * - Name: 82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4) - * - URL: http://www.intel.com/design/intarch/datashts/290562.htm -@@ -120,6 +207,8 @@ static int enable_flash_piix4(struct pci_dev *dev, const char *name) - uint16_t old, new; - uint16_t xbcs = 0x4e; /* X-Bus Chip Select register. */ - -+ buses_supported = CHIP_BUSTYPE_PARALLEL; -+ - old = pci_read_word(dev, xbcs); - - /* Set bit 9: 1-Meg Extended BIOS Enable (PCI master accesses to -@@ -204,51 +293,115 @@ static int enable_flash_ich_dc(struct pci_dev *dev, const char *name) - uint32_t fwh_conf; - int i; - char *idsel = NULL; -+ int tmp; -+ int max_decode_fwh_idsel = 0; -+ int max_decode_fwh_decode = 0; -+ int contiguous = 1; - -- /* Ignore all legacy ranges below 1 MB. */ -+ if (programmer_param) -+ idsel = strstr(programmer_param, "fwh_idsel="); -+ -+ if (idsel) { -+ idsel += strlen("fwh_idsel="); -+ fwh_conf = (uint32_t)strtoul(idsel, NULL, 0); -+ -+ /* FIXME: Need to undo this on shutdown. */ -+ printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf); -+ pci_write_long(dev, 0xd0, fwh_conf); -+ pci_write_word(dev, 0xd4, fwh_conf); -+ /* FIXME: Decode settings are not changed. */ -+ } -+ -+ /* Ignore all legacy ranges below 1 MB. -+ * We currently only support flashing the chip which responds to -+ * IDSEL=0. To support IDSEL!=0, flashbase and decode size calculations -+ * have to be adjusted. -+ */ - /* FWH_SEL1 */ - fwh_conf = pci_read_long(dev, 0xd0); -- for (i = 7; i >= 0; i--) -+ for (i = 7; i >= 0; i--) { -+ tmp = (fwh_conf >> (i * 4)) & 0xf; - printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", - (0x1ff8 + i) * 0x80000, - (0x1ff0 + i) * 0x80000, -- (fwh_conf >> (i * 4)) & 0xf); -+ tmp); -+ if ((tmp == 0) && contiguous) { -+ max_decode_fwh_idsel = (8 - i) * 0x80000; -+ } else { -+ contiguous = 0; -+ } -+ } - /* FWH_SEL2 */ - fwh_conf = pci_read_word(dev, 0xd4); -- for (i = 3; i >= 0; i--) -+ for (i = 3; i >= 0; i--) { -+ tmp = (fwh_conf >> (i * 4)) & 0xf; - printf_debug("\n0x%08x/0x%08x FWH IDSEL: 0x%x", - (0xff4 + i) * 0x100000, - (0xff0 + i) * 0x100000, -- (fwh_conf >> (i * 4)) & 0xf); -+ tmp); -+ if ((tmp == 0) && contiguous) { -+ max_decode_fwh_idsel = (8 - i) * 0x100000; -+ } else { -+ contiguous = 0; -+ } -+ } -+ contiguous = 1; - /* FWH_DEC_EN1 */ - fwh_conf = pci_read_word(dev, 0xd8); -- for (i = 7; i >= 0; i--) -+ for (i = 7; i >= 0; i--) { -+ tmp = (fwh_conf >> (i + 0x8)) & 0x1; - printf_debug("\n0x%08x/0x%08x FWH decode %sabled", - (0x1ff8 + i) * 0x80000, - (0x1ff0 + i) * 0x80000, -- (fwh_conf >> (i + 0x8)) & 0x1 ? "en" : "dis"); -- for (i = 3; i >= 0; i--) -+ tmp ? "en" : "dis"); -+ if ((tmp == 1) && contiguous) { -+ max_decode_fwh_decode = (8 - i) * 0x80000; -+ } else { -+ contiguous = 0; -+ } -+ } -+ for (i = 3; i >= 0; i--) { -+ tmp = (fwh_conf >> i) & 0x1; - printf_debug("\n0x%08x/0x%08x FWH decode %sabled", - (0xff4 + i) * 0x100000, - (0xff0 + i) * 0x100000, -- (fwh_conf >> i) & 0x1 ? "en" : "dis"); -+ tmp ? "en" : "dis"); -+ if ((tmp == 1) && contiguous) { -+ max_decode_fwh_decode = (8 - i) * 0x100000; -+ } else { -+ contiguous = 0; -+ } -+ } -+ max_rom_decode.fwh = min(max_decode_fwh_idsel, max_decode_fwh_decode); -+ printf_debug("\nMaximum FWH chip size: 0x%x bytes", max_rom_decode.fwh); - -- if (programmer_param) -- idsel = strstr(programmer_param, "fwh_idsel="); -+ /* If we're called by enable_flash_ich_dc_spi, it will override -+ * buses_supported anyway. -+ */ -+ buses_supported = CHIP_BUSTYPE_FWH; -+ return enable_flash_ich(dev, name, 0xdc); -+} - -- if (idsel) { -- idsel += strlen("fwh_idsel="); -- fwh_conf = (uint32_t)strtoul(idsel, NULL, 0); -+static int enable_flash_poulsbo(struct pci_dev *dev, const char *name) -+{ -+ uint16_t old, new; -+ int err; - -- /* FIXME: Need to undo this on shutdown. */ -- printf("\nSetting IDSEL=0x%x for top 16 MB", fwh_conf); -- pci_write_long(dev, 0xd0, fwh_conf); -- pci_write_word(dev, 0xd4, fwh_conf); -- } -+ if ((err = enable_flash_ich(dev, name, 0xd8)) != 0) -+ return err; - -- return enable_flash_ich(dev, name, 0xdc); -+ old = pci_read_byte(dev, 0xd9); -+ printf_debug("BIOS Prefetch Enable: %sabled, ", -+ (old & 1) ? "en" : "dis"); -+ new = old & ~1; -+ -+ if (new != old) -+ pci_write_byte(dev, 0xd9, new); -+ -+ return 0; - } - -+ - #define ICH_STRAP_RSVD 0x00 - #define ICH_STRAP_SPI 0x01 - #define ICH_STRAP_PCI 0x02 -@@ -258,6 +411,7 @@ static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name) - { - uint32_t mmio_base; - -+ /* Do we really need no write enable? */ - mmio_base = (pci_read_long(dev, 0xbc)) << 8; - printf_debug("MMIO base at = 0x%x\n", mmio_base); - spibar = physmap("VT8237S MMIO registers", mmio_base, 0x70); -@@ -312,8 +466,7 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, - */ - - if (ich_generation == 7 && bbs == ICH_STRAP_LPC) { -- /* Not sure if it speaks LPC as well. */ -- buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH; -+ buses_supported = CHIP_BUSTYPE_FWH; - /* No further SPI initialization required */ - return ret; - } -@@ -325,16 +478,14 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, - spibar_offset = 0x3020; - break; - case 8: -- /* Not sure if it speaks LPC as well. */ -- buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; -+ buses_supported = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_ICH9; - spibar_offset = 0x3020; - break; - case 9: - case 10: - default: /* Future version might behave the same */ -- /* Not sure if it speaks LPC as well. */ -- buses_supported = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; -+ buses_supported = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_ICH9; - spibar_offset = 0x3800; - break; -@@ -506,6 +657,13 @@ static int enable_flash_vt823x(struct pci_dev *dev, const char *name) - return -1; - } - -+ if (dev->device_id == 0x3227) { /* VT8237R */ -+ /* All memory cycles, not just ROM ones, go to LPC. */ -+ val = pci_read_byte(dev, 0x59); -+ val &= ~0x80; -+ pci_write_byte(dev, 0x59, val); -+ } -+ - return 0; - } - -@@ -515,14 +673,22 @@ static int enable_flash_cs5530(struct pci_dev *dev, const char *name) - - #define DECODE_CONTROL_REG2 0x5b /* F0 index 0x5b */ - #define ROM_AT_LOGIC_CONTROL_REG 0x52 /* F0 index 0x52 */ -+#define CS5530_RESET_CONTROL_REG 0x44 /* F0 index 0x44 */ -+#define CS5530_USB_SHADOW_REG 0x43 /* F0 index 0x43 */ - - #define LOWER_ROM_ADDRESS_RANGE (1 << 0) - #define ROM_WRITE_ENABLE (1 << 1) - #define UPPER_ROM_ADDRESS_RANGE (1 << 2) - #define BIOS_ROM_POSITIVE_DECODE (1 << 5) -+#define CS5530_ISA_MASTER (1 << 7) -+#define CS5530_ENABLE_SA2320 (1 << 2) -+#define CS5530_ENABLE_SA20 (1 << 6) - -+ buses_supported = CHIP_BUSTYPE_PARALLEL; - /* Decode 0x000E0000-0x000FFFFF (128 KB), not just 64 KB, and - * decode 0xFF000000-0xFFFFFFFF (16 MB), not just 256 KB. -+ * FIXME: Should we really touch the low mapping below 1 MB? Flashrom -+ * ignores that region completely. - * Make the configured ROM areas writable. - */ - reg8 = pci_read_byte(dev, ROM_AT_LOGIC_CONTROL_REG); -@@ -536,6 +702,24 @@ static int enable_flash_cs5530(struct pci_dev *dev, const char *name) - reg8 |= BIOS_ROM_POSITIVE_DECODE; - pci_write_byte(dev, DECODE_CONTROL_REG2, reg8); - -+ reg8 = pci_read_byte(dev, CS5530_RESET_CONTROL_REG); -+ if (reg8 & CS5530_ISA_MASTER) { -+ /* We have A0-A23 available. */ -+ max_rom_decode.parallel = 16 * 1024 * 1024; -+ } else { -+ reg8 = pci_read_byte(dev, CS5530_USB_SHADOW_REG); -+ if (reg8 & CS5530_ENABLE_SA2320) { -+ /* We have A0-19, A20-A23 available. */ -+ max_rom_decode.parallel = 16 * 1024 * 1024; -+ } else if (reg8 & CS5530_ENABLE_SA20) { -+ /* We have A0-19, A20 available. */ -+ max_rom_decode.parallel = 2 * 1024 * 1024; -+ } else { -+ /* A20 and above are not active. */ -+ max_rom_decode.parallel = 1024 * 1024; -+ } -+ } -+ - return 0; - } - -@@ -592,38 +776,6 @@ static int enable_flash_sc1100(struct pci_dev *dev, const char *name) - return 0; - } - --static int enable_flash_sis5595(struct pci_dev *dev, const char *name) --{ -- uint8_t new, newer; -- -- new = pci_read_byte(dev, 0x45); -- -- new &= (~0x20); /* Clear bit 5. */ -- new |= 0x4; /* Set bit 2. */ -- -- pci_write_byte(dev, 0x45, new); -- -- newer = pci_read_byte(dev, 0x45); -- if (newer != new) { -- printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x45, new, name); -- printf_debug("Stuck at 0x%x\n", newer); -- return -1; -- } -- -- /* Extended BIOS enable = 1, Lower BIOS Enable = 1 */ -- new = pci_read_byte(dev, 0x40); -- new &= 0xFB; -- new |= 0x3; -- pci_write_byte(dev, 0x40, new); -- newer = pci_read_byte(dev, 0x40); -- if (newer != new) { -- printf_debug("tried to set register 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x40, new, name); -- printf_debug("Stuck at 0x%x\n", newer); -- return -1; -- } -- return 0; --} -- - /* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */ - static int enable_flash_amd8111(struct pci_dev *dev, const char *name) - { -@@ -874,19 +1026,19 @@ static int enable_flash_sb400(struct pci_dev *dev, const char *name) - - static int enable_flash_mcp55(struct pci_dev *dev, const char *name) - { -- uint8_t old, new, byte; -- uint16_t word; -+ uint8_t old, new, val; -+ uint16_t wordval; - - /* Set the 0-16 MB enable bits. */ -- byte = pci_read_byte(dev, 0x88); -- byte |= 0xff; /* 256K */ -- pci_write_byte(dev, 0x88, byte); -- byte = pci_read_byte(dev, 0x8c); -- byte |= 0xff; /* 1M */ -- pci_write_byte(dev, 0x8c, byte); -- word = pci_read_word(dev, 0x90); -- word |= 0x7fff; /* 16M */ -- pci_write_word(dev, 0x90, word); -+ val = pci_read_byte(dev, 0x88); -+ val |= 0xff; /* 256K */ -+ pci_write_byte(dev, 0x88, val); -+ val = pci_read_byte(dev, 0x8c); -+ val |= 0xff; /* 1M */ -+ pci_write_byte(dev, 0x8c, val); -+ wordval = pci_read_word(dev, 0x90); -+ wordval |= 0x7fff; /* 16M */ -+ pci_write_word(dev, 0x90, wordval); - - old = pci_read_byte(dev, 0x6d); - new = old | 0x01; -@@ -902,18 +1054,186 @@ static int enable_flash_mcp55(struct pci_dev *dev, const char *name) - return 0; - } - -+/* This is a shot in the dark. Even if the code is totally bogus for some -+ * chipsets, users will at least start to send in reports. -+ */ -+static int enable_flash_mcp6x_7x_common(struct pci_dev *dev, const char *name) -+{ -+ int ret = 0; -+ uint8_t val; -+ uint16_t status; -+ char *busname; -+ uint32_t mcp_spibaraddr; -+ void *mcp_spibar; -+ struct pci_dev *smbusdev; -+ -+ msg_pinfo("This chipset is not really supported yet. Guesswork...\n"); -+ -+ /* dev is the ISA bridge. No idea what the stuff below does. */ -+ val = pci_read_byte(dev, 0x8a); -+ msg_pdbg("ISA/LPC bridge reg 0x8a contents: 0x%02x, bit 6 is %i, bit 5 " -+ "is %i\n", val, (val >> 6) & 0x1, (val >> 5) & 0x1); -+ switch ((val >> 5) & 0x3) { -+ case 0x0: -+ buses_supported = CHIP_BUSTYPE_LPC; -+ break; -+ case 0x2: -+ buses_supported = CHIP_BUSTYPE_SPI; -+ break; -+ default: -+ buses_supported = CHIP_BUSTYPE_UNKNOWN; -+ break; -+ } -+ busname = flashbuses_to_text(buses_supported); -+ msg_pdbg("Guessed flash bus type is %s\n", busname); -+ free(busname); -+ -+ /* Force enable SPI and disable LPC? Not a good idea. */ -+#if 0 -+ val |= (1 << 6); -+ val &= ~(1 << 5); -+ pci_write_byte(dev, 0x8a, val); -+#endif -+ -+ /* Look for the SMBus device (SMBus PCI class) */ -+ smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05); -+ if (!smbusdev) { -+ if (buses_supported & CHIP_BUSTYPE_SPI) { -+ msg_perr("ERROR: SMBus device not found. Not enabling " -+ "SPI.\n"); -+ buses_supported &= ~CHIP_BUSTYPE_SPI; -+ ret = 1; -+ } else { -+ msg_pinfo("Odd. SMBus device not found.\n"); -+ } -+ goto out_msg; -+ } -+ msg_pdbg("Found SMBus device %04x:%04x at %02x:%02x:%01x\n", -+ smbusdev->vendor_id, smbusdev->device_id, -+ smbusdev->bus, smbusdev->dev, smbusdev->func); -+ -+ /* Locate the BAR where the SPI interface lives. */ -+ mcp_spibaraddr = pci_read_long(smbusdev, 0x74); -+ msg_pdbg("SPI BAR is at 0x%08x, ", mcp_spibaraddr); -+ /* We hope this has native alignment. We know the SPI interface (well, -+ * a set of GPIOs that is connected to SPI flash) is at offset 0x530, -+ * so we expect a size of at least 0x800. Clear the lower bits. -+ * It is entirely possible that the BAR is 64k big and the low bits are -+ * reserved for an entirely different purpose. -+ */ -+ mcp_spibaraddr &= ~0x7ff; -+ msg_pdbg("after clearing low bits BAR is at 0x%08x\n", mcp_spibaraddr); -+ -+ /* Accessing a NULL pointer BAR is evil. Don't do it. */ -+ if (mcp_spibaraddr && (buses_supported == CHIP_BUSTYPE_SPI)) { -+ /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */ -+ mcp_spibar = physmap("MCP67 SPI", mcp_spibaraddr, 0x544); -+ -+/* Guessed. If this is correct, migrate to a separate MCP67 SPI driver. */ -+#define MCP67_SPI_CS (1 << 1) -+#define MCP67_SPI_SCK (1 << 2) -+#define MCP67_SPI_MOSI (1 << 3) -+#define MCP67_SPI_MISO (1 << 4) -+#define MCP67_SPI_ENABLE (1 << 0) -+#define MCP67_SPI_IDLE (1 << 8) -+ -+ status = mmio_readw(mcp_spibar + 0x530); -+ msg_pdbg("SPI control is 0x%04x, enable=%i, idle=%i\n", -+ status, status & 0x1, (status >> 8) & 0x1); -+ /* FIXME: Remove the physunmap once the SPI driver exists. */ -+ physunmap(mcp_spibar, 0x544); -+ } else if (!mcp_spibaraddr && (buses_supported & CHIP_BUSTYPE_SPI)) { -+ msg_pdbg("Strange. MCP SPI BAR is invalid.\n"); -+ buses_supported &= ~CHIP_BUSTYPE_SPI; -+ ret = 1; -+ } else if (mcp_spibaraddr && !(buses_supported & CHIP_BUSTYPE_SPI)) { -+ msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently" -+ " doesn't have SPI enabled.\n"); -+ } else { -+ msg_pdbg("MCP SPI is not used.\n"); -+ } -+out_msg: -+ msg_pinfo("Please send the output of \"flashrom -V\" to " -+ "flashrom@flashrom.org to help us finish support for your " -+ "chipset. Thanks.\n"); -+ -+ return ret; -+} -+ -+/** -+ * The MCP61/MCP67 code is guesswork based on cleanroom reverse engineering. -+ * Due to that, it only reads info and doesn't change any settings. -+ * It is assumed that LPC chips need the MCP55 code and SPI chips need the -+ * code provided in enable_flash_mcp6x_7x_common. Until we know for sure, call -+ * enable_flash_mcp55 from this function only if enable_flash_mcp6x_7x_common -+ * indicates the flash chip is LPC. Warning: enable_flash_mcp55 -+ * might make SPI flash inaccessible. The same caveat applies to SPI init -+ * for LPC flash. -+ */ -+static int enable_flash_mcp67(struct pci_dev *dev, const char *name) -+{ -+ int result = 0; -+ -+ result = enable_flash_mcp6x_7x_common(dev, name); -+ if (result) -+ return result; -+ -+ /* Not sure if this is correct. No docs as usual. */ -+ switch (buses_supported) { -+ case CHIP_BUSTYPE_LPC: -+ result = enable_flash_mcp55(dev, name); -+ break; -+ case CHIP_BUSTYPE_SPI: -+ msg_pinfo("SPI on this chipset is not supported yet.\n"); -+ buses_supported = CHIP_BUSTYPE_NONE; -+ break; -+ default: -+ msg_pinfo("Something went wrong with bus type detection.\n"); -+ buses_supported = CHIP_BUSTYPE_NONE; -+ break; -+ } -+ -+ return result; -+} -+ -+static int enable_flash_mcp7x(struct pci_dev *dev, const char *name) -+{ -+ int result = 0; -+ -+ result = enable_flash_mcp6x_7x_common(dev, name); -+ if (result) -+ return result; -+ -+ /* Not sure if this is correct. No docs as usual. */ -+ switch (buses_supported) { -+ case CHIP_BUSTYPE_LPC: -+ msg_pinfo("LPC on this chipset is not supported yet.\n"); -+ break; -+ case CHIP_BUSTYPE_SPI: -+ msg_pinfo("SPI on this chipset is not supported yet.\n"); -+ buses_supported = CHIP_BUSTYPE_NONE; -+ break; -+ default: -+ msg_pinfo("Something went wrong with bus type detection.\n"); -+ buses_supported = CHIP_BUSTYPE_NONE; -+ break; -+ } -+ -+ return result; -+} -+ - static int enable_flash_ht1000(struct pci_dev *dev, const char *name) - { -- uint8_t byte; -+ uint8_t val; - - /* Set the 4MB enable bit. */ -- byte = pci_read_byte(dev, 0x41); -- byte |= 0x0e; -- pci_write_byte(dev, 0x41, byte); -+ val = pci_read_byte(dev, 0x41); -+ val |= 0x0e; -+ pci_write_byte(dev, 0x41, val); - -- byte = pci_read_byte(dev, 0x43); -- byte |= (1 << 4); -- pci_write_byte(dev, 0x43, byte); -+ val = pci_read_byte(dev, 0x43); -+ val |= (1 << 4); -+ pci_write_byte(dev, 0x43, val); - - return 0; - } -@@ -972,12 +1292,16 @@ const struct penable chipset_enables[] = { - {0x1022, 0x7468, OK, "AMD", "AMD8111", enable_flash_amd8111}, - {0x1078, 0x0100, OK, "AMD", "CS5530(A)", enable_flash_cs5530}, - {0x1022, 0x2080, OK, "AMD", "CS5536", enable_flash_cs5536}, -+ {0x1022, 0x2090, OK, "AMD", "CS5536", enable_flash_cs5536}, - {0x1022, 0x3000, OK, "AMD", "Elan SC520", get_flashbase_sc520}, - {0x1002, 0x438D, OK, "AMD", "SB600", enable_flash_sb600}, - {0x1002, 0x439d, OK, "AMD", "SB700/SB710/SB750", enable_flash_sb600}, - {0x100b, 0x0510, NT, "AMD", "SC1100", enable_flash_sc1100}, - {0x1002, 0x4377, OK, "ATI", "SB400", enable_flash_sb400}, - {0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000}, -+ {0x8086, 0x3b00, NT, "Intel", "3400 Desktop", enable_flash_ich10}, -+ {0x8086, 0x3b01, NT, "Intel", "3400 Mobile", enable_flash_ich10}, -+ {0x8086, 0x3b0d, NT, "Intel", "3400 Mobile SFF", enable_flash_ich10}, - {0x8086, 0x7198, OK, "Intel", "440MX", enable_flash_piix4}, - {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich_4e}, - {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc}, -@@ -1000,6 +1324,7 @@ const struct penable chipset_enables[] = { - {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R", enable_flash_ich7}, - {0x8086, 0x27b9, OK, "Intel", "ICH7M", enable_flash_ich7}, - {0x8086, 0x27bd, OK, "Intel", "ICH7MDH", enable_flash_ich7}, -+ {0x8086, 0x27bc, OK, "Intel", "NM10", enable_flash_ich7}, - {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich_4e}, - {0x8086, 0x2812, OK, "Intel", "ICH8DH", enable_flash_ich8}, - {0x8086, 0x2814, OK, "Intel", "ICH8DO", enable_flash_ich8}, -@@ -1017,6 +1342,8 @@ const struct penable chipset_enables[] = { - {0x8086, 0x7000, OK, "Intel", "PIIX3", enable_flash_piix4}, - {0x8086, 0x7110, OK, "Intel", "PIIX4/4E/4M", enable_flash_piix4}, - {0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4}, -+ {0x8086, 0x8119, OK, "Intel", "Poulsbo", enable_flash_poulsbo}, -+ {0x10de, 0x0030, OK, "NVIDIA", "nForce4/MCP4", enable_flash_nvidia_nforce2}, - {0x10de, 0x0050, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* LPC */ - {0x10de, 0x0051, OK, "NVIDIA", "CK804", enable_flash_ck804}, /* Pro */ - {0x10de, 0x0060, OK, "NVIDIA", "NForce2", enable_flash_nvidia_nforce2}, -@@ -1034,17 +1361,60 @@ const struct penable chipset_enables[] = { - {0x10de, 0x0365, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0366, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* LPC */ - {0x10de, 0x0367, OK, "NVIDIA", "MCP55", enable_flash_mcp55}, /* Pro */ -- {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp55}, -- {0x1039, 0x0008, OK, "SiS", "SiS5595", enable_flash_sis5595}, -- {0x1039, 0x0630, NT, "SiS", "SiS630", enable_flash_sis630}, -+ {0x10de, 0x03e0, NT, "NVIDIA", "MCP61", enable_flash_mcp67}, -+ {0x10de, 0x03e1, NT, "NVIDIA", "MCP61", enable_flash_mcp67}, -+ {0x10de, 0x03e2, NT, "NVIDIA", "MCP61", enable_flash_mcp67}, -+ {0x10de, 0x03e3, NT, "NVIDIA", "MCP61", enable_flash_mcp67}, -+ {0x10de, 0x0440, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, -+ {0x10de, 0x0441, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, -+ {0x10de, 0x0442, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, -+ {0x10de, 0x0443, NT, "NVIDIA", "MCP65", enable_flash_mcp7x}, -+ {0x10de, 0x0548, OK, "NVIDIA", "MCP67", enable_flash_mcp67}, -+ {0x10de, 0x075c, NT, "NVIDIA", "MCP78S", enable_flash_mcp7x}, -+ {0x10de, 0x075d, NT, "NVIDIA", "MCP78S", enable_flash_mcp7x}, -+ {0x10de, 0x07d7, NT, "NVIDIA", "MCP73", enable_flash_mcp7x}, -+ {0x10de, 0x0aac, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, -+ {0x10de, 0x0aad, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, -+ {0x10de, 0x0aae, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, -+ {0x10de, 0x0aaf, NT, "NVIDIA", "MCP79", enable_flash_mcp7x}, -+ {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, -+ {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, -+ {0x1039, 0x5511, NT, "SiS", "5511", enable_flash_sis5511}, -+ {0x1039, 0x5596, NT, "SiS", "5596", enable_flash_sis5511}, -+ {0x1039, 0x5571, NT, "SiS", "5571", enable_flash_sis530}, -+ {0x1039, 0x5591, NT, "SiS", "5591/5592", enable_flash_sis530}, -+ {0x1039, 0x5597, NT, "SiS", "5597/5598/5581/5120", enable_flash_sis530}, -+ {0x1039, 0x0530, NT, "SiS", "530", enable_flash_sis530}, -+ {0x1039, 0x5600, NT, "SiS", "600", enable_flash_sis530}, -+ {0x1039, 0x0620, NT, "SiS", "620", enable_flash_sis530}, -+ {0x1039, 0x0540, NT, "SiS", "540", enable_flash_sis540}, -+ {0x1039, 0x0630, NT, "SiS", "630", enable_flash_sis540}, -+ {0x1039, 0x0635, NT, "SiS", "635", enable_flash_sis540}, -+ {0x1039, 0x0640, NT, "SiS", "640", enable_flash_sis540}, -+ {0x1039, 0x0645, NT, "SiS", "645", enable_flash_sis540}, -+ {0x1039, 0x0646, NT, "SiS", "645DX", enable_flash_sis540}, -+ {0x1039, 0x0648, NT, "SiS", "648", enable_flash_sis540}, -+ {0x1039, 0x0650, NT, "SiS", "650", enable_flash_sis540}, -+ {0x1039, 0x0651, NT, "SiS", "651", enable_flash_sis540}, -+ {0x1039, 0x0655, NT, "SiS", "655", enable_flash_sis540}, -+ {0x1039, 0x0730, NT, "SiS", "730", enable_flash_sis540}, -+ {0x1039, 0x0733, NT, "SiS", "733", enable_flash_sis540}, -+ {0x1039, 0x0735, OK, "SiS", "735", enable_flash_sis540}, -+ {0x1039, 0x0740, NT, "SiS", "740", enable_flash_sis540}, -+ {0x1039, 0x0745, NT, "SiS", "745", enable_flash_sis540}, -+ {0x1039, 0x0746, NT, "SiS", "746", enable_flash_sis540}, -+ {0x1039, 0x0748, NT, "SiS", "748", enable_flash_sis540}, -+ {0x1039, 0x0755, NT, "SiS", "755", enable_flash_sis540}, - {0x1106, 0x8324, OK, "VIA", "CX700", enable_flash_vt823x}, - {0x1106, 0x8231, NT, "VIA", "VT8231", enable_flash_vt823x}, - {0x1106, 0x3074, NT, "VIA", "VT8233", enable_flash_vt823x}, -+ {0x1106, 0x3147, OK, "VIA", "VT8233A", enable_flash_vt823x}, - {0x1106, 0x3177, OK, "VIA", "VT8235", enable_flash_vt823x}, - {0x1106, 0x3227, OK, "VIA", "VT8237", enable_flash_vt823x}, - {0x1106, 0x3337, OK, "VIA", "VT8237A", enable_flash_vt823x}, - {0x1106, 0x3372, OK, "VIA", "VT8237S", enable_flash_vt8237s_spi}, - {0x1106, 0x8353, OK, "VIA", "VX800", enable_flash_vt8237s_spi}, -+ {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_amd8111}, - {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_amd8111}, - {0x1106, 0x0686, NT, "VIA", "VT82C686A/B", enable_flash_amd8111}, - -diff --git a/cli_classic.c b/cli_classic.c -new file mode 100644 -index 0000000..6cb0578 ---- /dev/null -+++ b/cli_classic.c -@@ -0,0 +1,386 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2000 Silicon Integrated System Corporation -+ * Copyright (C) 2004 Tyan Corp -+ * Copyright (C) 2005-2008 coresystems GmbH -+ * Copyright (C) 2008,2009,2010 Carl-Daniel Hailfinger -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "flash.h" -+#include "flashchips.h" -+ -+void cli_classic_usage(const char *name) -+{ -+ const char *pname; -+ int pnamelen; -+ int remaining = 0; -+ enum programmer p; -+ -+ printf("Usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n" -+ " [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name); -+ -+ printf("Please note that the command line interface for flashrom will " -+ "change before\nflashrom 1.0. Do not use flashrom in scripts " -+ "or other automated tools without\nchecking that your flashrom" -+ " version won't interpret options in a different way.\n\n"); -+ -+ printf -+ (" -r | --read: read flash and save into file\n" -+ " -w | --write: write file into flash\n" -+ " -v | --verify: verify flash against file\n" -+ " -n | --noverify: don't verify flash against file\n" -+ " -E | --erase: erase flash device\n" -+ " -V | --verbose: more verbose output\n" -+ " -c | --chip : probe only for specified flash chip\n" -+#if INTERNAL_SUPPORT == 1 -+ " -m | --mainboard <[vendor:]part>: override mainboard settings\n" -+#endif -+ " -f | --force: force write without checking image\n" -+ " -l | --layout : read ROM layout from file\n" -+ " -i | --image : only flash image name from flash layout\n" -+ " -L | --list-supported: print supported devices\n" -+#if PRINT_WIKI_SUPPORT == 1 -+ " -z | --list-supported-wiki: print supported devices in wiki syntax\n" -+#endif -+ " -p | --programmer : specify the programmer device"); -+ -+ for (p = 0; p < PROGRAMMER_INVALID; p++) { -+ pname = programmer_table[p].name; -+ pnamelen = strlen(pname); -+ if (remaining - pnamelen - 2 < 0) { -+ printf("\n "); -+ remaining = 43; -+ } else { -+ printf(" "); -+ remaining--; -+ } -+ if (p == 0) { -+ printf("("); -+ remaining--; -+ } -+ printf("%s", pname); -+ remaining -= pnamelen; -+ if (p < PROGRAMMER_INVALID - 1) { -+ printf(","); -+ remaining--; -+ } else { -+ printf(")\n"); -+ } -+ } -+ -+ printf( -+ " -h | --help: print this help text\n" -+ " -R | --version: print the version (release)\n" -+ "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n" -+ "specified, then all that happens is that flash info is dumped.\n\n"); -+ exit(1); -+} -+ -+int cli_classic(int argc, char *argv[]) -+{ -+ unsigned long size; -+ /* Probe for up to three flash chips. */ -+ struct flashchip *flash, *flashes[3]; -+ const char *name; -+ int namelen; -+ int opt; -+ int option_index = 0; -+ int force = 0; -+ int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; -+ int dont_verify_it = 0, list_supported = 0; -+#if PRINT_WIKI_SUPPORT == 1 -+ int list_supported_wiki = 0; -+#endif -+ int operation_specified = 0; -+ int i; -+ -+#if PRINT_WIKI_SUPPORT == 1 -+ const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh"; -+#else -+ const char *optstring = "rRwvnVEfc:m:l:i:p:Lh"; -+#endif -+ static struct option long_options[] = { -+ {"read", 0, 0, 'r'}, -+ {"write", 0, 0, 'w'}, -+ {"erase", 0, 0, 'E'}, -+ {"verify", 0, 0, 'v'}, -+ {"noverify", 0, 0, 'n'}, -+ {"chip", 1, 0, 'c'}, -+ {"mainboard", 1, 0, 'm'}, -+ {"verbose", 0, 0, 'V'}, -+ {"force", 0, 0, 'f'}, -+ {"layout", 1, 0, 'l'}, -+ {"image", 1, 0, 'i'}, -+ {"list-supported", 0, 0, 'L'}, -+#if PRINT_WIKI_SUPPORT == 1 -+ {"list-supported-wiki", 0, 0, 'z'}, -+#endif -+ {"programmer", 1, 0, 'p'}, -+ {"help", 0, 0, 'h'}, -+ {"version", 0, 0, 'R'}, -+ {0, 0, 0, 0} -+ }; -+ -+ char *filename = NULL; -+ -+ char *tempstr = NULL; -+ -+ print_version(); -+ -+ if (argc > 1) { -+ /* Yes, print them. */ -+ printf_debug("The arguments are:\n"); -+ for (i = 1; i < argc; ++i) -+ printf_debug("%s\n", argv[i]); -+ } -+ -+ if (selfcheck()) -+ exit(1); -+ -+ setbuf(stdout, NULL); -+ while ((opt = getopt_long(argc, argv, optstring, -+ long_options, &option_index)) != EOF) { -+ switch (opt) { -+ case 'r': -+ if (++operation_specified > 1) { -+ fprintf(stderr, "More than one operation " -+ "specified. Aborting.\n"); -+ exit(1); -+ } -+ read_it = 1; -+ break; -+ case 'w': -+ if (++operation_specified > 1) { -+ fprintf(stderr, "More than one operation " -+ "specified. Aborting.\n"); -+ exit(1); -+ } -+ write_it = 1; -+ break; -+ case 'v': -+ //FIXME: gracefully handle superfluous -v -+ if (++operation_specified > 1) { -+ fprintf(stderr, "More than one operation " -+ "specified. Aborting.\n"); -+ exit(1); -+ } -+ if (dont_verify_it) { -+ fprintf(stderr, "--verify and --noverify are" -+ "mutually exclusive. Aborting.\n"); -+ exit(1); -+ } -+ verify_it = 1; -+ break; -+ case 'n': -+ if (verify_it) { -+ fprintf(stderr, "--verify and --noverify are" -+ "mutually exclusive. Aborting.\n"); -+ exit(1); -+ } -+ dont_verify_it = 1; -+ break; -+ case 'c': -+ chip_to_probe = strdup(optarg); -+ break; -+ case 'V': -+ verbose++; -+ break; -+ case 'E': -+ if (++operation_specified > 1) { -+ fprintf(stderr, "More than one operation " -+ "specified. Aborting.\n"); -+ exit(1); -+ } -+ erase_it = 1; -+ break; -+#if INTERNAL_SUPPORT == 1 -+ case 'm': -+ tempstr = strdup(optarg); -+ lb_vendor_dev_from_string(tempstr); -+ break; -+#endif -+ case 'f': -+ force = 1; -+ break; -+ case 'l': -+ tempstr = strdup(optarg); -+ if (read_romlayout(tempstr)) -+ exit(1); -+ break; -+ case 'i': -+ tempstr = strdup(optarg); -+ find_romentry(tempstr); -+ break; -+ case 'L': -+ list_supported = 1; -+ break; -+#if PRINT_WIKI_SUPPORT == 1 -+ case 'z': -+ list_supported_wiki = 1; -+ break; -+#endif -+ case 'p': -+ for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) { -+ name = programmer_table[programmer].name; -+ namelen = strlen(name); -+ if (strncmp(optarg, name, namelen) == 0) { -+ switch (optarg[namelen]) { -+ case ':': -+ programmer_param = strdup(optarg + namelen + 1); -+ break; -+ case '\0': -+ break; -+ default: -+ /* The continue refers to the -+ * for loop. It is here to be -+ * able to differentiate between -+ * foo and foobar. -+ */ -+ continue; -+ } -+ break; -+ } -+ } -+ if (programmer == PROGRAMMER_INVALID) { -+ printf("Error: Unknown programmer %s.\n", optarg); -+ exit(1); -+ } -+ break; -+ case 'R': -+ /* print_version() is always called during startup. */ -+ exit(0); -+ break; -+ case 'h': -+ default: -+ cli_classic_usage(argv[0]); -+ break; -+ } -+ } -+ -+ if (list_supported) { -+ print_supported(); -+ exit(0); -+ } -+ -+#if PRINT_WIKI_SUPPORT == 1 -+ if (list_supported_wiki) { -+ print_supported_wiki(); -+ exit(0); -+ } -+#endif -+ -+ if (read_it && write_it) { -+ printf("Error: -r and -w are mutually exclusive.\n"); -+ cli_classic_usage(argv[0]); -+ } -+ -+ if (optind < argc) -+ filename = argv[optind++]; -+ -+ if (optind < argc) { -+ printf("Error: Extra parameter found.\n"); -+ cli_classic_usage(argv[0]); -+ } -+ -+ if (programmer_init()) { -+ fprintf(stderr, "Error: Programmer initialization failed.\n"); -+ exit(1); -+ } -+ -+ // FIXME: Delay calibration should happen in programmer code. -+ myusec_calibrate_delay(); -+ -+ for (i = 0; i < ARRAY_SIZE(flashes); i++) { -+ flashes[i] = -+ probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0); -+ if (!flashes[i]) -+ for (i++; i < ARRAY_SIZE(flashes); i++) -+ flashes[i] = NULL; -+ } -+ -+ if (flashes[1]) { -+ printf("Multiple flash chips were detected:"); -+ for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++) -+ printf(" %s", flashes[i]->name); -+ printf("\nPlease specify which chip to use with the -c option.\n"); -+ programmer_shutdown(); -+ exit(1); -+ } else if (!flashes[0]) { -+ printf("No EEPROM/flash device found.\n"); -+ if (!force || !chip_to_probe) { -+ printf("If you know which flash chip you have, and if this version of flashrom\n"); -+ printf("supports a similar flash chip, you can try to force read your chip. Run:\n"); -+ printf("flashrom -f -r -c similar_supported_flash_chip filename\n"); -+ printf("\n"); -+ printf("Note: flashrom can never write when the flash chip isn't found automatically.\n"); -+ } -+ if (force && read_it && chip_to_probe) { -+ printf("Force read (-f -r -c) requested, forcing chip probe success:\n"); -+ flashes[0] = probe_flash(flashchips, 1); -+ if (!flashes[0]) { -+ printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe); -+ printf("Run flashrom -L to view the hardware supported in this flashrom version.\n"); -+ exit(1); -+ } -+ printf("Please note that forced reads most likely contain garbage.\n"); -+ return read_flash(flashes[0], filename); -+ } -+ // FIXME: flash writes stay enabled! -+ programmer_shutdown(); -+ exit(1); -+ } -+ -+ flash = flashes[0]; -+ -+ check_chip_supported(flash); -+ -+ size = flash->total_size * 1024; -+ if (check_max_decode((buses_supported & flash->bustype), size) && -+ (!force)) { -+ fprintf(stderr, "Chip is too big for this programmer " -+ "(-V gives details). Use --force to override.\n"); -+ programmer_shutdown(); -+ return 1; -+ } -+ -+ if (!(read_it | write_it | verify_it | erase_it)) { -+ printf("No operations were specified.\n"); -+ // FIXME: flash writes stay enabled! -+ programmer_shutdown(); -+ exit(1); -+ } -+ -+ if (!filename && !erase_it) { -+ printf("Error: No filename specified.\n"); -+ // FIXME: flash writes stay enabled! -+ programmer_shutdown(); -+ exit(1); -+ } -+ -+ /* Always verify write operations unless -n is used. */ -+ if (write_it && !dont_verify_it) -+ verify_it = 1; -+ -+ return doit(flash, force, filename, read_it, write_it, erase_it, verify_it); -+} -diff --git a/cli_output.c b/cli_output.c -new file mode 100644 -index 0000000..b3d4e04 ---- /dev/null -+++ b/cli_output.c -@@ -0,0 +1,51 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Sean Nelson -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include "flash.h" -+ -+int print(int type, const char *fmt, ...) -+{ -+ va_list ap; -+ int ret; -+ FILE *output_type; -+ -+ switch (type) { -+ case MSG_ERROR: -+ output_type = stderr; -+ break; -+ case MSG_BARF: -+ if (verbose < 2) -+ return 0; -+ case MSG_DEBUG: -+ if (verbose < 1) -+ return 0; -+ case MSG_INFO: -+ default: -+ output_type = stdout; -+ break; -+ } -+ -+ va_start(ap, fmt); -+ ret = vfprintf(output_type, fmt, ap); -+ va_end(ap); -+ return ret; -+} -diff --git a/coreboot_tables.h b/coreboot_tables.h -index 6944559..2e96526 100644 ---- a/coreboot_tables.h -+++ b/coreboot_tables.h -@@ -27,11 +27,11 @@ - /* The coreboot table information is for conveying information - * from the firmware to the loaded OS image. Primarily this - * is expected to be information that cannot be discovered by -- * other means, such as quering the hardware directly. -+ * other means, such as querying the hardware directly. - * - * All of the information should be Position Independent Data. - * That is it should be safe to relocated any of the information -- * without it's meaning/correctnes changing. For table that -+ * without it's meaning/correctness changing. For table that - * can reasonably be used on multiple architectures the data - * size should be fixed. This should ease the transition between - * 32 bit and 64 bit architectures etc. -@@ -48,7 +48,7 @@ - * table entry is required or not. This should remove much of the - * long term compatibility burden as table entries which are - * irrelevant or have been replaced by better alternatives may be -- * dropped. Of course it is polite and expidite to include extra -+ * dropped. Of course it is polite and expedite to include extra - * table entries and be backwards compatible, but it is not required. - */ - -@@ -78,10 +78,10 @@ struct lb_header { - uint32_t table_entries; - }; - --/* Every entry in the boot enviroment list will correspond to a boot -+/* Every entry in the boot environment list will correspond to a boot - * info record. Encoding both type and size. The type is obviously - * so you can tell what it is. The size allows you to skip that -- * boot enviroment record if you don't know what it easy. This allows -+ * boot environment record if you don't know what it easy. This allows - * forward compatibility with records not yet defined. - */ - struct lb_record { -diff --git a/dediprog.c b/dediprog.c -new file mode 100644 -index 0000000..2d0d060 ---- /dev/null -+++ b/dediprog.c -@@ -0,0 +1,395 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2010 Carl-Daniel Hailfinger -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include "flash.h" -+#include "chipdrivers.h" -+#include "spi.h" -+ -+#define DEFAULT_TIMEOUT 3000 -+usb_dev_handle *dediprog_handle; -+ -+int dediprog_do_stuff(void); -+ -+void print_hex(void *buf, size_t len) -+{ -+ size_t i; -+ -+ for (i = 0; i < len; i++) -+ msg_pdbg(" %02x", ((uint8_t *)buf)[i]); -+} -+ -+struct usb_device *get_device_by_vid_pid(uint16_t vid, uint16_t pid) -+{ -+ struct usb_bus *bus; -+ struct usb_device *dev; -+ -+ for (bus = usb_get_busses(); bus; bus = bus->next) -+ for (dev = bus->devices; dev; dev = dev->next) -+ if ((dev->descriptor.idVendor == vid) && -+ (dev->descriptor.idProduct == pid)) -+ return dev; -+ -+ return NULL; -+} -+ -+//int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout); -+ -+int dediprog_set_spi_voltage(uint16_t voltage) -+{ -+ int ret; -+ unsigned int mv; -+ -+ switch (voltage) { -+ case 0x0: -+ /* Admittedly this one is an assumption. */ -+ mv = 0; -+ break; -+ case 0x12: -+ mv = 1800; -+ break; -+ case 0x11: -+ mv = 2500; -+ break; -+ case 0x10: -+ mv = 3500; -+ break; -+ default: -+ msg_perr("Unknown voltage selector 0x%x! Aborting.\n", voltage); -+ return 1; -+ } -+ msg_pdbg("Setting SPI voltage to %u.%03u V\n", mv / 1000, mv % 1000); -+ -+ ret = usb_control_msg(dediprog_handle, 0x42, 0x9, voltage, 0xff, NULL, 0x0, DEFAULT_TIMEOUT); -+ if (ret != 0x0) { -+ msg_perr("Command Set SPI Voltage 0x%x failed!\n", voltage); -+ return 1; -+ } -+ return 0; -+} -+ -+/* After dediprog_set_spi_speed, the original app always calls -+ * dediprog_set_spi_voltage(0) and then -+ * dediprog_check_devicestring() four times in a row. -+ * After that, dediprog_command_a() is called. -+ * This looks suspiciously like the microprocessor in the SF100 has to be -+ * restarted/reinitialized in case the speed changes. -+ */ -+int dediprog_set_spi_speed(uint16_t speed) -+{ -+ int ret; -+ unsigned int khz; -+ -+ /* Case 1 and 2 are in weird order. Probably an organically "grown" -+ * interface. -+ * Base frequency is 24000 kHz, divisors are (in order) -+ * 1, 3, 2, 8, 11, 16, 32, 64. -+ */ -+ switch (speed) { -+ case 0x0: -+ khz = 24000; -+ break; -+ case 0x1: -+ khz = 8000; -+ break; -+ case 0x2: -+ khz = 12000; -+ break; -+ case 0x3: -+ khz = 3000; -+ break; -+ case 0x4: -+ khz = 2180; -+ break; -+ case 0x5: -+ khz = 1500; -+ break; -+ case 0x6: -+ khz = 750; -+ break; -+ case 0x7: -+ khz = 375; -+ break; -+ default: -+ msg_perr("Unknown frequency selector 0x%x! Aborting.\n", speed); -+ return 1; -+ } -+ msg_pdbg("Setting SPI speed to %u kHz\n", khz); -+ -+ ret = usb_control_msg(dediprog_handle, 0x42, 0x61, speed, 0xff, NULL, 0x0, DEFAULT_TIMEOUT); -+ if (ret != 0x0) { -+ msg_perr("Command Set SPI Speed 0x%x failed!\n", speed); -+ return 1; -+ } -+ return 0; -+} -+ -+int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -+{ -+ msg_pspew("%s, start=0x%x, len=0x%x\n", __func__, start, len); -+ /* Chosen read length is 16 bytes for now. */ -+ return spi_read_chunked(flash, buf, start, len, 16); -+} -+ -+int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, -+ const unsigned char *writearr, unsigned char *readarr) -+{ -+ int ret; -+ -+ msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt); -+ /* Paranoid, but I don't want to be blamed if anything explodes. */ -+ if (writecnt > 5) { -+ msg_perr("Untested writecnt=%i, aborting.\n", writecnt); -+ return 1; -+ } -+ /* 16 byte reads should work. */ -+ if (readcnt > 16) { -+ msg_perr("Untested readcnt=%i, aborting.\n", readcnt); -+ return 1; -+ } -+ -+ ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0xff, readcnt ? 0x1 : 0x0, (char *)writearr, writecnt, DEFAULT_TIMEOUT); -+ if (ret != writecnt) { -+ msg_perr("Send SPI failed, expected %i, got %i %s!\n", -+ writecnt, ret, usb_strerror()); -+ return 1; -+ } -+ if (!readcnt) -+ return 0; -+ memset(readarr, 0, readcnt); -+ ret = usb_control_msg(dediprog_handle, 0xc2, 0x01, 0xbb8, 0x0000, (char *)readarr, readcnt, DEFAULT_TIMEOUT); -+ if (ret != readcnt) { -+ msg_perr("Receive SPI failed, expected %i, got %i %s!\n", -+ readcnt, ret, usb_strerror()); -+ return 1; -+ } -+ return 0; -+} -+ -+int dediprog_check_devicestring(void) -+{ -+ int ret; -+ char buf[0x11]; -+ -+ /* Command Prepare Receive Device String. */ -+ memset(buf, 0, sizeof(buf)); -+ ret = usb_control_msg(dediprog_handle, 0xc3, 0x7, 0x0, 0xef03, buf, 0x1, DEFAULT_TIMEOUT); -+ /* The char casting is needed to stop gcc complaining about an always true comparison. */ -+ if ((ret != 0x1) || (buf[0] != (char)0xff)) { -+ msg_perr("Unexpected response to Command Prepare Receive Device" -+ " String!\n"); -+ return 1; -+ } -+ /* Command Receive Device String. */ -+ memset(buf, 0, sizeof(buf)); -+ ret = usb_control_msg(dediprog_handle, 0xc2, 0x8, 0xff, 0xff, buf, 0x10, DEFAULT_TIMEOUT); -+ if (ret != 0x10) { -+ msg_perr("Incomplete/failed Command Receive Device String!\n"); -+ return 1; -+ } -+ buf[0x10] = '\0'; -+ msg_pdbg("Found a %s\n", buf); -+ if (memcmp(buf, "SF100", 0x5)) { -+ msg_perr("Device not a SF100!\n"); -+ return 1; -+ } -+ /* Only these versions were tested. */ -+ if (memcmp(buf, "SF100 V:2.1.1 ", 0x10) && -+ memcmp(buf, "SF100 V:3.1.8 ", 0x10)) { -+ msg_perr("Unexpected firmware version!\n"); -+ return 1; -+ } -+ return 0; -+} -+ -+/* Command A seems to be some sort of device init. It is either followed by -+ * dediprog_check_devicestring (often) or Command A (often) or -+ * Command F (once). -+ */ -+int dediprog_command_a(void) -+{ -+ int ret; -+ char buf[0x1]; -+ -+ memset(buf, 0, sizeof(buf)); -+ ret = usb_control_msg(dediprog_handle, 0xc3, 0xb, 0x0, 0x0, buf, 0x1, DEFAULT_TIMEOUT); -+ if ((ret != 0x1) || (buf[0] != 0x6f)) { -+ msg_perr("Unexpected response to Command A!\n"); -+ return 1; -+ } -+ return 0; -+} -+ -+/* Command C is only sent after dediprog_check_devicestring, but not after every -+ * invocation of dediprog_check_devicestring. It is only sent after the first -+ * dediprog_command_a(); dediprog_check_devicestring() sequence in each session. -+ * I'm tempted to call this one start_SPI_engine or finish_init. -+ */ -+int dediprog_command_c(void) -+{ -+ int ret; -+ -+ ret = usb_control_msg(dediprog_handle, 0x42, 0x4, 0x0, 0x0, NULL, 0x0, DEFAULT_TIMEOUT); -+ if (ret != 0x0) { -+ msg_perr("Unexpected response to Command C!\n"); -+ return 1; -+ } -+ return 0; -+} -+ -+/* Very strange. Seems to be a programmer keepalive or somesuch. -+ * Wait unsuccessfully for timeout ms to read one byte. -+ * Is usually called after setting voltage to 0. -+ */ -+int dediprog_command_f(int timeout) -+{ -+ int ret; -+ char buf[0x1]; -+ -+ memset(buf, 0, sizeof(buf)); -+ ret = usb_control_msg(dediprog_handle, 0xc2, 0x11, 0xff, 0xff, buf, 0x1, timeout); -+ if (ret != 0x0) { -+ msg_perr("Unexpected response to Command F!\n"); -+ return 1; -+ } -+ return 0; -+} -+ -+/* URB numbers refer to the first log ever captured. */ -+int dediprog_init(void) -+{ -+ struct usb_device *dev; -+ -+ msg_pspew("%s\n", __func__); -+ -+ /* Here comes the USB stuff. */ -+ usb_init(); -+ usb_find_busses(); -+ usb_find_devices(); -+ dev = get_device_by_vid_pid(0x0483, 0xdada); -+ if (!dev) { -+ msg_perr("Could not find a Dediprog SF100 on USB!\n"); -+ return 1; -+ } -+ msg_pdbg("Found USB device (%04x:%04x).\n", -+ dev->descriptor.idVendor, -+ dev->descriptor.idProduct); -+ dediprog_handle = usb_open(dev); -+ usb_set_configuration(dediprog_handle, 1); -+ usb_claim_interface(dediprog_handle, 0); -+ /* URB 6. Command A. */ -+ if (dediprog_command_a()) -+ return 1; -+ /* URB 7. Command A. */ -+ if (dediprog_command_a()) -+ return 1; -+ /* URB 8. Command Prepare Receive Device String. */ -+ /* URB 9. Command Receive Device String. */ -+ if (dediprog_check_devicestring()) -+ return 1; -+ /* URB 10. Command C. */ -+ if (dediprog_command_c()) -+ return 1; -+ /* URB 11. Command Set SPI Voltage. */ -+ if (dediprog_set_spi_voltage(0x10)) -+ return 1; -+ -+ buses_supported = CHIP_BUSTYPE_SPI; -+ spi_controller = SPI_CONTROLLER_DEDIPROG; -+ -+ /* RE leftover, leave in until the driver is complete. */ -+#if 0 -+ /* Execute RDID by hand if you want to test it. */ -+ dediprog_do_stuff(); -+#endif -+ -+ return 0; -+} -+ -+/* Leftovers from reverse engineering. Keep for documentation purposes until -+ * completely understood. -+ */ -+int dediprog_do_stuff(void) -+{ -+ char buf[0x4]; -+ /* SPI command processing starts here. */ -+ -+ /* URB 12. Command Send SPI. */ -+ /* URB 13. Command Receive SPI. */ -+ memset(buf, 0, sizeof(buf)); -+ /* JEDEC RDID */ -+ msg_pdbg("Sending RDID\n"); -+ buf[0] = JEDEC_RDID; -+ if (dediprog_spi_send_command(JEDEC_RDID_OUTSIZE, JEDEC_RDID_INSIZE, (unsigned char *)buf, (unsigned char *)buf)) -+ return 1; -+ msg_pdbg("Receiving response: "); -+ print_hex(buf, JEDEC_RDID_INSIZE); -+#if 0 -+ /* URB 14-27 are more SPI commands. */ -+ /* URB 28. Command Set SPI Voltage. */ -+ if (dediprog_set_spi_voltage(0x0)) -+ return 1; -+ /* URB 29-38. Command F, unsuccessful wait. */ -+ if (dediprog_command_f(544)) -+ return 1; -+ /* URB 39. Command Set SPI Voltage. */ -+ if (dediprog_set_spi_voltage(0x10)) -+ return 1; -+ /* URB 40. Command Set SPI Speed. */ -+ if (dediprog_set_spi_speed(0x2)) -+ return 1; -+ /* URB 41 is just URB 28. */ -+ /* URB 42,44,46,48,51,53 is just URB 8. */ -+ /* URB 43,45,47,49,52,54 is just URB 9. */ -+ /* URB 50 is just URB 6/7. */ -+ /* URB 55-131 is just URB 29-38. (wait unsuccessfully for 4695 (maybe 4751) ms)*/ -+ /* URB 132,134 is just URB 6/7. */ -+ /* URB 133 is just URB 29-38. */ -+ /* URB 135 is just URB 8. */ -+ /* URB 136 is just URB 9. */ -+ /* URB 137 is just URB 11. */ -+ -+ /* Command I is probably Start Bulk Read. Data is u16 blockcount, u16 blocksize. */ -+ /* Command J is probably Start Bulk Write. Data is u16 blockcount, u16 blocksize. */ -+ /* Bulk transfer sizes for Command I/J are always 512 bytes, rest is filled with 0xff. */ -+#endif -+ -+ msg_pinfo("All probes will fail because this driver is not hooked up " -+ "to the SPI infrastructure yet."); -+ return 0; -+} -+ -+int dediprog_shutdown(void) -+{ -+ msg_pspew("%s\n", __func__); -+ -+ /* URB 28. Command Set SPI Voltage to 0. */ -+ if (dediprog_set_spi_voltage(0x0)) -+ return 1; -+ -+ if (usb_close(dediprog_handle)) { -+ msg_perr("Couldn't close USB device!\n"); -+ return 1; -+ } -+ return 0; -+} -diff --git a/dmi.c b/dmi.c -new file mode 100644 -index 0000000..d9f307f ---- /dev/null -+++ b/dmi.c -@@ -0,0 +1,172 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009,2010 Michael Karcher -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+ -+#include "flash.h" -+ -+const char *dmidecode_names[] = { -+ "system-manufacturer", -+ "system-product-name", -+ "system-version", -+ "baseboard-manufacturer", -+ "baseboard-product-name", -+ "baseboard-version", -+}; -+ -+#define DMI_COMMAND_LEN_MAX 260 -+const char *dmidecode_command = "dmidecode"; -+ -+int has_dmi_support = 0; -+char *dmistrings[ARRAY_SIZE(dmidecode_names)]; -+ -+/* Strings longer than 4096 in DMI are just insane. */ -+#define DMI_MAX_ANSWER_LEN 4096 -+ -+static char *get_dmi_string(const char *string_name) -+{ -+ FILE *dmidecode_pipe; -+ char *result; -+ char answerbuf[DMI_MAX_ANSWER_LEN]; -+ char commandline[DMI_COMMAND_LEN_MAX + 40]; -+ -+ snprintf(commandline, sizeof(commandline), -+ "%s -s %s", dmidecode_command, string_name); -+ dmidecode_pipe = popen(commandline, "r"); -+ if (!dmidecode_pipe) { -+ printf_debug("DMI pipe open error\n"); -+ return NULL; -+ } -+ if (!fgets(answerbuf, DMI_MAX_ANSWER_LEN, dmidecode_pipe)) { -+ if(ferror(dmidecode_pipe)) { -+ printf_debug("DMI pipe read error\n"); -+ pclose(dmidecode_pipe); -+ return NULL; -+ } else { -+ answerbuf[0] = 0; /* Hit EOF */ -+ } -+ } -+ /* Toss all output above DMI_MAX_ANSWER_LEN away to prevent -+ deadlock on pclose. */ -+ while (!feof(dmidecode_pipe)) -+ getc(dmidecode_pipe); -+ if (pclose(dmidecode_pipe) != 0) { -+ printf_debug("DMI pipe close error\n"); -+ return NULL; -+ } -+ -+ /* Chomp trailing newline. */ -+ if (answerbuf[0] != 0 && -+ answerbuf[strlen(answerbuf) - 1] == '\n') -+ answerbuf[strlen(answerbuf) - 1] = 0; -+ printf_debug("DMI string %s: \"%s\"\n", string_name, answerbuf); -+ -+ result = strdup(answerbuf); -+ if (!result) -+ puts("WARNING: Out of memory - DMI support fails"); -+ -+ return result; -+} -+ -+void dmi_init(void) -+{ -+ int i; -+ char *chassis_type; -+ -+ has_dmi_support = 1; -+ for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) { -+ dmistrings[i] = get_dmi_string(dmidecode_names[i]); -+ if (!dmistrings[i]) { -+ has_dmi_support = 0; -+ return; -+ } -+ } -+ -+ chassis_type = get_dmi_string("chassis-type"); -+ if (chassis_type && !strcmp(chassis_type, "Notebook")) { -+ printf_debug("Laptop detected via DMI\n"); -+ is_laptop = 1; -+ } -+ free(chassis_type); -+} -+ -+/** -+ * Does an substring/prefix/postfix/whole-string match. -+ * -+ * The pattern is matched as-is. The only metacharacters supported are '^' -+ * at the beginning and '$' at the end. So you can look for "^prefix", -+ * "suffix$", "substring" or "^complete string$". -+ * -+ * @param value The string to check. -+ * @param pattern The pattern. -+ * @return Nonzero if pattern matches. -+ */ -+static int dmi_compare(const char *value, const char *pattern) -+{ -+ int anchored = 0; -+ int patternlen; -+ -+ printf_debug("matching %s against %s\n", value, pattern); -+ /* The empty string is part of all strings! */ -+ if (pattern[0] == 0) -+ return 1; -+ -+ if (pattern[0] == '^') { -+ anchored = 1; -+ pattern++; -+ } -+ -+ patternlen = strlen(pattern); -+ if (pattern[patternlen - 1] == '$') { -+ int valuelen = strlen(value); -+ patternlen--; -+ if (patternlen > valuelen) -+ return 0; -+ -+ /* full string match: require same length */ -+ if (anchored && (valuelen != patternlen)) -+ return 0; -+ -+ /* start character to make ends match */ -+ value += valuelen - patternlen; -+ anchored = 1; -+ } -+ -+ if (anchored) -+ return strncmp(value, pattern, patternlen) == 0; -+ else -+ return strstr(value, pattern) != NULL; -+} -+ -+int dmi_match(const char *pattern) -+{ -+ int i; -+ -+ if (!has_dmi_support) -+ return 0; -+ -+ for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) -+ if (dmi_compare(dmistrings[i], pattern)) -+ return 1; -+ -+ return 0; -+} -diff --git a/drkaiser.c b/drkaiser.c -new file mode 100644 -index 0000000..572fee3 ---- /dev/null -+++ b/drkaiser.c -@@ -0,0 +1,79 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Joerg Fischer -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include "flash.h" -+ -+#define PCI_VENDOR_ID_DRKAISER 0x1803 -+ -+#define PCI_MAGIC_DRKAISER_ADDR 0x50 -+#define PCI_MAGIC_DRKAISER_VALUE 0xa971 -+ -+struct pcidev_status drkaiser_pcidev[] = { -+ {0x1803, 0x5057, OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"}, -+ {}, -+}; -+ -+uint8_t *drkaiser_bar; -+ -+int drkaiser_init(void) -+{ -+ uint32_t addr; -+ -+ get_io_perms(); -+ pcidev_init(PCI_VENDOR_ID_DRKAISER, PCI_BASE_ADDRESS_2, -+ drkaiser_pcidev, programmer_param); -+ -+ /* Write magic register to enable flash write. */ -+ pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, -+ PCI_MAGIC_DRKAISER_VALUE); -+ -+ /* TODO: Mask lower bits? How many? 3? 7? */ -+ addr = pci_read_long(pcidev_dev, PCI_BASE_ADDRESS_2) & ~0x03; -+ -+ /* Map 128KB flash memory window. */ -+ drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", -+ addr, 128 * 1024); -+ -+ buses_supported = CHIP_BUSTYPE_PARALLEL; -+ return 0; -+} -+ -+int drkaiser_shutdown(void) -+{ -+ /* Write protect the flash again. */ -+ pci_write_word(pcidev_dev, PCI_MAGIC_DRKAISER_ADDR, 0); -+ free(programmer_param); -+ pci_cleanup(pacc); -+ release_io_perms(); -+ return 0; -+}; -+ -+void drkaiser_chip_writeb(uint8_t val, chipaddr addr) -+{ -+ mmio_writeb(val, drkaiser_bar + addr); -+} -+ -+uint8_t drkaiser_chip_readb(const chipaddr addr) -+{ -+ return mmio_readb(drkaiser_bar + addr); -+} -diff --git a/dummyflasher.c b/dummyflasher.c -index 903f88b..8ebd695 100644 ---- a/dummyflasher.c -+++ b/dummyflasher.c -@@ -27,7 +27,7 @@ - int dummy_init(void) - { - int i; -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - - /* "all" is equivalent to specifying no type. */ - if (programmer_param && (!strcmp(programmer_param, "all"))) { -@@ -38,100 +38,101 @@ int dummy_init(void) - programmer_param = strdup("parallel,lpc,fwh,spi"); - /* Convert the parameters to lowercase. */ - for (i = 0; programmer_param[i] != '\0'; i++) -- programmer_param[i] = (char)tolower(programmer_param[i]); -+ programmer_param[i] = -+ (char)tolower((unsigned char)programmer_param[i]); - - buses_supported = CHIP_BUSTYPE_NONE; - if (strstr(programmer_param, "parallel")) { - buses_supported |= CHIP_BUSTYPE_PARALLEL; -- printf_debug("Enabling support for %s flash.\n", "parallel"); -+ msg_pdbg("Enabling support for %s flash.\n", "parallel"); - } - if (strstr(programmer_param, "lpc")) { - buses_supported |= CHIP_BUSTYPE_LPC; -- printf_debug("Enabling support for %s flash.\n", "LPC"); -+ msg_pdbg("Enabling support for %s flash.\n", "LPC"); - } - if (strstr(programmer_param, "fwh")) { - buses_supported |= CHIP_BUSTYPE_FWH; -- printf_debug("Enabling support for %s flash.\n", "FWH"); -+ msg_pdbg("Enabling support for %s flash.\n", "FWH"); - } - if (strstr(programmer_param, "spi")) { - buses_supported |= CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_DUMMY; -- printf_debug("Enabling support for %s flash.\n", "SPI"); -+ msg_pdbg("Enabling support for %s flash.\n", "SPI"); - } - if (buses_supported == CHIP_BUSTYPE_NONE) -- printf_debug("Support for all flash bus types disabled.\n"); -+ msg_pdbg("Support for all flash bus types disabled.\n"); - free(programmer_param); - return 0; - } - - int dummy_shutdown(void) - { -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - return 0; - } - - void *dummy_map(const char *descr, unsigned long phys_addr, size_t len) - { -- printf_debug("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n", -- __func__, descr, (unsigned long)len, phys_addr); -+ msg_pspew("%s: Mapping %s, 0x%lx bytes at 0x%08lx\n", -+ __func__, descr, (unsigned long)len, phys_addr); - return (void *)phys_addr; - } - - void dummy_unmap(void *virt_addr, size_t len) - { -- printf_debug("%s: Unmapping 0x%lx bytes at %p\n", -- __func__, (unsigned long)len, virt_addr); -+ msg_pspew("%s: Unmapping 0x%lx bytes at %p\n", -+ __func__, (unsigned long)len, virt_addr); - } - - void dummy_chip_writeb(uint8_t val, chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val); -+ msg_pspew("%s: addr=0x%lx, val=0x%02x\n", __func__, addr, val); - } - - void dummy_chip_writew(uint16_t val, chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val); -+ msg_pspew("%s: addr=0x%lx, val=0x%04x\n", __func__, addr, val); - } - - void dummy_chip_writel(uint32_t val, chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val); -+ msg_pspew("%s: addr=0x%lx, val=0x%08x\n", __func__, addr, val); - } - - void dummy_chip_writen(uint8_t *buf, chipaddr addr, size_t len) - { - size_t i; -- printf_debug("%s: addr=0x%lx, len=0x%08lx, writing data (hex):", -- __func__, addr, (unsigned long)len); -+ msg_pspew("%s: addr=0x%lx, len=0x%08lx, writing data (hex):", -+ __func__, addr, (unsigned long)len); - for (i = 0; i < len; i++) { - if ((i % 16) == 0) -- printf_debug("\n"); -- printf_debug("%02x ", buf[i]) -+ msg_pspew("\n"); -+ msg_pspew("%02x ", buf[i]); - } - } - - uint8_t dummy_chip_readb(const chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, returning 0xff\n", __func__, addr); -+ msg_pspew("%s: addr=0x%lx, returning 0xff\n", __func__, addr); - return 0xff; - } - - uint16_t dummy_chip_readw(const chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, returning 0xffff\n", __func__, addr); -+ msg_pspew("%s: addr=0x%lx, returning 0xffff\n", __func__, addr); - return 0xffff; - } - - uint32_t dummy_chip_readl(const chipaddr addr) - { -- printf_debug("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr); -+ msg_pspew("%s: addr=0x%lx, returning 0xffffffff\n", __func__, addr); - return 0xffffffff; - } - - void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) - { -- printf_debug("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n", -- __func__, addr, (unsigned long)len); -+ msg_pspew("%s: addr=0x%lx, len=0x%lx, returning array of 0xff\n", -+ __func__, addr, (unsigned long)len); - memset(buf, 0xff, len); - return; - } -@@ -141,18 +142,18 @@ int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, - { - int i; - -- printf_debug("%s:", __func__); -+ msg_pspew("%s:", __func__); - -- printf_debug(" writing %u bytes:", writecnt); -+ msg_pspew(" writing %u bytes:", writecnt); - for (i = 0; i < writecnt; i++) -- printf_debug(" 0x%02x", writearr[i]); -+ msg_pspew(" 0x%02x", writearr[i]); - -- printf_debug(" reading %u bytes:", readcnt); -+ msg_pspew(" reading %u bytes:", readcnt); - for (i = 0; i < readcnt; i++) { -- printf_debug(" 0xff"); -+ msg_pspew(" 0xff"); - readarr[i] = 0xff; - } - -- printf_debug("\n"); -+ msg_pspew("\n"); - return 0; - } -diff --git a/en29f002a.c b/en29f002a.c -deleted file mode 100644 -index b89eb31..0000000 ---- a/en29f002a.c -+++ /dev/null -@@ -1,125 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2007 Carl-Daniel Hailfinger -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --/* -- * EN29F512 has 1C,21 -- * EN29F010 has 1C,20 -- * EN29F040A has 1C,04 -- * EN29LV010 has 1C,6E and uses short F0 reset sequence -- * EN29LV040(A) has 1C,4F and uses short F0 reset sequence -- */ -- --#include "flash.h" -- --int probe_en29f512(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x90, bios + 0x555); -- -- programmer_delay(10); -- -- id1 = chip_readb(bios + 0x100); -- id2 = chip_readb(bios + 0x101); -- -- /* exit by writing F0 anywhere? or the code below */ -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0xF0, bios + 0x555); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- -- if (id1 == flash->manufacture_id && id2 == flash->model_id) -- return 1; -- -- return 0; --} -- --/* -- * EN29F002AT has 1C,92 -- * EN29F002AB has 1C,97 -- */ -- --/* This does not seem to function properly for EN29F002NT. */ --int probe_en29f002a(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0xAAA); -- chip_writeb(0x90, bios + 0x555); -- -- programmer_delay(10); -- -- id1 = chip_readb(bios + 0x100); -- id2 = chip_readb(bios + 0x101); -- -- /* exit by writing F0 anywhere? or the code below */ -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0xAAA); -- chip_writeb(0xF0, bios + 0x555); -- -- printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2); -- -- if (id1 == flash->manufacture_id && id2 == flash->model_id) -- return 1; -- -- return 0; --} -- --/* The EN29F002 chip needs repeated single byte writing, no block writing. */ --int write_en29f002a(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- chipaddr bios = flash->virtual_memory; -- chipaddr dst = bios; -- -- //chip_writeb(0xF0, bios); -- programmer_delay(10); -- if (erase_chip_jedec(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- printf("Programming page: "); -- for (i = 0; i < total_size; i++) { -- /* write to the sector */ -- if ((i & 0xfff) == 0) -- printf("address: 0x%08lx", (unsigned long)i); -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -- chip_writeb(*buf++, dst++); -- -- /* wait for Toggle bit ready */ -- toggle_ready_jedec(dst); -- -- if ((i & 0xfff) == 0) -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- -- printf("\n"); -- return 0; --} -diff --git a/flash.h b/flash.h -index d3e2e30..0a74363 100644 ---- a/flash.h -+++ b/flash.h -@@ -24,74 +24,55 @@ - #ifndef __FLASH_H__ - #define __FLASH_H__ 1 - --#if defined(__GLIBC__) --#include --#endif - #include - #include - #include --#include -- --/* for iopl and outb under Solaris */ --#if defined (__sun) && (defined(__i386) || defined(__amd64)) --#include --#include --#include --#include --#endif -- --#if (defined(__MACH__) && defined(__APPLE__)) --#define __DARWIN__ --#endif -- --#if defined(__FreeBSD__) || defined(__DragonFly__) -- #include -- #define off64_t off_t -- #define lseek64 lseek -- #define OUTB(x, y) do { u_int tmp = (y); outb(tmp, (x)); } while (0) -- #define OUTW(x, y) do { u_int tmp = (y); outw(tmp, (x)); } while (0) -- #define OUTL(x, y) do { u_int tmp = (y); outl(tmp, (x)); } while (0) -- #define INB(x) __extension__ ({ u_int tmp = (x); inb(tmp); }) -- #define INW(x) __extension__ ({ u_int tmp = (x); inw(tmp); }) -- #define INL(x) __extension__ ({ u_int tmp = (x); inl(tmp); }) --#else --#if defined(__DARWIN__) -- #include -- #define off64_t off_t -- #define lseek64 lseek --#endif --#if defined (__sun) && (defined(__i386) || defined(__amd64)) -- /* Note different order for outb */ -- #define OUTB(x,y) outb(y, x) -- #define OUTW(x,y) outw(y, x) -- #define OUTL(x,y) outl(y, x) -- #define INB inb -- #define INW inw -- #define INL inl --#else -- #define OUTB outb -- #define OUTW outw -- #define OUTL outl -- #define INB inb -- #define INW inw -- #define INL inl --#endif -+#include "hwaccess.h" -+#ifdef _WIN32 -+#include -+#undef min -+#undef max - #endif - - typedef unsigned long chipaddr; - - enum programmer { -+#if INTERNAL_SUPPORT == 1 - PROGRAMMER_INTERNAL, -+#endif -+#if DUMMY_SUPPORT == 1 - PROGRAMMER_DUMMY, -+#endif -+#if NIC3COM_SUPPORT == 1 - PROGRAMMER_NIC3COM, -+#endif -+#if GFXNVIDIA_SUPPORT == 1 -+ PROGRAMMER_GFXNVIDIA, -+#endif -+#if DRKAISER_SUPPORT == 1 -+ PROGRAMMER_DRKAISER, -+#endif -+#if SATASII_SUPPORT == 1 - PROGRAMMER_SATASII, -+#endif -+#if ATAHPT_SUPPORT == 1 -+ PROGRAMMER_ATAHPT, -+#endif -+#if INTERNAL_SUPPORT == 1 - PROGRAMMER_IT87SPI, -+#endif - #if FT2232_SPI_SUPPORT == 1 - PROGRAMMER_FT2232SPI, - #endif - #if SERPROG_SUPPORT == 1 - PROGRAMMER_SERPROG, - #endif -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ PROGRAMMER_BUSPIRATESPI, -+#endif -+#if DEDIPROG_SUPPORT == 1 -+ PROGRAMMER_DEDIPROG, -+#endif - PROGRAMMER_INVALID /* This must always be the last entry. */ - }; - -@@ -121,6 +102,8 @@ struct programmer_entry { - - extern const struct programmer_entry programmer_table[]; - -+int register_shutdown(void (*function) (void *data), void *data); -+ - int programmer_init(void); - int programmer_shutdown(void); - void *programmer_map_flash_region(const char *descr, unsigned long phys_addr, -@@ -136,6 +119,21 @@ uint32_t chip_readl(const chipaddr addr); - void chip_readn(uint8_t *buf, const chipaddr addr, size_t len); - void programmer_delay(int usecs); - -+enum bitbang_spi_master { -+ BITBANG_SPI_INVALID /* This must always be the last entry. */ -+}; -+ -+extern const int bitbang_spi_master_count; -+ -+extern enum bitbang_spi_master bitbang_spi_master; -+ -+struct bitbang_spi_master_entry { -+ void (*set_cs) (int val); -+ void (*set_sck) (int val); -+ void (*set_mosi) (int val); -+ int (*get_miso) (void); -+}; -+ - #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - - enum chipbustype { -@@ -148,6 +146,28 @@ enum chipbustype { - CHIP_BUSTYPE_UNKNOWN = CHIP_BUSTYPE_PARALLEL | CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_SPI, - }; - -+/* -+ * How many different contiguous runs of erase blocks with one size each do -+ * we have for a given erase function? -+ */ -+#define NUM_ERASEREGIONS 5 -+ -+/* -+ * How many different erase functions do we have per chip? -+ */ -+#define NUM_ERASEFUNCTIONS 5 -+ -+#define FEATURE_REGISTERMAP (1 << 0) -+#define FEATURE_BYTEWRITES (1 << 1) -+#define FEATURE_LONG_RESET (0 << 4) -+#define FEATURE_SHORT_RESET (1 << 4) -+#define FEATURE_EITHER_RESET FEATURE_LONG_RESET -+#define FEATURE_ADDR_FULL (0 << 2) -+#define FEATURE_ADDR_MASK (3 << 2) -+#define FEATURE_ADDR_2AA (1 << 2) -+#define FEATURE_ADDR_AAA (2 << 2) -+#define FEATURE_ADDR_SHIFTED (1 << 5) -+ - struct flashchip { - const char *vendor; - const char *name; -@@ -164,6 +184,7 @@ struct flashchip { - - int total_size; - int page_size; -+ int feature_bits; - - /* - * Indicate if flashrom has been tested with this flash chip and if -@@ -175,7 +196,21 @@ struct flashchip { - - /* Delay after "enter/exit ID mode" commands in microseconds. */ - int probe_timing; -- int (*erase) (struct flashchip *flash); -+ -+ /* -+ * Erase blocks and associated erase function. Any chip erase function -+ * is stored as chip-sized virtual block together with said function. -+ */ -+ struct block_eraser { -+ struct eraseblock{ -+ unsigned int size; /* Eraseblock size */ -+ unsigned int count; /* Number of contiguous blocks with that size */ -+ } eraseblocks[NUM_ERASEREGIONS]; -+ int (*block_erase) (struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen); -+ } block_erasers[NUM_ERASEFUNCTIONS]; -+ -+ int (*printlock) (struct flashchip *flash); -+ int (*unlock) (struct flashchip *flash); - int (*write) (struct flashchip *flash, uint8_t *buf); - int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len); - -@@ -192,6 +227,7 @@ struct flashchip { - #define TEST_OK_WRITE (1 << 3) - #define TEST_OK_PR (TEST_OK_PROBE | TEST_OK_READ) - #define TEST_OK_PRE (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE) -+#define TEST_OK_PRW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_WRITE) - #define TEST_OK_PREW (TEST_OK_PROBE | TEST_OK_READ | TEST_OK_ERASE | TEST_OK_WRITE) - #define TEST_OK_MASK 0x0f - -@@ -214,6 +250,7 @@ struct flashchip { - - extern struct flashchip flashchips[]; - -+#if INTERNAL_SUPPORT == 1 - struct penable { - uint16_t vendor_id; - uint16_t device_id; -@@ -240,6 +277,9 @@ struct board_pciid_enable { - uint16_t second_card_vendor; - uint16_t second_card_device; - -+ /* Pattern to match DMI entries */ -+ const char *dmi_pattern; -+ - /* The vendor / part name from the coreboot table. */ - const char *lb_vendor; - const char *lb_part; -@@ -247,6 +287,8 @@ struct board_pciid_enable { - const char *vendor_name; - const char *board_name; - -+ int max_rom_decode_parallel; -+ int status; - int (*enable) (const char *name); - }; - -@@ -261,18 +303,18 @@ extern const struct board_info boards_ok[]; - extern const struct board_info boards_bad[]; - extern const struct board_info laptops_ok[]; - extern const struct board_info laptops_bad[]; -+#endif - - /* udelay.c */ - void myusec_delay(int usecs); - void myusec_calibrate_delay(void); -+void internal_delay(int usecs); - -+#if NEED_PCI == 1 - /* pcidev.c */ --#define PCI_OK 0 --#define PCI_NT 1 /* Not tested */ - - extern uint32_t io_base_addr; - extern struct pci_access *pacc; --extern struct pci_filter filter; - extern struct pci_dev *pcidev_dev; - struct pcidev_status { - uint16_t vendor_id; -@@ -281,16 +323,17 @@ struct pcidev_status { - const char *vendor_name; - const char *device_name; - }; --uint32_t pcidev_validate(struct pci_dev *dev, struct pcidev_status *devs); --uint32_t pcidev_init(uint16_t vendor_id, struct pcidev_status *devs, char *pcidev_bdf); -+uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, struct pcidev_status *devs); -+uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, struct pcidev_status *devs, char *pcidev_bdf); -+#endif - - /* print.c */ - char *flashbuses_to_text(enum chipbustype bustype); --void print_supported_chips(void); --void print_supported_chipsets(void); --void print_supported_boards(void); -+void print_supported(void); -+#if (NIC3COM_SUPPORT == 1) || (GFXNVIDIA_SUPPORT == 1) || (DRKAISER_SUPPORT == 1) || (SATASII_SUPPORT == 1) || (ATAHPT_SUPPORT == 1) - void print_supported_pcidevs(struct pcidev_status *devs); --void print_wiki_tables(void); -+#endif -+void print_supported_wiki(void); - - /* board_enable.c */ - void w836xx_ext_enter(uint16_t port); -@@ -301,39 +344,48 @@ void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask); - int board_flash_enable(const char *vendor, const char *part); - - /* chipset_enable.c */ --extern enum chipbustype buses_supported; - int chipset_flash_enable(void); - --extern unsigned long flashbase; -- - /* physmap.c */ - void *physmap(const char *descr, unsigned long phys_addr, size_t len); -+void *physmap_try_ro(const char *descr, unsigned long phys_addr, size_t len); - void physunmap(void *virt_addr, size_t len); - int setup_cpu_msr(int cpu); - void cleanup_cpu_msr(void); --#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__) --typedef struct { uint32_t hi, lo; } msr_t; --msr_t rdmsr(int addr); --int wrmsr(int addr, msr_t msr); --#endif --#if defined(__FreeBSD__) || defined(__DragonFly__) --/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */ --#undef rdmsr --#undef wrmsr --#define rdmsr freebsd_rdmsr --#define wrmsr freebsd_wrmsr --typedef struct { uint32_t hi, lo; } msr_t; --msr_t freebsd_rdmsr(int addr); --int freebsd_wrmsr(int addr, msr_t msr); --#endif -+ -+/* cbtable.c */ -+void lb_vendor_dev_from_string(char *boardstring); -+int coreboot_init(void); -+extern char *lb_part, *lb_vendor; -+extern int partvendor_from_cbtable; -+ -+/* dmi.c */ -+extern int has_dmi_support; -+void dmi_init(void); -+int dmi_match(const char *pattern); - - /* internal.c */ -+#if NEED_PCI == 1 -+struct superio { -+ uint16_t vendor; -+ uint16_t port; -+ uint16_t model; -+}; -+extern struct superio superio; -+#define SUPERIO_VENDOR_NONE 0x0 -+#define SUPERIO_VENDOR_ITE 0x1 - struct pci_dev *pci_dev_find_filter(struct pci_filter filter); -+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class); - struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device); - struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, - uint16_t card_vendor, uint16_t card_device); -+#endif - void get_io_perms(void); - void release_io_perms(void); -+#if INTERNAL_SUPPORT == 1 -+extern int is_laptop; -+extern int force_boardenable; -+void probe_superio(void); - int internal_init(void); - int internal_shutdown(void); - void internal_chip_writeb(uint8_t val, chipaddr addr); -@@ -343,28 +395,29 @@ uint8_t internal_chip_readb(const chipaddr addr); - uint16_t internal_chip_readw(const chipaddr addr); - uint32_t internal_chip_readl(const chipaddr addr); - void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); -+#endif - void mmio_writeb(uint8_t val, void *addr); - void mmio_writew(uint16_t val, void *addr); - void mmio_writel(uint32_t val, void *addr); - uint8_t mmio_readb(void *addr); - uint16_t mmio_readw(void *addr); - uint32_t mmio_readl(void *addr); --void internal_delay(int usecs); --int fallback_shutdown(void); -+ -+/* programmer.c */ -+int noop_shutdown(void); - void *fallback_map(const char *descr, unsigned long phys_addr, size_t len); - void fallback_unmap(void *virt_addr, size_t len); --void fallback_chip_writeb(uint8_t val, chipaddr addr); -+uint8_t noop_chip_readb(const chipaddr addr); -+void noop_chip_writeb(uint8_t val, chipaddr addr); - void fallback_chip_writew(uint16_t val, chipaddr addr); - void fallback_chip_writel(uint32_t val, chipaddr addr); - void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len); - uint16_t fallback_chip_readw(const chipaddr addr); - uint32_t fallback_chip_readl(const chipaddr addr); - void fallback_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); --#if defined(__FreeBSD__) || defined(__DragonFly__) --extern int io_fd; --#endif - - /* dummyflasher.c */ -+#if DUMMY_SUPPORT == 1 - int dummy_init(void); - int dummy_shutdown(void); - void *dummy_map(const char *descr, unsigned long phys_addr, size_t len); -@@ -379,20 +432,52 @@ uint32_t dummy_chip_readl(const chipaddr addr); - void dummy_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); - int dummy_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -+#endif - - /* nic3com.c */ -+#if NIC3COM_SUPPORT == 1 - int nic3com_init(void); - int nic3com_shutdown(void); - void nic3com_chip_writeb(uint8_t val, chipaddr addr); - uint8_t nic3com_chip_readb(const chipaddr addr); - extern struct pcidev_status nics_3com[]; -+#endif -+ -+/* gfxnvidia.c */ -+#if GFXNVIDIA_SUPPORT == 1 -+int gfxnvidia_init(void); -+int gfxnvidia_shutdown(void); -+void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr); -+uint8_t gfxnvidia_chip_readb(const chipaddr addr); -+extern struct pcidev_status gfx_nvidia[]; -+#endif -+ -+/* drkaiser.c */ -+#if DRKAISER_SUPPORT == 1 -+int drkaiser_init(void); -+int drkaiser_shutdown(void); -+void drkaiser_chip_writeb(uint8_t val, chipaddr addr); -+uint8_t drkaiser_chip_readb(const chipaddr addr); -+extern struct pcidev_status drkaiser_pcidev[]; -+#endif - - /* satasii.c */ -+#if SATASII_SUPPORT == 1 - int satasii_init(void); - int satasii_shutdown(void); - void satasii_chip_writeb(uint8_t val, chipaddr addr); - uint8_t satasii_chip_readb(const chipaddr addr); - extern struct pcidev_status satas_sii[]; -+#endif -+ -+/* atahpt.c */ -+#if ATAHPT_SUPPORT == 1 -+int atahpt_init(void); -+int atahpt_shutdown(void); -+void atahpt_chip_writeb(uint8_t val, chipaddr addr); -+uint8_t atahpt_chip_readb(const chipaddr addr); -+extern struct pcidev_status ata_hpt[]; -+#endif - - /* ft2232_spi.c */ - #define FTDI_FT2232H 0x6010 -@@ -402,46 +487,123 @@ int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, const u - int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); - int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf); - -+/* bitbang_spi.c */ -+extern int bitbang_spi_half_period; -+extern const struct bitbang_spi_master_entry bitbang_spi_master_table[]; -+int bitbang_spi_init(void); -+int bitbang_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -+int bitbang_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -+int bitbang_spi_write_256(struct flashchip *flash, uint8_t *buf); -+ -+/* buspirate_spi.c */ -+struct buspirate_spispeeds { -+ const char *name; -+ const int speed; -+}; -+int buspirate_spi_init(void); -+int buspirate_spi_shutdown(void); -+int buspirate_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -+int buspirate_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -+int buspirate_spi_write_256(struct flashchip *flash, uint8_t *buf); -+ -+/* dediprog.c */ -+int dediprog_init(void); -+int dediprog_shutdown(void); -+int dediprog_spi_send_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); -+int dediprog_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); -+ - /* flashrom.c */ -+enum write_granularity { -+ write_gran_1bit, -+ write_gran_1byte, -+ write_gran_256bytes, -+}; -+extern enum chipbustype buses_supported; -+struct decode_sizes { -+ uint32_t parallel; -+ uint32_t lpc; -+ uint32_t fwh; -+ uint32_t spi; -+}; -+extern struct decode_sizes max_rom_decode; - extern char *programmer_param; -+extern unsigned long flashbase; - extern int verbose; - extern const char *flashrom_version; -+extern char *chip_to_probe; - #define printf_debug(x...) { if (verbose) printf(x); } - void map_flash_registers(struct flashchip *flash); - int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len); -+int erase_flash(struct flashchip *flash); -+struct flashchip *probe_flash(struct flashchip *first_flash, int force); -+int read_flash(struct flashchip *flash, char *filename); -+void check_chip_supported(struct flashchip *flash); -+int check_max_decode(enum chipbustype buses, uint32_t size); - int min(int a, int b); - int max(int a, int b); -+char *extract_param(char **haystack, char *needle, char *delim); - int check_erased_range(struct flashchip *flash, int start, int len); - int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, char *message); -+int need_erase(uint8_t *have, uint8_t *want, int len, enum write_granularity gran); - char *strcat_realloc(char *dest, const char *src); -+void print_version(void); -+int selfcheck(void); -+int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it); - - #define OK 0 - #define NT 1 /* Not tested */ - -+/* cli_output.c */ -+int print(int type, const char *fmt, ...); -+#define MSG_ERROR 0 -+#define MSG_INFO 1 -+#define MSG_DEBUG 2 -+#define MSG_BARF 3 -+#define msg_gerr(...) print(MSG_ERROR, __VA_ARGS__) /* general errors */ -+#define msg_perr(...) print(MSG_ERROR, __VA_ARGS__) /* programmer errors */ -+#define msg_cerr(...) print(MSG_ERROR, __VA_ARGS__) /* chip errors */ -+#define msg_ginfo(...) print(MSG_INFO, __VA_ARGS__) /* general info */ -+#define msg_pinfo(...) print(MSG_INFO, __VA_ARGS__) /* programmer info */ -+#define msg_cinfo(...) print(MSG_INFO, __VA_ARGS__) /* chip info */ -+#define msg_gdbg(...) print(MSG_DEBUG, __VA_ARGS__) /* general debug */ -+#define msg_pdbg(...) print(MSG_DEBUG, __VA_ARGS__) /* programmer debug */ -+#define msg_cdbg(...) print(MSG_DEBUG, __VA_ARGS__) /* chip debug */ -+#define msg_gspew(...) print(MSG_BARF, __VA_ARGS__) /* general debug barf */ -+#define msg_pspew(...) print(MSG_BARF, __VA_ARGS__) /* programmer debug barf */ -+#define msg_cspew(...) print(MSG_BARF, __VA_ARGS__) /* chip debug barf */ -+ -+/* cli_classic.c */ -+int cli_classic(int argc, char *argv[]); -+ - /* layout.c */ - int show_id(uint8_t *bios, int size, int force); - int read_romlayout(char *name); - int find_romentry(char *name); - int handle_romentries(uint8_t *buffer, struct flashchip *flash); - --/* cbtable.c */ --int coreboot_init(void); --extern char *lb_part, *lb_vendor; --extern int partvendor_from_cbtable; -- - /* spi.c */ - enum spi_controller { - SPI_CONTROLLER_NONE, -+#if INTERNAL_SUPPORT == 1 - SPI_CONTROLLER_ICH7, - SPI_CONTROLLER_ICH9, - SPI_CONTROLLER_IT87XX, - SPI_CONTROLLER_SB600, - SPI_CONTROLLER_VIA, - SPI_CONTROLLER_WBSIO, -+#endif - #if FT2232_SPI_SUPPORT == 1 - SPI_CONTROLLER_FT2232, - #endif -+#if DUMMY_SUPPORT == 1 - SPI_CONTROLLER_DUMMY, -+#endif -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ SPI_CONTROLLER_BUSPIRATE, -+#endif -+#if DEDIPROG_SUPPORT == 1 -+ SPI_CONTROLLER_DEDIPROG, -+#endif - SPI_CONTROLLER_INVALID /* This must always be the last entry. */ - }; - extern const int spi_programmer_count; -@@ -454,7 +616,7 @@ struct spi_command { - struct spi_programmer { - int (*command)(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); -- int (*multicommand)(struct spi_command *spicommands); -+ int (*multicommand)(struct spi_command *cmds); - - /* Optimized functions for this programmer */ - int (*read)(struct flashchip *flash, uint8_t *buf, int start, int len); -@@ -464,56 +626,13 @@ struct spi_programmer { - extern enum spi_controller spi_controller; - extern const struct spi_programmer spi_programmer[]; - extern void *spibar; --int probe_spi_rdid(struct flashchip *flash); --int probe_spi_rdid4(struct flashchip *flash); --int probe_spi_rems(struct flashchip *flash); --int probe_spi_res(struct flashchip *flash); - int spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); --int spi_send_multicommand(struct spi_command *spicommands); --int spi_write_enable(void); --int spi_write_disable(void); --int spi_chip_erase_60(struct flashchip *flash); --int spi_chip_erase_c7(struct flashchip *flash); --int spi_chip_erase_60_c7(struct flashchip *flash); --int spi_chip_erase_d8(struct flashchip *flash); --int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen); --int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen); --int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen); --int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen); --int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen); --int spi_chip_write_1(struct flashchip *flash, uint8_t *buf); --int spi_chip_write_256(struct flashchip *flash, uint8_t *buf); --int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); --uint8_t spi_read_status_register(void); --int spi_disable_blockprotect(void); --int spi_byte_program(int addr, uint8_t byte); --int spi_nbyte_program(int addr, uint8_t *bytes, int len); --int spi_nbyte_read(int addr, uint8_t *bytes, int len); --int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize); --int spi_aai_write(struct flashchip *flash, uint8_t *buf); --uint32_t spi_get_valid_read_addr(void); -+int spi_send_multicommand(struct spi_command *cmds); - int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); --int default_spi_send_multicommand(struct spi_command *spicommands); -- --/* 82802ab.c */ --int probe_82802ab(struct flashchip *flash); --int erase_82802ab(struct flashchip *flash); --int write_82802ab(struct flashchip *flash, uint8_t *buf); -- --/* am29f040b.c */ --int probe_29f040b(struct flashchip *flash); --int erase_29f040b(struct flashchip *flash); --int write_29f040b(struct flashchip *flash, uint8_t *buf); -- --/* pm29f002.c */ --int write_pm29f002(struct flashchip *flash, uint8_t *buf); -- --/* en29f002a.c */ --int probe_en29f002a(struct flashchip *flash); --int erase_en29f002a(struct flashchip *flash); --int write_en29f002a(struct flashchip *flash, uint8_t *buf); -+int default_spi_send_multicommand(struct spi_command *cmds); -+uint32_t spi_get_valid_read_addr(void); - - /* ichspi.c */ - int ich_init_opcodes(void); -@@ -521,12 +640,13 @@ int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr); - int ich_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); - int ich_spi_write_256(struct flashchip *flash, uint8_t * buf); --int ich_spi_send_multicommand(struct spi_command *spicommands); -+int ich_spi_send_multicommand(struct spi_command *cmds); - - /* it87spi.c */ - extern uint16_t it8716f_flashport; - void enter_conf_mode_ite(uint16_t port); - void exit_conf_mode_ite(uint16_t port); -+struct superio probe_superio_ite(void); - int it87spi_init(void); - int it87xx_probe_spi_flash(const char *name); - int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, -@@ -541,96 +661,6 @@ int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); - int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf); - extern uint8_t *sb600_spibar; - --/* jedec.c */ --uint8_t oddparity(uint8_t val); --void toggle_ready_jedec(chipaddr dst); --void data_polling_jedec(chipaddr dst, uint8_t data); --void unprotect_jedec(chipaddr bios); --void protect_jedec(chipaddr bios); --int write_byte_program_jedec(chipaddr bios, uint8_t *src, -- chipaddr dst); --int probe_jedec(struct flashchip *flash); --int erase_chip_jedec(struct flashchip *flash); --int write_jedec(struct flashchip *flash, uint8_t *buf); --int erase_sector_jedec(struct flashchip *flash, unsigned int page, int pagesize); --int erase_block_jedec(struct flashchip *flash, unsigned int page, int blocksize); --int write_sector_jedec(chipaddr bios, uint8_t *src, -- chipaddr dst, unsigned int page_size); -- --/* m29f002.c */ --int erase_m29f002(struct flashchip *flash); --int write_m29f002t(struct flashchip *flash, uint8_t *buf); --int write_m29f002b(struct flashchip *flash, uint8_t *buf); -- --/* m29f400bt.c */ --int probe_m29f400bt(struct flashchip *flash); --int erase_m29f400bt(struct flashchip *flash); --int block_erase_m29f400bt(struct flashchip *flash, int start, int len); --int write_m29f400bt(struct flashchip *flash, uint8_t *buf); --int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf); --void toggle_ready_m29f400bt(chipaddr dst); --void data_polling_m29f400bt(chipaddr dst, uint8_t data); --void protect_m29f400bt(chipaddr bios); --void write_page_m29f400bt(chipaddr bios, uint8_t *src, -- chipaddr dst, int page_size); -- --/* mx29f002.c */ --int probe_29f002(struct flashchip *flash); --int erase_29f002(struct flashchip *flash); --int write_29f002(struct flashchip *flash, uint8_t *buf); -- --/* pm49fl00x.c */ --int probe_49fl00x(struct flashchip *flash); --int erase_49fl00x(struct flashchip *flash); --int write_49fl00x(struct flashchip *flash, uint8_t *buf); -- --/* sharplhf00l04.c */ --int probe_lhf00l04(struct flashchip *flash); --int erase_lhf00l04(struct flashchip *flash); --int write_lhf00l04(struct flashchip *flash, uint8_t *buf); --void toggle_ready_lhf00l04(chipaddr dst); --void data_polling_lhf00l04(chipaddr dst, uint8_t data); --void protect_lhf00l04(chipaddr bios); -- --/* sst28sf040.c */ --int probe_28sf040(struct flashchip *flash); --int erase_28sf040(struct flashchip *flash); --int write_28sf040(struct flashchip *flash, uint8_t *buf); -- --/* sst39sf020.c */ --int probe_39sf020(struct flashchip *flash); --int write_39sf020(struct flashchip *flash, uint8_t *buf); -- --/* sst49lf040.c */ --int erase_49lf040(struct flashchip *flash); --int write_49lf040(struct flashchip *flash, uint8_t *buf); -- --/* sst49lfxxxc.c */ --int probe_49lfxxxc(struct flashchip *flash); --int erase_49lfxxxc(struct flashchip *flash); --int write_49lfxxxc(struct flashchip *flash, uint8_t *buf); -- --/* sst_fwhub.c */ --int probe_sst_fwhub(struct flashchip *flash); --int erase_sst_fwhub(struct flashchip *flash); --int write_sst_fwhub(struct flashchip *flash, uint8_t *buf); -- --/* w39v040c.c */ --int probe_w39v040c(struct flashchip *flash); --int erase_w39v040c(struct flashchip *flash); --int write_w39v040c(struct flashchip *flash, uint8_t *buf); -- --/* w39V080fa.c */ --int probe_winbond_fwhub(struct flashchip *flash); --int erase_winbond_fwhub(struct flashchip *flash); --int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf); -- --/* w29ee011.c */ --int probe_w29ee011(struct flashchip *flash); -- --/* w49f002u.c */ --int write_49f002(struct flashchip *flash, uint8_t *buf); -- - /* wbsio_spi.c */ - int wbsio_check_for_spi(const char *name); - int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, -@@ -638,11 +668,6 @@ int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len); - int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf); - --/* stm50flw0x0x.c */ --int probe_stm50flw0x0x(struct flashchip *flash); --int erase_stm50flw0x0x(struct flashchip *flash); --int write_stm50flw0x0x(struct flashchip *flash, uint8_t *buf); -- - /* serprog.c */ - int serprog_init(void); - int serprog_shutdown(void); -@@ -651,4 +676,19 @@ uint8_t serprog_chip_readb(const chipaddr addr); - void serprog_chip_readn(uint8_t *buf, const chipaddr addr, size_t len); - void serprog_delay(int delay); - -+/* serial.c */ -+#if _WIN32 -+typedef HANDLE fdtype; -+#else -+typedef int fdtype; -+#endif -+ -+void sp_flush_incoming(void); -+fdtype sp_openserport(char *dev, unsigned int baud); -+void __attribute__((noreturn)) sp_die(char *msg); -+extern fdtype sp_fd; -+int serialport_shutdown(void); -+int serialport_write(unsigned char *buf, unsigned int writecnt); -+int serialport_read(unsigned char *buf, unsigned int readcnt); -+ - #endif /* !__FLASH_H__ */ -diff --git a/flashchips.c b/flashchips.c -index 5fd78f2..10c0989 100644 ---- a/flashchips.c -+++ b/flashchips.c -@@ -5,6 +5,7 @@ - * Copyright (C) 2004 Tyan Corp - * Copyright (C) 2005-2008 coresystems GmbH - * Copyright (C) 2006-2009 Carl-Daniel Hailfinger -+ * Copyright (C) 2009 Sean Nelson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -23,6 +24,7 @@ - - #include "flash.h" - #include "flashchips.h" -+#include "chipdrivers.h" - - /** - * List of supported flash chips. -@@ -43,7 +45,13 @@ struct flashchip flashchips[] = { - * .tested = Test status - * .probe = Probe function - * .probe_timing = Probe function delay -- * .erase = Chip erase function -+ * .block_erasers[] = Array of erase layouts and erase functions -+ * { -+ * .eraseblocks[] = Array of { blocksize, blockcount } -+ * .block_erase = Block erase function -+ * } -+ * .printlock = Chip lock status function -+ * .unlock = Chip unlock function - * .write = Chip write function - * .read = Chip read function - */ -@@ -56,11 +64,21 @@ struct flashchip flashchips[] = { - .model_id = AM_29F010B, /* Same as Am29F010A */ - .total_size = 128, - .page_size = 16 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f040b, -- .probe_timing = TIMING_FIXME, -- .erase = erase_29f040b, -- .write = write_pm29f002, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {16 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -72,11 +90,26 @@ struct flashchip flashchips[] = { - .model_id = AM_29F002BB, - .total_size = 256, - .page_size = 256, -+ .feature_bits = FEATURE_SHORT_RESET | FEATURE_ADDR_2AA, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_en29f002a, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -88,11 +121,26 @@ struct flashchip flashchips[] = { - .model_id = AM_29F002BT, - .total_size = 256, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET | FEATURE_ADDR_2AA, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_en29f002a, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -102,13 +150,23 @@ struct flashchip flashchips[] = { - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = AMD_ID, - .model_id = AM_29F016D, -- .total_size = 2048, -+ .total_size = 2 * 1024, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f040b, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {2048 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -120,11 +178,21 @@ struct flashchip flashchips[] = { - .model_id = AM_29F040B, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f040b, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -136,11 +204,21 @@ struct flashchip flashchips[] = { - .model_id = AM_29F080B, - .total_size = 1024, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -152,11 +230,21 @@ struct flashchip flashchips[] = { - .model_id = AM_29LV040B, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f040b, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -168,11 +256,21 @@ struct flashchip flashchips[] = { - .model_id = AM_29LV080B, - .total_size = 1024, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f040b, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -184,10 +282,25 @@ struct flashchip flashchips[] = { - .model_id = ASD_AE49F2008, - .total_size = 256, - .page_size = 128, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 1}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -203,7 +316,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 8} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -219,7 +350,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -235,7 +384,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 32} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -251,7 +418,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -264,10 +449,28 @@ struct flashchip flashchips[] = { - .model_id = AT_25DF321, - .total_size = 4096, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 128} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -283,7 +486,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 128} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -299,7 +520,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 2048} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 256} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 128} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -315,7 +554,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -331,7 +588,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -347,7 +622,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -363,7 +656,13 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ } -+ }, - .write = NULL /* Incompatible Page write */, - .read = spi_chip_read, - }, -@@ -379,7 +678,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 32} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -395,7 +712,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -411,7 +746,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -428,7 +781,6 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, - .write = spi_chip_write_256, - .read = spi_chip_read, - },*/ -@@ -444,7 +796,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = NULL /* Incompatible Page write */, - .read = spi_chip_read, - }, -@@ -457,10 +827,17 @@ struct flashchip flashchips[] = { - .model_id = AT_29C512, - .total_size = 64, - .page_size = 128, -- .tested = TEST_OK_PREW, -- .probe = probe_jedec, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = 10000, /* 10mS, Enter=Exec */ -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - -@@ -474,10 +851,17 @@ struct flashchip flashchips[] = { - .model_id = AT_29C010A, - .total_size = 128, - .page_size = 128, -- .tested = TEST_OK_PRE, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10000, /* 10mS, Enter=Exec */ -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, /* FIXME */ - .read = read_memmapped, - }, -@@ -490,10 +874,17 @@ struct flashchip flashchips[] = { - .model_id = AT_29C020, - .total_size = 256, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10000, /* 10ms */ -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -506,10 +897,17 @@ struct flashchip flashchips[] = { - .model_id = AT_29C040A, - .total_size = 512, - .page_size = 256, -+ .feature_bits = FEATURE_LONG_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10000, /* 10 ms */ -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -525,7 +923,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL /* Incompatible Page write */, - .read = NULL /* Incompatible read */, - }, -@@ -541,7 +938,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -557,7 +953,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -573,7 +968,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -589,7 +983,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -605,7 +998,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -621,7 +1013,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL /* Incompatible read */, - }, -@@ -637,7 +1028,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -653,7 +1043,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_READ, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -666,11 +1055,18 @@ struct flashchip flashchips[] = { - .model_id = AT_49BV512, - .total_size = 64, - .page_size = 64, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -682,11 +1078,26 @@ struct flashchip flashchips[] = { - .model_id = AT_49F002N, - .total_size = 256, - .page_size = 256, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, /* doc1008.pdf dont says anything about probe timing */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {96 * 1024, 1}, -+ {128 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -698,26 +1109,89 @@ struct flashchip flashchips[] = { - .model_id = AT_49F002NT, - .total_size = 256, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, /* doc1008.pdf dont says anything about probe timing */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 1}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -+ /* The next two chip definitions have top/bottom boot blocks, but has no -+ device differentiation between the two */ - { - .vendor = "AMIC", -- .name = "A25L40P", -+ .name = "A25L40PT", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = AMIC_ID, - .model_id = AMIC_A25L40P, - .total_size = 512, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid4, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "AMIC", -+ .name = "A25L40PU", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = AMIC_ID, -+ .model_id = AMIC_A25L40P, -+ .total_size = 512, -+ .page_size = 256, -+ .tested = TEST_OK_PRW, -+ .probe = probe_spi_rdid4, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 7}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -730,11 +1204,26 @@ struct flashchip flashchips[] = { - .model_id = AMIC_A29002B, - .total_size = 256, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f002, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -746,11 +1235,26 @@ struct flashchip flashchips[] = { - .model_id = AMIC_A29002T, - .total_size = 256, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f002, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_OK_PRW, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -762,11 +1266,21 @@ struct flashchip flashchips[] = { - .model_id = AMIC_A29040B, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PR, -- .probe = probe_29f040b, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -778,11 +1292,22 @@ struct flashchip flashchips[] = { - .model_id = AMIC_A49LF040A, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_49fl00x, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -- .erase = erase_49fl00x, -- .write = write_49fl00x, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .unlock = unlock_49fl00x, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -794,11 +1319,26 @@ struct flashchip flashchips[] = { - .model_id = EMST_F49B002UA, - .total_size = 256, - .page_size = 4096, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 1}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -813,7 +1353,51 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B05T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B05, -+ .total_size = 64, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -829,7 +1413,51 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 3}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B10T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B10, -+ .total_size = 128, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {32 * 1024, 3}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -845,7 +1473,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3} -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B20T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B20, -+ .total_size = 256, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -861,7 +1535,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 7} -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B40T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B40, -+ .total_size = 512, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -877,7 +1597,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 15} -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B80T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B80, -+ .total_size = 1024, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 15}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -893,7 +1659,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 31}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B16T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B16, -+ .total_size = 2048, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 31}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -909,7 +1721,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 63}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B32T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B32, -+ .total_size = 4096, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 63}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -925,7 +1783,53 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ {16 * 1024, 1}, -+ {32 * 1024, 1}, -+ {64 * 1024, 127}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Eon", -+ .name = "EN25B64T", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = EON_ID_NOPREFIX, -+ .model_id = EN_25B64, -+ .total_size = 8192, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 127}, -+ {32 * 1024, 1}, -+ {16 * 1024, 1}, -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -941,7 +1845,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -957,7 +1879,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -973,7 +1913,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -989,7 +1947,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1005,7 +1981,22 @@ struct flashchip flashchips[] = { - .tested = TEST_OK_PROBE, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1021,7 +2012,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1037,7 +2043,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1053,12 +2074,54 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { -+ .vendor = "Eon", -+ .name = "EN29F010", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = EON_ID, -+ .model_id = EN_29F010, -+ .total_size = 128, -+ .page_size = 128, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PREW, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {16 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, -+ .read = read_memmapped, -+ }, -+ -+ { - .vendor = "EON", - .name = "EN29F002(A)(N)B", - .bustype = CHIP_BUSTYPE_PARALLEL, -@@ -1066,11 +2129,26 @@ struct flashchip flashchips[] = { - .model_id = EN_29F002B, - .total_size = 256, - .page_size = 256, -- .tested = TEST_UNTESTED, -+ .feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_en29f002a, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1082,11 +2160,26 @@ struct flashchip flashchips[] = { - .model_id = EN_29F002T, - .total_size = 256, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_en29f002a, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1098,10 +2191,25 @@ struct flashchip flashchips[] = { - .model_id = MBM29F004BC, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 7}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, - .write = NULL, - .read = read_memmapped, - }, -@@ -1114,15 +2222,31 @@ struct flashchip flashchips[] = { - .model_id = MBM29F004TC, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, - .write = NULL, - .read = read_memmapped, - }, - - { -+ /* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */ - .vendor = "Fujitsu", - .name = "MBM29F400BC", - .bustype = CHIP_BUSTYPE_PARALLEL, -@@ -1130,10 +2254,25 @@ struct flashchip flashchips[] = { - .model_id = MBM29F400BC, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ -- .erase = erase_m29f400bt, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 7}, -+ }, -+ .block_erase = block_erase_m29f400bt, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = block_erase_chip_m29f400bt, -+ }, -+ }, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, -@@ -1146,10 +2285,25 @@ struct flashchip flashchips[] = { - .model_id = MBM29F400TC, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ -- .erase = erase_m29f400bt, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = block_erase_m29f400bt, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = block_erase_chip_m29f400bt, -+ }, -+ }, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, -@@ -1162,11 +2316,21 @@ struct flashchip flashchips[] = { - .model_id = P28F001BXB, - .total_size = 128, - .page_size = 128 * 1024, /* 8k + 2x4k + 112k */ -- .tested = TEST_BAD_ERASE|TEST_BAD_WRITE, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -- .write = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ {112 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, - .read = read_memmapped, - }, - -@@ -1178,11 +2342,154 @@ struct flashchip flashchips[] = { - .model_id = P28F001BXT, - .total_size = 128, - .page_size = 128 * 1024, /* 112k + 2x4k + 8k */ -- .tested = TEST_OK_PR|TEST_BAD_ERASE|TEST_BAD_WRITE, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -- .write = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {112 * 1024, 1}, -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "Intel", -+ .name = "28F004S5", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = INTEL_ID, -+ .model_id = E_28F004S5, -+ .total_size = 512, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .unlock = unlock_28f004s5, -+ .write = write_82802ab, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "Intel", -+ .name = "28F004BV/BE-B", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = INTEL_ID, -+ .model_id = P28F004BB, -+ .total_size = 512, -+ .page_size = 128 * 1024, /* maximal block size */ -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {96 * 1024, 1}, -+ {128 * 1024, 3}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "Intel", -+ .name = "28F004BV/BE-T", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = INTEL_ID, -+ .model_id = P28F004BT, -+ .total_size = 512, -+ .page_size = 128 * 1024, /* maximal block size */ -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 3}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "Intel", -+ .name = "28F400BV/CV/CE-B", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = INTEL_ID, -+ .model_id = P28F400BB, -+ .total_size = 512, -+ .page_size = 128 * 1024, /* maximal block size */ -+ .feature_bits = FEATURE_ADDR_SHIFTED, -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {96 * 1024, 1}, -+ {128 * 1024, 3}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "Intel", -+ .name = "28F400BV/CV/CE-T", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = INTEL_ID, -+ .model_id = P28F400BT, -+ .total_size = 512, -+ .page_size = 128 * 1024, /* maximal block size */ -+ .feature_bits = FEATURE_ADDR_SHIFTED, -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 3}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .write = write_82802ab, - .read = read_memmapped, - }, - -@@ -1194,10 +2501,18 @@ struct flashchip flashchips[] = { - .model_id = I_82802AB, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PR, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ -- .erase = erase_82802ab, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .unlock = unlock_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, -@@ -1210,10 +2525,18 @@ struct flashchip flashchips[] = { - .model_id = I_82802AC, - .total_size = 1024, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PR, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */ -- .erase = erase_82802ab, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_block_82802ab, -+ }, -+ }, -+ .unlock = unlock_82802ab, - .write = write_82802ab, - .read = read_memmapped, - }, -@@ -1229,7 +2552,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1245,7 +2586,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1261,7 +2617,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1274,10 +2648,28 @@ struct flashchip flashchips[] = { - .model_id = MX_25L4005, - .total_size = 512, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1290,10 +2682,28 @@ struct flashchip flashchips[] = { - .model_id = MX_25L8005, - .total_size = 1024, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1306,10 +2716,28 @@ struct flashchip flashchips[] = { - .model_id = MX_25L1605, - .total_size = 2048, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, /* This erase function has 64k blocksize for eLiteFlash */ -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, /* Not supported in MX25L1605 (eLiteFlash) and MX25L1605D */ -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1325,7 +2753,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1338,10 +2781,25 @@ struct flashchip flashchips[] = { - .model_id = MX_25L3205, - .total_size = 4096, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1357,7 +2815,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1373,7 +2846,22 @@ struct flashchip flashchips[] = { - .tested = TEST_OK_PROBE, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 128} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1389,7 +2877,22 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 4096} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 256} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {16 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {16 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1402,11 +2905,27 @@ struct flashchip flashchips[] = { - .model_id = MX_29F001B, - .total_size = 128, - .page_size = 32 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f002, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {8 * 1024, 1}, -+ {4 * 1024, 2}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1418,11 +2937,27 @@ struct flashchip flashchips[] = { - .model_id = MX_29F001T, - .total_size = 128, - .page_size = 32 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f002, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 1}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {4 * 1024, 2}, -+ {8 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1434,11 +2969,26 @@ struct flashchip flashchips[] = { - .model_id = MX_29F002B, - .total_size = 256, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f002, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1450,11 +3000,26 @@ struct flashchip flashchips[] = { - .model_id = MX_29F002T, - .total_size = 256, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f002, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_OK_PRW, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1466,11 +3031,21 @@ struct flashchip flashchips[] = { - .model_id = MX_29LV040, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PR, -- .probe = probe_29f002, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (mx29f002.c) */ -- .erase = erase_29f002, -- .write = write_29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1485,7 +3060,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_d8, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1501,7 +3088,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_d8, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1512,12 +3111,24 @@ struct flashchip flashchips[] = { - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = ST_ID, - .model_id = ST_M25PE40, -- .total_size = 256, -+ .total_size = 512, - .page_size = 256, - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_d8, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1533,7 +3144,19 @@ struct flashchip flashchips[] = { - .tested = TEST_OK_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_d8, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1549,7 +3172,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_d8, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1565,7 +3200,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1581,7 +3228,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1597,7 +3262,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1613,7 +3290,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1629,7 +3318,25 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1645,40 +3352,82 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = spi_block_erase_d7, -+ }, { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, - - { - .vendor = "PMC", -- .name = "Pm29F0002T", -+ .name = "Pm29F002T", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_29F002T, - .total_size = 256, -- .page_size = 8192, -- .tested = TEST_OK_PREW, -- .probe = probe_29f040b, -+ .page_size = 8 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_FIXME, -- .erase = erase_29f040b, -- .write = write_pm29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 1}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "PMC", -- .name = "Pm29F0002B", -+ .name = "Pm29F002B", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_29F002B, - .total_size = 256, -- .page_size = 8192, -+ .page_size = 8 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_29f040b, -+ .probe = probe_jedec, - .probe_timing = TIMING_FIXME, -- .erase = erase_29f040b, -- .write = write_pm29f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {96 * 1024, 1}, -+ {128 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1687,50 +3436,174 @@ struct flashchip flashchips[] = { - .name = "Pm39LV010", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = PMC_ID_NOPREFIX, -- .model_id = PMC_39F010, -+ .model_id = PMC_39F010, /* Pm39LV010 and Pm39F010 have identical IDs but different voltage */ - .total_size = 128, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 2} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "PMC", -+ .name = "Pm39LV020", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = PMC_ID_NOPREFIX, -+ .model_id = PMC_39LV020, -+ .total_size = 256, -+ .page_size = 4096, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "PMC", -+ .name = "Pm39LV040", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = PMC_ID_NOPREFIX, -+ .model_id = PMC_39LV040, -+ .total_size = 512, -+ .page_size = 4096, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "PMC", - .name = "Pm49FL002", -- .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ -+ .bustype = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, /* A/A Mux*/ - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_49FL002, - .total_size = 256, - .page_size = 16 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, -- .probe = probe_49fl00x, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -- .erase = erase_49fl00x, -- .write = write_49fl00x, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {16 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .unlock = unlock_49fl00x, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "PMC", - .name = "Pm49FL004", -- .bustype = CHIP_BUSTYPE_LPC|CHIP_BUSTYPE_FWH, /* A/A Mux*/ -+ .bustype = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, /* A/A Mux*/ - .manufacture_id = PMC_ID_NOPREFIX, - .model_id = PMC_49FL004, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_49fl00x, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -- .erase = erase_49fl00x, -- .write = write_49fl00x, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .unlock = unlock_49fl00x, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { -+ .vendor = "Sanyo", -+ .name = "LF25FW203A", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = SANYO_ID, -+ .model_id = SANYO_LE25FW203A, -+ .total_size = 2048, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { - .vendor = "Sharp", - .name = "LHF00L04", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ -@@ -1738,26 +3611,76 @@ struct flashchip flashchips[] = { - .model_id = SHARP_LHF00L04, - .total_size = 1024, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_lhf00l04, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sharplhf00l04.c) */ -- .erase = erase_lhf00l04, -- .write = write_lhf00l04, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 15}, -+ {8 * 1024, 8} -+ }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { -+ {1024 * 1024, 1} -+ }, -+ .block_erase = NULL, /* 30 D0, only in A/A mux mode */ -+ }, -+ }, -+ .unlock = unlock_82802ab, -+ .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "Spansion", -+ .name = "S25FL008A", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = SPANSION_ID, -+ .model_id = SPANSION_S25FL008A, -+ .total_size = 1024, -+ .page_size = 256, -+ .tested = TEST_OK_PREW, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Spansion", - .name = "S25FL016A", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SPANSION_ID, - .model_id = SPANSION_S25FL016A, - .total_size = 2048, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -1770,10 +3693,28 @@ struct flashchip flashchips[] = { - .model_id = SST_25VF016B, - .total_size = 2048, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, -@@ -1786,42 +3727,90 @@ struct flashchip flashchips[] = { - .model_id = SST_25VF032B, - .total_size = 4096, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 128} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", -- .name = "SST25VF040B", -+ .name = "SST25VF040.REMS", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, -- .model_id = SST_25VF040B, -+ .model_id = SST_25VF040_REMS, - .total_size = 512, - .page_size = 256, -- .tested = TEST_UNTESTED, -- .probe = probe_spi_rdid, -+ .tested = TEST_OK_PR, -+ .probe = probe_spi_rems, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, - - { - .vendor = "SST", -- .name = "SST25VF040.REMS", -+ .name = "SST25VF040B", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = SST_ID, -- .model_id = SST_25VF040_REMS, -+ .model_id = SST_25VF040B, - .total_size = 512, -- .page_size = 64*1024, -- .tested = TEST_OK_PR, -- .probe = probe_spi_rems, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, -@@ -1833,11 +3822,29 @@ struct flashchip flashchips[] = { - .manufacture_id = SST_ID, - .model_id = SST_25VF040B_REMS, - .total_size = 512, -- .page_size = 64*1024, -+ .page_size = 256, - .tested = TEST_OK_PR, - .probe = probe_spi_rems, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 16} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, -@@ -1850,10 +3857,28 @@ struct flashchip flashchips[] = { - .model_id = SST_25VF080B, - .total_size = 1024, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_60_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 32} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ }, -+ }, - .write = spi_chip_write_1, - .read = spi_chip_read, - }, -@@ -1866,10 +3891,20 @@ struct flashchip flashchips[] = { - .model_id = SST_28SF040, - .total_size = 512, - .page_size = 256, -+ .feature_bits = 0, - .tested = TEST_UNTESTED, -- .probe = probe_28sf040, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst28sf040.c) */ -- .erase = erase_28sf040, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128, 4096} }, -+ .block_erase = erase_sector_28sf040, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_28sf040, -+ } -+ }, - .write = write_28sf040, - .read = read_memmapped, - }, -@@ -1882,10 +3917,17 @@ struct flashchip flashchips[] = { - .model_id = SST_29EE010, - .total_size = 128, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -1898,10 +3940,17 @@ struct flashchip flashchips[] = { - .model_id = SST_29LE010, - .total_size = 128, - .page_size = 128, -+ .feature_bits = FEATURE_LONG_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -1914,10 +3963,17 @@ struct flashchip flashchips[] = { - .model_id = SST_29EE020A, - .total_size = 256, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PR, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -+ .probe_timing = 10, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -1930,27 +3986,70 @@ struct flashchip flashchips[] = { - .model_id = SST_29LE020, - .total_size = 256, - .page_size = 128, -- .tested = TEST_UNTESTED, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PREW, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, - - { - .vendor = "SST", -+ .name = "SST39SF512", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = SST_ID, -+ .model_id = SST_39SF512, -+ .total_size = 64, -+ .page_size = 4096, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150 ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, -+ .read = read_memmapped, -+ }, -+ -+ { -+ .vendor = "SST", - .name = "SST39SF010A", - .bustype = CHIP_BUSTYPE_PARALLEL, - .manufacture_id = SST_ID, - .model_id = SST_39SF010, - .total_size = 128, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1962,11 +4061,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39SF020, - .total_size = 256, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1978,11 +4087,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39SF040, - .total_size = 512, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -1994,11 +4113,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39VF512, - .total_size = 64, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns*/ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 16} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2010,11 +4139,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39VF010, - .total_size = 128, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2026,11 +4165,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39VF020, - .total_size = 256, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2042,11 +4191,21 @@ struct flashchip flashchips[] = { - .model_id = SST_39VF040, - .total_size = 512, - .page_size = 4096, -- .tested = TEST_OK_PROBE, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2058,11 +4217,24 @@ struct flashchip flashchips[] = { - .model_id = SST_39VF080, - .total_size = 1024, - .page_size = 4096, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2074,11 +4246,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF002A, - .total_size = 256, - .page_size = 16 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_sst_fwhub, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (sst_fwhub.c) */ -- .erase = erase_sst_fwhub, -- .write = write_sst_fwhub, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150 ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {16 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */ -+ } -+ }, -+ .printlock = printlock_sst_fwhub, -+ .unlock = unlock_sst_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2090,15 +4277,33 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF003A, - .total_size = 384, - .page_size = 64 * 1024, -- .tested = TEST_OK_PROBE, -- .probe = probe_sst_fwhub, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (sst_fwhub.c) */ -- .erase = erase_sst_fwhub, -- .write = write_sst_fwhub, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PR, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150 ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 96} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 6} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {384 * 1024, 1} }, -+ .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */ -+ } -+ }, -+ .printlock = printlock_sst_fwhub, -+ .unlock = unlock_sst_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { -+ /* Contrary to the data sheet, TBL# on the SST49LF004B affects the top 128kB (instead of 64kB) -+ * and is only honored for 64k block erase, but not 4k sector erase. -+ */ - .vendor = "SST", - .name = "SST49LF004A/B", - .bustype = CHIP_BUSTYPE_FWH, /* A/A Mux */ -@@ -2106,11 +4311,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF004A, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_OK_PREW, -- .probe = probe_sst_fwhub, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (sst_fwhub.c) */ -- .erase = erase_sst_fwhub, -- .write = write_sst_fwhub, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150 ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */ -+ }, -+ }, -+ .printlock = printlock_sst_fwhub, -+ .unlock = unlock_sst_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2122,10 +4342,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF004C, - .total_size = 512, - .page_size = 4 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_49lfxxxc, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ -- .erase = erase_49lfxxxc, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_49lfxxxc, -+ }, { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ } -+ }, -+ .unlock = unlock_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, -@@ -2138,11 +4374,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF008A, - .total_size = 1024, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_sst_fwhub, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (sst_fwhub.c) */ -- .erase = erase_sst_fwhub, -- .write = write_sst_fwhub, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150 ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */ -+ } -+ }, -+ .printlock = printlock_sst_fwhub, -+ .unlock = unlock_sst_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2154,10 +4405,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF008C, - .total_size = 1024, - .page_size = 4 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_49lfxxxc, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ -- .erase = erase_49lfxxxc, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = erase_sector_49lfxxxc, -+ }, { -+ .eraseblocks = { -+ {64 * 1024, 15}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ } -+ }, -+ .unlock = unlock_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, -@@ -2170,10 +4437,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF016C, - .total_size = 2048, - .page_size = 4 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_49lfxxxc, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PRW, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ -- .erase = erase_49lfxxxc, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = erase_sector_49lfxxxc, -+ }, { -+ .eraseblocks = { -+ {64 * 1024, 31}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ } -+ }, -+ .unlock = unlock_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, -@@ -2186,11 +4469,24 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF020, - .total_size = 256, - .page_size = 16 * 1024, -- .tested = TEST_OK_PR, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_49lf040, -- .write = write_49lf040, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {16 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = NULL, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2202,11 +4498,24 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF020A, - .total_size = 256, - .page_size = 4 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_49lf040, -- .write = write_49lf040, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {16 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = NULL, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2218,11 +4527,24 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF040, - .total_size = 512, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 1, /* 150 ns */ -- .erase = erase_49lf040, -- .write = write_49lf040, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = NULL, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2234,11 +4556,24 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF040B, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_sst_fwhub, -- .probe_timing = TIMING_FIXME, /* routine is wrapper to probe_jedec (sst_fwhub.c) */ -- .erase = erase_sst_fwhub, -- .write = write_sst_fwhub, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = 1, /* 150ns */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = NULL, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2250,11 +4585,24 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF080A, - .total_size = 1024, - .page_size = 4096, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PR, - .probe = probe_jedec, - .probe_timing = TIMING_FIXME, -- .erase = erase_49lf040, -- .write = write_49lf040, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = NULL, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2266,10 +4614,26 @@ struct flashchip flashchips[] = { - .model_id = SST_49LF160C, - .total_size = 2048, - .page_size = 4 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_49lfxxxc, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PRW, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ -- .erase = erase_49lfxxxc, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = erase_sector_49lfxxxc, -+ }, { -+ .eraseblocks = { -+ {64 * 1024, 31}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ } -+ }, -+ .unlock = unlock_49lfxxxc, - .write = write_49lfxxxc, - .read = read_memmapped, - }, -@@ -2285,7 +4649,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2306,7 +4679,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {32 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_1, /* 128 */ - .read = spi_chip_read, - }, -@@ -2322,7 +4704,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2339,7 +4730,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {32 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_1, /* 128 */ - .read = spi_chip_read, - }, -@@ -2355,7 +4755,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2368,10 +4777,19 @@ struct flashchip flashchips[] = { - .model_id = ST_M25P40, - .total_size = 512, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2387,7 +4805,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_res, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2400,10 +4827,19 @@ struct flashchip flashchips[] = { - .model_id = ST_M25P80, - .total_size = 1024, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2416,10 +4852,19 @@ struct flashchip flashchips[] = { - .model_id = ST_M25P16, - .total_size = 2048, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2432,10 +4877,19 @@ struct flashchip flashchips[] = { - .model_id = ST_M25P32, - .total_size = 4096, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2451,7 +4905,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 128} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2467,7 +4930,16 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {256 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {16 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2480,11 +4952,26 @@ struct flashchip flashchips[] = { - .model_id = ST_M29F002B, - .total_size = 256, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_m29f002, -- .write = write_m29f002b, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2496,11 +4983,26 @@ struct flashchip flashchips[] = { - .model_id = ST_M29F002T, - .total_size = 256, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_m29f002, -- .write = write_m29f002t, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2512,15 +5014,26 @@ struct flashchip flashchips[] = { - .model_id = ST_M29F040B, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_29f040b, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (am29f040b.c) */ -- .erase = erase_29f040b, -- .write = write_29f040b, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { -+ /* FIXME: this has WORD/BYTE sequences; 2AA for word, 555 for byte */ - .vendor = "ST", - .name = "M29F400BT", - .bustype = CHIP_BUSTYPE_PARALLEL, -@@ -2528,10 +5041,25 @@ struct flashchip flashchips[] = { - .model_id = ST_M29F400BT, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_m29f400bt, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (m29f400bt.c) */ -- .erase = erase_m29f400bt, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 7}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = block_erase_m29f400bt, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = block_erase_chip_m29f400bt, -+ } -+ }, - .write = write_coreboot_m29f400bt, - .read = read_memmapped, - }, -@@ -2544,11 +5072,21 @@ struct flashchip flashchips[] = { - .model_id = ST_M29W010B, - .total_size = 128, - .page_size = 16 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_jedec, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {16 * 1024, 8}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2560,75 +5098,184 @@ struct flashchip flashchips[] = { - .model_id = ST_M29W040B, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_jedec, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -+ { -+ .vendor = "ST", -+ .name = "M29W512B", -+ .bustype = CHIP_BUSTYPE_PARALLEL, -+ .manufacture_id = ST_ID, -+ .model_id = ST_M29W512B, -+ .total_size = 64, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PREW, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, -+ .read = read_memmapped, -+ }, -+ - { - .vendor = "ST", - .name = "M50FLW040A", -- .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ -+ .bustype = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW040A, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_stm50flw0x0x, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ -- .erase = erase_stm50flw0x0x, -- .write = write_stm50flw0x0x, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 16}, /* sector */ -+ {64 * 1024, 5}, /* block */ -+ {4 * 1024, 16}, /* sector */ -+ {4 * 1024, 16}, /* sector */ -+ }, -+ .block_erase = NULL, -+ }, { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW040B", -- .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ -+ .bustype = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW040B, - .total_size = 512, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_stm50flw0x0x, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ -- .erase = erase_stm50flw0x0x, -- .write = write_stm50flw0x0x, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 16}, /* sector */ -+ {4 * 1024, 16}, /* sector */ -+ {64 * 1024, 5}, /* block */ -+ {4 * 1024, 16}, /* sector */ -+ }, -+ .block_erase = NULL, -+ }, { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW080A", -- .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ -+ .bustype = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW080A, - .total_size = 1024, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -- .probe = probe_stm50flw0x0x, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ -- .erase = erase_stm50flw0x0x, -- .write = write_stm50flw0x0x, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_UNTESTED, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 16}, /* sector */ -+ {64 * 1024, 13}, /* block */ -+ {4 * 1024, 16}, /* sector */ -+ {4 * 1024, 16}, /* sector */ -+ }, -+ .block_erase = NULL, -+ }, { -+ .eraseblocks = { {64 * 1024, 16}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - - { - .vendor = "ST", - .name = "M50FLW080B", -- .bustype = CHIP_BUSTYPE_FWH|CHIP_BUSTYPE_LPC, /* A/A Mux */ -+ .bustype = CHIP_BUSTYPE_FWH | CHIP_BUSTYPE_LPC, /* A/A Mux */ - .manufacture_id = ST_ID, - .model_id = ST_M50FLW080B, - .total_size = 1024, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_stm50flw0x0x, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (stm50flw0x0x.c) */ -- .erase = erase_stm50flw0x0x, -- .write = write_stm50flw0x0x, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 16}, /* sector */ -+ {4 * 1024, 16}, /* sector */ -+ {64 * 1024, 13}, /* block */ -+ {4 * 1024, 16}, /* sector */ -+ }, -+ .block_erase = NULL, -+ }, { -+ .eraseblocks = { {64 * 1024, 16}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - -@@ -2640,11 +5287,27 @@ struct flashchip flashchips[] = { - .model_id = ST_M50FW002, - .total_size = 256, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_49lfxxxc, -+ .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (sst49lfxxxc.c) */ -- .erase = NULL, -- .write = NULL, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - -@@ -2656,10 +5319,21 @@ struct flashchip flashchips[] = { - .model_id = ST_M50FW016, - .total_size = 2048, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ -- .erase = erase_82802ab, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 32}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, - .write = write_82802ab, - .read = read_memmapped, - }, -@@ -2672,10 +5346,21 @@ struct flashchip flashchips[] = { - .model_id = ST_M50FW040, - .total_size = 512, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PR, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ -- .erase = erase_82802ab, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, - .write = write_82802ab, - .read = read_memmapped, - }, -@@ -2688,10 +5373,21 @@ struct flashchip flashchips[] = { - .model_id = ST_M50FW080, - .total_size = 1024, - .page_size = 64 * 1024, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_REGISTERMAP, -+ .tested = TEST_OK_PR, - .probe = probe_82802ab, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (82802ab.c) */ -- .erase = erase_82802ab, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16}, }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, - .write = write_82802ab, - .read = read_memmapped, - }, -@@ -2704,11 +5400,28 @@ struct flashchip flashchips[] = { - .model_id = ST_M50LPW116, - .total_size = 2048, - .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP, - .tested = TEST_UNTESTED, -- .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_jedec, -+ .probe = probe_82802ab, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {4 * 1024, 16}, -+ {64 * 1024, 30}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_block_82802ab, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = erase_chip_stm50flw0x0x, -+ } -+ }, -+ .unlock = unlock_stm50flw0x0x, -+ .write = write_82802ab, - .read = read_memmapped, - }, - -@@ -2720,11 +5433,21 @@ struct flashchip flashchips[] = { - .model_id = S29C31004T, - .total_size = 512, - .page_size = 128, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {1 * 1024, 512} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2736,11 +5459,21 @@ struct flashchip flashchips[] = { - .model_id = S29C51001T, - .total_size = 128, - .page_size = 128, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {512, 256} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2752,11 +5485,21 @@ struct flashchip flashchips[] = { - .model_id = S29C51002T, - .total_size = 256, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {512, 512} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2768,11 +5511,21 @@ struct flashchip flashchips[] = { - .model_id = S29C51004T, - .total_size = 512, - .page_size = 128, -+ .feature_bits = FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {1 * 1024, 512} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2784,11 +5537,26 @@ struct flashchip flashchips[] = { - .model_id = TI_TMS29F002RB, - .total_size = 256, - .page_size = 16384, /* Non-uniform sectors */ -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -- .write = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {16 * 1024, 1}, -+ {8 * 1024, 2}, -+ {32 * 1024, 1}, -+ {64 * 1024, 3}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2800,16 +5568,133 @@ struct flashchip flashchips[] = { - .model_id = TI_TMS29F002RT, - .total_size = 256, - .page_size = 16384, /* Non-uniform sectors */ -+ .feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = NULL, -- .write = NULL, -+ .probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ }, -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - - { - .vendor = "Winbond", -+ .name = "W25Q80", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = WINBOND_NEX_ID, -+ .model_id = W_25Q80, -+ .total_size = 1024, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 32} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Winbond", -+ .name = "W25Q16", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = WINBOND_NEX_ID, -+ .model_id = W_25Q16, -+ .total_size = 2048, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Winbond", -+ .name = "W25Q32", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = WINBOND_NEX_ID, -+ .model_id = W_25Q32, -+ .total_size = 4096, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 128} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Winbond", - .name = "W25x10", - .bustype = CHIP_BUSTYPE_SPI, - .manufacture_id = WINBOND_NEX_ID, -@@ -2819,7 +5704,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 32} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 2} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2835,7 +5732,19 @@ struct flashchip flashchips[] = { - .tested = TEST_UNTESTED, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 64} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 4} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2848,10 +5757,22 @@ struct flashchip flashchips[] = { - .model_id = W_25X40, - .total_size = 512, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2864,10 +5785,22 @@ struct flashchip flashchips[] = { - .model_id = W_25X80, - .total_size = 1024, - .page_size = 256, -- .tested = TEST_OK_PREW, -+ .tested = TEST_OK_PRW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 256} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2883,7 +5816,93 @@ struct flashchip flashchips[] = { - .tested = TEST_OK_PR, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = spi_chip_erase_c7, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 512} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 64} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 32} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {2 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Winbond", -+ .name = "W25x32", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = WINBOND_NEX_ID, -+ .model_id = W_25X32, -+ .total_size = 4096, -+ .page_size = 256, -+ .tested = TEST_OK_PROBE, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 1024} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 128} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 64} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {4 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, -+ .write = spi_chip_write_256, -+ .read = spi_chip_read, -+ }, -+ -+ { -+ .vendor = "Winbond", -+ .name = "W25x64", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = WINBOND_NEX_ID, -+ .model_id = W_25X64, -+ .total_size = 8192, -+ .page_size = 256, -+ .tested = TEST_UNTESTED, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 2048} }, -+ .block_erase = spi_block_erase_20, -+ }, { -+ .eraseblocks = { {32 * 1024, 256} }, -+ .block_erase = spi_block_erase_52, -+ }, { -+ .eraseblocks = { {64 * 1024, 128} }, -+ .block_erase = spi_block_erase_d8, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_60, -+ }, { -+ .eraseblocks = { {8 * 1024 * 1024, 1} }, -+ .block_erase = spi_block_erase_c7, -+ } -+ }, - .write = spi_chip_write_256, - .read = spi_chip_read, - }, -@@ -2896,10 +5915,17 @@ struct flashchip flashchips[] = { - .model_id = W_29C011, - .total_size = 128, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -+ .probe_timing = 10, /* used datasheet for the W29C011A */ -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -2912,10 +5938,17 @@ struct flashchip flashchips[] = { - .model_id = W_29C020C, - .total_size = 256, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -2928,10 +5961,17 @@ struct flashchip flashchips[] = { - .model_id = W_29C040P, - .total_size = 512, - .page_size = 256, -+ .feature_bits = FEATURE_LONG_RESET, - .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -2944,10 +5984,17 @@ struct flashchip flashchips[] = { - .model_id = W_29C011, - .total_size = 128, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_LONG_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_w29ee011, - .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w29ee011.c) */ -- .erase = erase_chip_jedec, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {128 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, - .write = write_jedec, - .read = read_memmapped, - }, -@@ -2959,12 +6006,22 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V040A, - .total_size = 512, -- .page_size = 64*1024, -- .tested = TEST_OK_PREW, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2975,12 +6032,22 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V040B, - .total_size = 512, -- .page_size = 64*1024, -- .tested = TEST_OK_PR | TEST_BAD_ERASE | TEST_BAD_WRITE, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -2991,12 +6058,23 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V040C, - .total_size = 512, -- .page_size = 64*1024, -- .tested = TEST_OK_PREW, -- .probe = probe_w39v040c, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v040c.c) */ -- .erase = erase_w39v040c, -- .write = write_w39v040c, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .printlock = printlock_w39v040c, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3007,12 +6085,25 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V040FA, - .total_size = 512, -- .page_size = 64*1024, -- .tested = TEST_OK_PREW, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {4 * 1024, 128} }, -+ .block_erase = erase_block_jedec, -+ }, { -+ .eraseblocks = { {64 * 1024, 8} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3023,12 +6114,22 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V080A, - .total_size = 1024, -- .page_size = 64*1024, -- .tested = TEST_OK_PREW, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16} }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3040,11 +6141,26 @@ struct flashchip flashchips[] = { - .model_id = W_49F002U, - .total_size = 256, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = 10, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {128 * 1024, 1}, -+ {96 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3056,11 +6172,26 @@ struct flashchip flashchips[] = { - .model_id = W_49V002A, - .total_size = 256, - .page_size = 128, -- .tested = TEST_OK_PREW, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, - .probe = probe_jedec, - .probe_timing = 10, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3072,11 +6203,26 @@ struct flashchip flashchips[] = { - .model_id = W_49V002FA, - .total_size = 256, - .page_size = 128, -- .tested = TEST_UNTESTED, -+ .feature_bits = FEATURE_EITHER_RESET, -+ .tested = TEST_OK_PRW, - .probe = probe_jedec, -- .probe_timing = TIMING_FIXME, -- .erase = erase_chip_jedec, -- .write = write_49f002, -+ .probe_timing = 10, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { -+ {64 * 1024, 3}, -+ {32 * 1024, 1}, -+ {8 * 1024, 2}, -+ {16 * 1024, 1}, -+ }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {256 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3087,12 +6233,23 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V080FA, - .total_size = 1024, -- .page_size = 64*1024, -- .tested = TEST_OK_PREW, -- .probe = probe_winbond_fwhub, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ -- .erase = erase_winbond_fwhub, -- .write = write_winbond_fwhub, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, -+ .tested = TEST_UNTESTED, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 16}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {1024 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .unlock = unlock_winbond_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3103,12 +6260,23 @@ struct flashchip flashchips[] = { - .manufacture_id = WINBOND_ID, - .model_id = W_39V080FA_DM, - .total_size = 512, -- .page_size = 64*1024, -+ .page_size = 64 * 1024, -+ .feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET, - .tested = TEST_UNTESTED, -- .probe = probe_winbond_fwhub, -- .probe_timing = TIMING_IGNORED, /* routine don't use probe_timing (w39v080fa.c) */ -- .erase = erase_winbond_fwhub, -- .write = write_winbond_fwhub, -+ .probe = probe_jedec, -+ .probe_timing = TIMING_FIXME, -+ .block_erasers = -+ { -+ { -+ .eraseblocks = { {64 * 1024, 8}, }, -+ .block_erase = erase_sector_jedec, -+ }, { -+ .eraseblocks = { {512 * 1024, 1} }, -+ .block_erase = erase_chip_block_jedec, -+ } -+ }, -+ .unlock = unlock_winbond_fwhub, -+ .write = write_jedec_1, - .read = read_memmapped, - }, - -@@ -3123,7 +6291,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -3139,7 +6306,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -3155,7 +6321,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -3171,7 +6336,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -3187,7 +6351,6 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, -@@ -3203,10 +6366,49 @@ struct flashchip flashchips[] = { - .tested = TEST_BAD_PREW, - .probe = probe_spi_rdid, - .probe_timing = TIMING_ZERO, -- .erase = NULL, - .write = NULL, - .read = NULL, - }, - -+ { -+ .vendor = "Sanyo", -+ .name = "unknown Sanyo SPI chip", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = SANYO_ID, -+ .model_id = GENERIC_DEVICE_ID, -+ .total_size = 0, -+ .page_size = 256, -+ .tested = TEST_BAD_PREW, -+ .probe = probe_spi_rdid, -+ .probe_timing = TIMING_ZERO, -+ .write = NULL, -+ .read = NULL, -+ }, -+ -+ { -+ .vendor = "Generic", -+ .name = "unknown SPI chip (RDID)", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = GENERIC_MANUF_ID, -+ .model_id = GENERIC_DEVICE_ID, -+ .total_size = 0, -+ .page_size = 256, -+ .tested = TEST_BAD_PREW, -+ .probe = probe_spi_rdid, -+ .write = NULL, -+ }, -+ { -+ .vendor = "Generic", -+ .name = "unknown SPI chip (REMS)", -+ .bustype = CHIP_BUSTYPE_SPI, -+ .manufacture_id = GENERIC_MANUF_ID, -+ .model_id = GENERIC_DEVICE_ID, -+ .total_size = 0, -+ .page_size = 256, -+ .tested = TEST_BAD_PREW, -+ .probe = probe_spi_rems, -+ .write = NULL, -+ }, -+ - { NULL } - }; -diff --git a/flashchips.h b/flashchips.h -index 40edbbb..bfd8145 100644 ---- a/flashchips.h -+++ b/flashchips.h -@@ -34,6 +34,7 @@ - * SPI parts have 16-bit device IDs if they support RDID. - */ - -+#define GENERIC_MANUF_ID 0xffff /* Check if there is a vendor ID */ - #define GENERIC_DEVICE_ID 0xffff /* Only match the vendor ID */ - - #define ALLIANCE_ID 0x52 /* Alliance Semiconductor */ -@@ -163,13 +164,29 @@ - #define EON_ID 0x7F1C /* EON Silicon Devices */ - #define EON_ID_NOPREFIX 0x1C /* EON, missing 0x7F prefix */ - #define EN_25B05 0x2010 /* Same as P05, 2^19 kbit or 2^16 kByte */ -+#define EN_25B05T 0x25 -+#define EN_25B05B 0x95 - #define EN_25B10 0x2011 /* Same as P10 */ -+#define EN_25B10T 0x40 -+#define EN_25B10B 0x30 - #define EN_25B20 0x2012 /* Same as P20 */ -+#define EN_25B20T 0x41 -+#define EN_25B20B 0x31 - #define EN_25B40 0x2013 /* Same as P40 */ -+#define EN_25B40T 0x42 -+#define EN_25B40B 0x32 - #define EN_25B80 0x2014 /* Same as P80 */ -+#define EN_25B80T 0x43 -+#define EN_25B80B 0x33 - #define EN_25B16 0x2015 /* Same as P16 */ -+#define EN_25B16T 0x44 -+#define EN_25B16B 0x34 - #define EN_25B32 0x2016 /* Same as P32 */ -+#define EN_25B32T 0x45 -+#define EN_25B32B 0x35 - #define EN_25B64 0x2017 /* Same as P64 */ -+#define EN_25B64T 0x46 -+#define EN_25B64B 0x36 - #define EN_25D16 0x3015 - #define EN_25F05 0x3110 - #define EN_25F10 0x3111 -@@ -179,7 +196,7 @@ - #define EN_25F16 0x3115 - #define EN_25F32 0x3116 - #define EN_29F512 0x7F21 --#define EN_29F010 0x7F20 -+#define EN_29F010 0x20 - #define EN_29F040A 0x7F04 - #define EN_29LV010 0x7F6E - #define EN_29LV040A 0x7F4F /* EN_29LV040(A) */ -@@ -237,8 +254,15 @@ - #define INTEL_ID 0x89 /* Intel */ - #define I_82802AB 0xAD - #define I_82802AC 0xAC -+#define E_28F004S5 0xA7 -+#define E_28F008S5 0xA6 -+#define E_28F016S5 0xAA - #define P28F001BXT 0x94 /* 28F001BX-T */ - #define P28F001BXB 0x95 /* 28F001BX-B */ -+#define P28F004BT 0x78 /* 28F004BV/BE-T */ -+#define P28F004BB 0x79 /* 28F004BV/BE-B */ -+#define P28F400BT 0x70 /* 28F400BV/CV/CE-T */ -+#define P28F400BB 0x71 /* 28F400BV/CV/CE-B */ - #define SHARP_LH28F008SA 0xA2 /* Sharp chip, Intel Vendor ID */ - #define SHARP_LH28F008SC 0xA6 /* Sharp chip, Intel Vendor ID */ - -@@ -251,11 +275,11 @@ - * and use the same set of IDs. - */ - #define MX_ID 0xC2 /* Macronix (MX) */ --#define MX_25L512 0x2010 /* 2^19 kbit or 2^16 kByte */ -+#define MX_25L512 0x2010 /* Same as MX25V512 */ - #define MX_25L1005 0x2011 - #define MX_25L2005 0x2012 - #define MX_25L4005 0x2013 /* MX25L4005{,A} */ --#define MX_25L8005 0x2014 -+#define MX_25L8005 0x2014 /* Same as MX25V8005 */ - #define MX_25L1605 0x2015 /* MX25L1605{,A,D} */ - #define MX_25L3205 0x2016 /* MX25L3205{,A} */ - #define MX_25L6405 0x2017 /* MX25L3205{,D} */ -@@ -325,6 +349,14 @@ - #define PMC_49FL002 0x6D - #define PMC_49FL004 0x6E - -+/* -+ * The Sanyo chip found so far uses SPI, first byte is manufacture code, -+ * second byte is the device code, -+ * third byte is a dummy byte. -+ */ -+#define SANYO_ID 0x62 -+#define SANYO_LE25FW203A 0x1600 -+ - #define SHARP_ID 0xB0 /* Sharp */ - #define SHARP_LH28F008BJxxPT 0xEC - #define SHARP_LH28F008BJxxPB 0xED -@@ -340,6 +372,7 @@ - * the second device ID byte is memory capacity. - */ - #define SPANSION_ID 0x01 /* Spansion, same ID as AMD */ -+#define SPANSION_S25FL008A 0x0213 - #define SPANSION_S25FL016A 0x0214 - - /* -@@ -380,6 +413,7 @@ - #define SST_29VF020 0x25 - #define SST_29SF040 0x13 - #define SST_29VF040 0x14 -+#define SST_39SF512 0xB4 - #define SST_39SF010 0xB5 - #define SST_39SF020 0xB6 /* Same as 39SF020A */ - #define SST_39SF040 0xB7 -@@ -446,6 +480,7 @@ - #define ST_M29F800DT 0xEC - #define ST_M29W010B 0x23 - #define ST_M29W040B 0xE3 -+#define ST_M29W512B 0x27 - - #define SYNCMOS_ID 0x40 /* SyncMOS and Mosel Vitelic */ - #define S29C51001T 0x01 -@@ -471,6 +506,9 @@ - #define W_25X16 0x3015 - #define W_25X32 0x3016 - #define W_25X64 0x3017 -+#define W_25Q80 0x4014 -+#define W_25Q16 0x4015 -+#define W_25Q32 0x4016 - #define W_29C011 0xC1 - #define W_29C020C 0x45 /* Same as W29C020 and ASD AE29F2008 */ - #define W_29C040P 0x46 /* Same as W29C040 */ -diff --git a/flashrom.8 b/flashrom.8 -index 1324854..47e77d6 100644 ---- a/flashrom.8 -+++ b/flashrom.8 -@@ -22,7 +22,11 @@ checking that your flashrom version won't interpret options in a different way. - .PP - You can specify one of \-E, \-r, \-w, \-v or no operation. - If no operation is specified, then all that happens --is that flash info is dumped and the flash chip is set to writable. -+is that flash info is dumped and the flash chip is set to writable. It is -+recommended that if you try flashrom the first time on a system, you run it -+in probe only mode and check the output. Also you are advised to make a -+backup of your current ROM contents with \-r before you try to write a new -+image. - .TP - .B "\-r, \-\-read " - Read flash ROM contents and save them into the given -@@ -58,6 +62,30 @@ More verbose output. - .TP - .B "\-c, \-\-chip" - Probe only for specified flash ROM chip. -+.TP -+.B "\-m, \-\-mainboard" <[vendor:]part> -+Override mainboard settings. -+.sp -+flashrom reads the coreboot table to determine the current mainboard. If no -+coreboot table could be read or if you want to override these values, you can -+specify \-m, e.g.: -+.sp -+.B " flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom" -+.sp -+See the 'Supported mainboards' section in the output of 'flashrom \-L' for -+a list of boards which require the specification of the board name, if no -+coreboot table is found. -+.TP -+.B "\-f, \-\-force" -+Force write without checking whether the ROM image file is really meant -+to be used on this board. -+.sp -+Note: This check only works while coreboot is running, and only for those -+boards where the coreboot code supports it. -+.TP -+.B "\-l, \-\-layout " -+Read ROM layout from -+.BR . - .sp - flashrom supports ROM layouts. This allows you to flash certain parts of - the flash chip only. A ROM layout file looks like follows: -@@ -86,30 +114,6 @@ ROM layouts should replace the \-s and \-e option since they are more - flexible and they should lead to a ROM update file format with the - ROM layout and the ROM image in one file (cpio, zip or something?). - .TP --.B "\-m, \-\-mainboard" <[vendor:]part> --Override mainboard settings. --.sp --flashrom reads the coreboot table to determine the current mainboard. If no --coreboot table could be read or if you want to override these values, you can --specify \-m, e.g.: --.sp --.B " flashrom -w --mainboard AGAMI:ARUMA agami_aruma.rom" --.sp --See the 'Supported mainboards' section in the output of 'flashrom \-L' for --a list of boards which require the specification of the board name, if no --coreboot table is found. --.TP --.B "\-f, \-\-force" --Force write without checking whether the ROM image file is really meant --to be used on this board. --.sp --Note: This check only works while coreboot is running, and only for those --boards where the coreboot code supports it. --.TP --.B "\-l, \-\-layout " --Read ROM layout from --.BR . --.TP - .B "\-i, \-\-image " - Only flash image - .B -@@ -131,7 +135,7 @@ Same as - but outputs the supported hardware in MediaWiki syntax, so that it can be - easily pasted into the wiki page at http://www.flashrom.org/. - .TP --.B "\-p, \-\-programmer " -+.B "\-p, \-\-programmer [:parameters]" - Specify the programmer device. Currently supported are: - .sp - .BR "* internal" " (default, for in-system flashing in the mainboard)" -@@ -140,15 +144,93 @@ Specify the programmer device. Currently supported are: - .sp - .BR "* nic3com" " (for flash ROMs on 3COM network cards)" - .sp -+.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)" -+.sp -+.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)" -+.sp - .BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)" - .sp -+.BR "* atahpt" " (for flash ROMs on Highpoint ATA/RAID controllers)" -+.sp - .BR "* it87spi" " (for flash ROMs behind an ITE IT87xx Super I/O LPC/SPI translation unit)" - .sp - .BR "* ft2232spi" " (for flash ROMs attached to a FT2232H/FT4232H based USB SPI programmer)" - .sp - .BR "* serprog" " (for flash ROMs attached to Urja's AVR programmer)" - .sp --The dummy programmer has an optional parameter specifying the bus types it -+.BR "* buspiratespi" " (for flash ROMs attached to a Bus Pirate)" -+.sp -+Some programmers have optional or mandatory parameters which are described -+in detail in the -+.B PROGRAMMER SPECIFIC INFO -+section. Support for some programmers can be disabled at compile time. -+.B "flashrom -h" -+lists all supported programmers. -+.TP -+.B "\-h, \-\-help" -+Show a help text and exit. -+.TP -+.B "\-R, \-\-version" -+Show version information and exit. -+.SH PROGRAMMER SPECIFIC INFO -+Some programmer drivers accept further parameters to set programmer-specific -+parameters. These parameters are separated from the programmer name by a -+colon. While some programmers take arguments at fixed positions, other -+programmers use a key/value interface in which the key and value is separated -+by an equal sign and different pairs are separated by a comma or a colon. -+.TP -+.BR "internal " programmer -+Some mainboards require to run mainboard specific code to enable flash erase -+and write support (and probe support on old systems with parallel flash). -+The mainboard brand and model (if it requires specific code) is usually -+autodetected using one of the following mechanisms: If your system is -+running coreboot, the mainboard type is determined from the coreboot table, -+otherwise, the mainboard is detected by examining the onboard PCI devices -+and possibly DMI info. If PCI and DMI do not contain information to uniquely -+identify the mainboard (which is the exception), it might be necessary to -+specify the mainboard using the \-m switch (see above). -+.sp -+Some of these board-specific flash enabling functions (called board enables) -+in flashrom have not yet been tested. If your mainboard is detected needing -+an untested board enable function, a warning message is printed and the -+board enable is not executed, because a wrong board enable function might -+cause the system to behave erratically, as board enable functions touch the -+low-level internals of a mainboard. Not executing a board enable function -+(if one is needed) might cause detection or erasing failure. If your board -+protects only part of the flash (commonly the top end, called boot block), -+flashrom might encounter an error only after erasing the unprotected part, -+so running without the board-enable function might be dangerous for erase -+and write (which includes erase). -+.sp -+The suggested procedure for a mainboard with untested board specific code is -+to first try to probe the ROM (just invoke flashrom and check that it -+detects your flash chip type) without running the board enable code (i.e. -+without any parameters). If it finds your chip, fine, otherwise, retry -+probing your chip with the board-enable code running, using -+.sp -+.B "flashrom -p internal:boardenable=force" -+.sp -+If your chip is still not detected, the board enable code seems to be broken -+or the flash chip unsupported. Otherwise, make a backup of your current ROM -+contents (using \-r) and store it to a medium outside of your computer, like -+an USB drive or a network share. If you needed to run the board enable code -+already for probing, use it for reading too. Now you can try to write the -+new image. You should enable the board enable code in any case now, as it -+has been written because it is known that writing/erasing without the board -+enable is going to fail. In any case (success or failure), please report to -+the flashrom mailing list, see below. -+.sp -+If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus -+translation, flashrom should autodetect that configuration. You can use -+.B "flashrom -p internal:it87spiport=portnum" -+syntax as explained in the -+.B it87spi -+programmer section to use a non-default port for controlling the IT87 series -+Super I/O. In the unlikely case flashrom doesn't detect an active IT87 LPC<->SPI -+bridge, you can try to force recognition by using the it87spi programmer. -+.TP -+.BR "dummy " programmer -+An optional parameter specifies the bus types it - should support. For that you have to use the - .B "flashrom -p dummy:type" - syntax where -@@ -159,11 +241,13 @@ in any order. - .sp - Example: - .B "flashrom -p dummy:lpc,fwh" --.sp --If you have multiple supported PCI cards which can program flash chips --(NICs, SATA/IDE controllers, etc.) in your system, you must use the -+.TP -+.BR "nic3com" , " gfxnvidia" , " satasii " and " atahpt " programmers -+These programmers have an option to specify the PCI address of the card -+your want to use, which must be specified if more than one card supported -+by the selected programmer is installed in your system. The syntax is - .B "flashrom -p xxxx:bb:dd.f" --syntax to explicitly select one of them, where -+, where - .B xxxx - is the name of the programmer - .B bb -@@ -175,20 +259,18 @@ is the PCI function number of the desired NIC. - .sp - Example: - .B "flashrom -p nic3com:05:04.0" --.sp --Currently the following programmers support this mechanism: --.BR nic3com , --.BR satasii . --.sp --The it87spi programmer has an optional parameter which will set the I/O base --port of the IT87* SPI controller interface to the port specified in the --parameter. For that you have to use the --.B "flashrom -p it87spi:port=portnum" -+.TP -+.BR "it87spi " programmer -+An optional parameter sets the I/O base port of the IT87* SPI controller -+interface to the port specified in the parameter instead of using the port -+address set by the BIOS. For that you have to use the -+.B "flashrom -p it87spi:it87spiport=portnum" - syntax where - .B portnum - is an I/O port number which must be a multiple of 8. --.sp --The ft2232spi programmer has an optional parameter specifying the controller -+.TP -+.BR "ft2232spi " programmer -+An optional parameter species the controller - type and interface/port it should support. For that you have to use the - .B "flashrom -p ft2232spi:model,port=interface" - syntax where -@@ -198,31 +280,35 @@ can be any of - and - .B interface - can be any of --.B A --.BR B . -+.BR "A B" . - The default model is - .B 4232H - and the default interface is - .BR B . --.sp --The serprog programmer has an optional parameter specifying either a serial -+.TP -+.BR "serprog " programmer -+A mandatory parameter specifies either a serial - device/baud combination or an IP/port combination for communication with the --programmer. For serial, you have to use the -+programmer. In the device/baud combination, the device has to start with a -+slash. For serial, you have to use the - .B "flashrom -p serprog:/dev/device:baud" - syntax and for IP, you have to use - .B "flashrom -p serprog:ip:port" - instead. More information about serprog is available in serprog-protocol.txt in - the source distribution. --.sp --Support for some programmers can be disabled at compile time. --.B "flashrom -h" --lists all supported programmers. --.TP --.B "\-h, \-\-help" --Show a help text and exit. - .TP --.B "\-R, \-\-version" --Show version information and exit. -+.BR "buspiratespi " programmer -+A required dev parameter specifies the Bus Pirate device node and an optional -+spispeed parameter specifies the frequency of the SPI bus. The parameter -+delimiter is a comma. Syntax is -+.sp -+.B "flashrom -p buspiratespi:dev=/dev/device,spispeed=frequency" -+.sp -+where -+.B frequency -+can be any of -+.B 30k 125k 250k 1M 2M 2.6M 4M 8M -+(in Hz). The default is the maximum frequency of 8 MHz. - .SH EXIT STATUS - flashrom exits with 0 on success, 1 on most failures but with 2 if /dev/mem - (/dev/xsvc on Solaris) can not be opened and with 3 if a call to mmap() fails. -@@ -245,7 +331,7 @@ Claus Gindhart - .br - Dominik Geyer - .br --Eric Biederman -+Eric Biederman - .br - Giampiero Giancipoli - .br -@@ -275,9 +361,9 @@ Steven James - .br - Uwe Hermann - .br --Wang Qingpei -+Wang Qingpei - .br --Yinghai Lu -+Yinghai Lu - .br - some others - .PP -diff --git a/flashrom.c b/flashrom.c -index fc80301..2450dee 100644 ---- a/flashrom.c -+++ b/flashrom.c -@@ -27,16 +27,82 @@ - #include - #include - #include -+#if HAVE_UTSNAME == 1 -+#include -+#endif - #include "flash.h" - #include "flashchips.h" - - const char *flashrom_version = FLASHROM_VERSION; - char *chip_to_probe = NULL; - int verbose = 0; -+ -+#if INTERNAL_SUPPORT == 1 - enum programmer programmer = PROGRAMMER_INTERNAL; -+#elif DUMMY_SUPPORT == 1 -+enum programmer programmer = PROGRAMMER_DUMMY; -+#else -+/* If neither internal nor dummy are selected, we must pick a sensible default. -+ * Since there is no reason to prefer a particular external programmer, we fail -+ * if more than one of them is selected. If only one is selected, it is clear -+ * that the user wants that one to become the default. -+ */ -+#if NIC3COM_SUPPORT+GFXNVIDIA_SUPPORT+DRKAISER_SUPPORT+SATASII_SUPPORT+ATAHPT_SUPPORT+FT2232_SPI_SUPPORT+SERPROG_SUPPORT+BUSPIRATE_SPI_SUPPORT+DEDIPROG_SUPPORT > 1 -+#error Please enable either CONFIG_DUMMY or CONFIG_INTERNAL or disable support for all external programmers except one. -+#endif -+enum programmer programmer = -+#if NIC3COM_SUPPORT == 1 -+ PROGRAMMER_NIC3COM -+#endif -+#if GFXNVIDIA_SUPPORT == 1 -+ PROGRAMMER_GFXNVIDIA -+#endif -+#if DRKAISER_SUPPORT == 1 -+ PROGRAMMER_DRKAISER -+#endif -+#if SATASII_SUPPORT == 1 -+ PROGRAMMER_SATASII -+#endif -+#if ATAHPT_SUPPORT == 1 -+ PROGRAMMER_ATAHPT -+#endif -+#if FT2232_SPI_SUPPORT == 1 -+ PROGRAMMER_FT2232SPI -+#endif -+#if SERPROG_SUPPORT == 1 -+ PROGRAMMER_SERPROG -+#endif -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ PROGRAMMER_BUSPIRATESPI -+#endif -+#if DEDIPROG_SUPPORT == 1 -+ PROGRAMMER_DEDIPROG -+#endif -+; -+#endif -+ - char *programmer_param = NULL; - -+/** -+ * flashrom defaults to Parallel/LPC/FWH flash devices. If a known host -+ * controller is found, the init routine sets the buses_supported bitfield to -+ * contain the supported buses for that controller. -+ */ -+enum chipbustype buses_supported = CHIP_BUSTYPE_NONSPI; -+ -+/** -+ * Programmers supporting multiple buses can have differing size limits on -+ * each bus. Store the limits for each bus in a common struct. -+ */ -+struct decode_sizes max_rom_decode = { -+ .parallel = 0xffffffff, -+ .lpc = 0xffffffff, -+ .fwh = 0xffffffff, -+ .spi = 0xffffffff -+}; -+ - const struct programmer_entry programmer_table[] = { -+#if INTERNAL_SUPPORT == 1 - { - .name = "internal", - .init = internal_init, -@@ -53,7 +119,9 @@ const struct programmer_entry programmer_table[] = { - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -+#endif - -+#if DUMMY_SUPPORT == 1 - { - .name = "dummy", - .init = dummy_init, -@@ -70,7 +138,9 @@ const struct programmer_entry programmer_table[] = { - .chip_writen = dummy_chip_writen, - .delay = internal_delay, - }, -+#endif - -+#if NIC3COM_SUPPORT == 1 - { - .name = "nic3com", - .init = nic3com_init, -@@ -87,7 +157,47 @@ const struct programmer_entry programmer_table[] = { - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -+#endif -+ -+#if GFXNVIDIA_SUPPORT == 1 -+ { -+ .name = "gfxnvidia", -+ .init = gfxnvidia_init, -+ .shutdown = gfxnvidia_shutdown, -+ .map_flash_region = fallback_map, -+ .unmap_flash_region = fallback_unmap, -+ .chip_readb = gfxnvidia_chip_readb, -+ .chip_readw = fallback_chip_readw, -+ .chip_readl = fallback_chip_readl, -+ .chip_readn = fallback_chip_readn, -+ .chip_writeb = gfxnvidia_chip_writeb, -+ .chip_writew = fallback_chip_writew, -+ .chip_writel = fallback_chip_writel, -+ .chip_writen = fallback_chip_writen, -+ .delay = internal_delay, -+ }, -+#endif - -+#if DRKAISER_SUPPORT == 1 -+ { -+ .name = "drkaiser", -+ .init = drkaiser_init, -+ .shutdown = drkaiser_shutdown, -+ .map_flash_region = fallback_map, -+ .unmap_flash_region = fallback_unmap, -+ .chip_readb = drkaiser_chip_readb, -+ .chip_readw = fallback_chip_readw, -+ .chip_readl = fallback_chip_readl, -+ .chip_readn = fallback_chip_readn, -+ .chip_writeb = drkaiser_chip_writeb, -+ .chip_writew = fallback_chip_writew, -+ .chip_writel = fallback_chip_writel, -+ .chip_writen = fallback_chip_writen, -+ .delay = internal_delay, -+ }, -+#endif -+ -+#if SATASII_SUPPORT == 1 - { - .name = "satasii", - .init = satasii_init, -@@ -104,36 +214,58 @@ const struct programmer_entry programmer_table[] = { - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -+#endif - -+#if ATAHPT_SUPPORT == 1 -+ { -+ .name = "atahpt", -+ .init = atahpt_init, -+ .shutdown = atahpt_shutdown, -+ .map_flash_region = fallback_map, -+ .unmap_flash_region = fallback_unmap, -+ .chip_readb = atahpt_chip_readb, -+ .chip_readw = fallback_chip_readw, -+ .chip_readl = fallback_chip_readl, -+ .chip_readn = fallback_chip_readn, -+ .chip_writeb = atahpt_chip_writeb, -+ .chip_writew = fallback_chip_writew, -+ .chip_writel = fallback_chip_writel, -+ .chip_writen = fallback_chip_writen, -+ .delay = internal_delay, -+ }, -+#endif -+ -+#if INTERNAL_SUPPORT == 1 - { - .name = "it87spi", - .init = it87spi_init, -- .shutdown = fallback_shutdown, -+ .shutdown = noop_shutdown, - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, -- .chip_readb = dummy_chip_readb, -+ .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, -- .chip_writeb = fallback_chip_writeb, -+ .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, - .delay = internal_delay, - }, -+#endif - - #if FT2232_SPI_SUPPORT == 1 - { - .name = "ft2232spi", - .init = ft2232_spi_init, -- .shutdown = fallback_shutdown, -+ .shutdown = noop_shutdown, /* Missing shutdown */ - .map_flash_region = fallback_map, - .unmap_flash_region = fallback_unmap, -- .chip_readb = dummy_chip_readb, -+ .chip_readb = noop_chip_readb, - .chip_readw = fallback_chip_readw, - .chip_readl = fallback_chip_readl, - .chip_readn = fallback_chip_readn, -- .chip_writeb = fallback_chip_writeb, -+ .chip_writeb = noop_chip_writeb, - .chip_writew = fallback_chip_writew, - .chip_writel = fallback_chip_writel, - .chip_writen = fallback_chip_writen, -@@ -160,9 +292,76 @@ const struct programmer_entry programmer_table[] = { - }, - #endif - -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ { -+ .name = "buspiratespi", -+ .init = buspirate_spi_init, -+ .shutdown = buspirate_spi_shutdown, -+ .map_flash_region = fallback_map, -+ .unmap_flash_region = fallback_unmap, -+ .chip_readb = noop_chip_readb, -+ .chip_readw = fallback_chip_readw, -+ .chip_readl = fallback_chip_readl, -+ .chip_readn = fallback_chip_readn, -+ .chip_writeb = noop_chip_writeb, -+ .chip_writew = fallback_chip_writew, -+ .chip_writel = fallback_chip_writel, -+ .chip_writen = fallback_chip_writen, -+ .delay = internal_delay, -+ }, -+#endif -+ -+#if DEDIPROG_SUPPORT == 1 -+ { -+ .name = "dediprog", -+ .init = dediprog_init, -+ .shutdown = dediprog_shutdown, -+ .map_flash_region = fallback_map, -+ .unmap_flash_region = fallback_unmap, -+ .chip_readb = noop_chip_readb, -+ .chip_readw = fallback_chip_readw, -+ .chip_readl = fallback_chip_readl, -+ .chip_readn = fallback_chip_readn, -+ .chip_writeb = noop_chip_writeb, -+ .chip_writew = fallback_chip_writew, -+ .chip_writel = fallback_chip_writel, -+ .chip_writen = fallback_chip_writen, -+ .delay = internal_delay, -+ }, -+#endif -+ - {}, /* This entry corresponds to PROGRAMMER_INVALID. */ - }; - -+#define SHUTDOWN_MAXFN 4 -+static int shutdown_fn_count = 0; -+struct shutdown_func_data { -+ void (*func) (void *data); -+ void *data; -+} shutdown_fn[SHUTDOWN_MAXFN]; -+ -+/* Register a function to be executed on programmer shutdown. -+ * The advantage over atexit() is that you can supply a void pointer which will -+ * be used as parameter to the registered function upon programmer shutdown. -+ * This pointer can point to arbitrary data used by said function, e.g. undo -+ * information for GPIO settings etc. If unneeded, set data=NULL. -+ * Please note that the first (void *data) belongs to the function signature of -+ * the function passed as first parameter. -+ */ -+int register_shutdown(void (*function) (void *data), void *data) -+{ -+ if (shutdown_fn_count >= SHUTDOWN_MAXFN) { -+ msg_perr("Tried to register more than %n shutdown functions.\n", -+ SHUTDOWN_MAXFN); -+ return 1; -+ } -+ shutdown_fn[shutdown_fn_count].func = function; -+ shutdown_fn[shutdown_fn_count].data = data; -+ shutdown_fn_count++; -+ -+ return 0; -+} -+ - int programmer_init(void) - { - return programmer_table[programmer].init(); -@@ -170,6 +369,10 @@ int programmer_init(void) - - int programmer_shutdown(void) - { -+ int i; -+ -+ for (i = shutdown_fn_count - 1; i >= 0; i--) -+ shutdown_fn[i].func(shutdown_fn[i].data); - return programmer_table[programmer].shutdown(); - } - -@@ -245,6 +448,8 @@ int read_memmapped(struct flashchip *flash, uint8_t *buf, int start, int len) - return 0; - } - -+unsigned long flashbase = 0; -+ - int min(int a, int b) - { - return (a < b) ? a : b; -@@ -255,6 +460,15 @@ int max(int a, int b) - return (a > b) ? a : b; - } - -+int bitcount(unsigned long a) -+{ -+ int i = 0; -+ for (; a != 0; a >>= 1) -+ if (a & 1) -+ i++; -+ return i; -+} -+ - char *strcat_realloc(char *dest, const char *src) - { - dest = realloc(dest, strlen(dest) + strlen(src) + 1); -@@ -264,6 +478,60 @@ char *strcat_realloc(char *dest, const char *src) - return dest; - } - -+/* This is a somewhat hacked function similar in some ways to strtok(). -+ * It will look for needle in haystack, return a copy of needle and remove -+ * everything from the first occurrence of needle to the next delimiter -+ * from haystack. -+ */ -+char *extract_param(char **haystack, char *needle, char *delim) -+{ -+ char *param_pos, *rest, *tmp; -+ char *dev = NULL; -+ int devlen; -+ -+ param_pos = strstr(*haystack, needle); -+ do { -+ if (!param_pos) -+ return NULL; -+ /* Beginning of the string? */ -+ if (param_pos == *haystack) -+ break; -+ /* After a delimiter? */ -+ if (strchr(delim, *(param_pos - 1))) -+ break; -+ /* Continue searching. */ -+ param_pos++; -+ param_pos = strstr(param_pos, needle); -+ } while (1); -+ -+ if (param_pos) { -+ param_pos += strlen(needle); -+ devlen = strcspn(param_pos, delim); -+ if (devlen) { -+ dev = malloc(devlen + 1); -+ if (!dev) { -+ fprintf(stderr, "Out of memory!\n"); -+ exit(1); -+ } -+ strncpy(dev, param_pos, devlen); -+ dev[devlen] = '\0'; -+ } -+ rest = param_pos + devlen; -+ rest += strspn(rest, delim); -+ param_pos -= strlen(needle); -+ memmove(param_pos, rest, strlen(rest) + 1); -+ tmp = realloc(*haystack, strlen(*haystack) + 1); -+ if (!tmp) { -+ fprintf(stderr, "Out of memory!\n"); -+ exit(1); -+ } -+ *haystack = tmp; -+ } -+ -+ -+ return dev; -+} -+ - /* start is an offset to the base address of the flash chip */ - int check_erased_range(struct flashchip *flash, int start, int len) - { -@@ -281,7 +549,8 @@ int check_erased_range(struct flashchip *flash, int start, int len) - } - - /** -- * @cmpbuf buffer to compare against -+ * @cmpbuf buffer to compare against, cmpbuf[0] is expected to match the -+ flash content at location start - * @start offset to the base address of the flash chip - * @len length of the verified area - * @message string to print in the "FAILED" message -@@ -354,32 +623,286 @@ out_free: - return ret; - } - -+/** -+ * Check if the buffer @have can be programmed to the content of @want without -+ * erasing. This is only possible if all chunks of size @gran are either kept -+ * as-is or changed from an all-ones state to any other state. -+ * The following write granularities (enum @gran) are known: -+ * - 1 bit. Each bit can be cleared individually. -+ * - 1 byte. A byte can be written once. Further writes to an already written -+ * byte cause the contents to be either undefined or to stay unchanged. -+ * - 128 bytes. If less than 128 bytes are written, the rest will be -+ * erased. Each write to a 128-byte region will trigger an automatic erase -+ * before anything is written. Very uncommon behaviour and unsupported by -+ * this function. -+ * - 256 bytes. If less than 256 bytes are written, the contents of the -+ * unwritten bytes are undefined. -+ * -+ * @have buffer with current content -+ * @want buffer with desired content -+ * @len length of the verified area -+ * @gran write granularity (enum, not count) -+ * @return 0 if no erase is needed, 1 otherwise -+ */ -+int need_erase(uint8_t *have, uint8_t *want, int len, enum write_granularity gran) -+{ -+ int result = 0; -+ int i, j, limit; -+ -+ switch (gran) { -+ case write_gran_1bit: -+ for (i = 0; i < len; i++) -+ if ((have[i] & want[i]) != want[i]) { -+ result = 1; -+ break; -+ } -+ break; -+ case write_gran_1byte: -+ for (i = 0; i < len; i++) -+ if ((have[i] != want[i]) && (have[i] != 0xff)) { -+ result = 1; -+ break; -+ } -+ break; -+ case write_gran_256bytes: -+ for (j = 0; j < len / 256; j++) { -+ limit = min (256, len - j * 256); -+ /* Are 'have' and 'want' identical? */ -+ if (!memcmp(have + j * 256, want + j * 256, limit)) -+ continue; -+ /* have needs to be in erased state. */ -+ for (i = 0; i < limit; i++) -+ if (have[i] != 0xff) { -+ result = 1; -+ break; -+ } -+ if (result) -+ break; -+ } -+ break; -+ } -+ return result; -+} -+ -+/* This function generates various test patterns useful for testing controller -+ * and chip communication as well as chip behaviour. -+ * -+ * If a byte can be written multiple times, each time keeping 0-bits at 0 -+ * and changing 1-bits to 0 if the new value for that bit is 0, the effect -+ * is essentially an AND operation. That's also the reason why this function -+ * provides the result of AND between various patterns. -+ * -+ * Below is a list of patterns (and their block length). -+ * Pattern 0 is 05 15 25 35 45 55 65 75 85 95 a5 b5 c5 d5 e5 f5 (16 Bytes) -+ * Pattern 1 is 0a 1a 2a 3a 4a 5a 6a 7a 8a 9a aa ba ca da ea fa (16 Bytes) -+ * Pattern 2 is 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f (16 Bytes) -+ * Pattern 3 is a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af (16 Bytes) -+ * Pattern 4 is 00 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 (16 Bytes) -+ * Pattern 5 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f (16 Bytes) -+ * Pattern 6 is 00 (1 Byte) -+ * Pattern 7 is ff (1 Byte) -+ * Patterns 0-7 have a big-endian block number in the last 2 bytes of each 256 -+ * byte block. -+ * -+ * Pattern 8 is 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11... (256 B) -+ * Pattern 9 is ff fe fd fc fb fa f9 f8 f7 f6 f5 f4 f3 f2 f1 f0 ef ee... (256 B) -+ * Pattern 10 is 00 00 00 01 00 02 00 03 00 04... (128 kB big-endian counter) -+ * Pattern 11 is ff ff ff fe ff fd ff fc ff fb... (128 kB big-endian downwards) -+ * Pattern 12 is 00 (1 Byte) -+ * Pattern 13 is ff (1 Byte) -+ * Patterns 8-13 have no block number. -+ * -+ * Patterns 0-3 are created to detect and efficiently diagnose communication -+ * slips like missed bits or bytes and their repetitive nature gives good visual -+ * cues to the person inspecting the results. In addition, the following holds: -+ * AND Pattern 0/1 == Pattern 4 -+ * AND Pattern 2/3 == Pattern 5 -+ * AND Pattern 0/1/2/3 == AND Pattern 4/5 == Pattern 6 -+ * A weakness of pattern 0-5 is the inability to detect swaps/copies between -+ * any two 16-byte blocks except for the last 16-byte block in a 256-byte bloc. -+ * They work perfectly for detecting any swaps/aliasing of blocks >= 256 bytes. -+ * 0x5 and 0xa were picked because they are 0101 and 1010 binary. -+ * Patterns 8-9 are best for detecting swaps/aliasing of blocks < 256 bytes. -+ * Besides that, they provide for bit testing of the last two bytes of every -+ * 256 byte block which contains the block number for patterns 0-6. -+ * Patterns 10-11 are special purpose for detecting subblock aliasing with -+ * block sizes >256 bytes (some Dataflash chips etc.) -+ * AND Pattern 8/9 == Pattern 12 -+ * AND Pattern 10/11 == Pattern 12 -+ * Pattern 13 is the completely erased state. -+ * None of the patterns can detect aliasing at boundaries which are a multiple -+ * of 16 MBytes (but such chips do not exist anyway for Parallel/LPC/FWH/SPI). -+ */ -+int generate_testpattern(uint8_t *buf, uint32_t size, int variant) -+{ -+ int i; -+ -+ if (!buf) { -+ fprintf(stderr, "Invalid buffer!\n"); -+ return 1; -+ } -+ -+ switch (variant) { -+ case 0: -+ for (i = 0; i < size; i++) -+ buf[i] = (i & 0xf) << 4 | 0x5; -+ break; -+ case 1: -+ for (i = 0; i < size; i++) -+ buf[i] = (i & 0xf) << 4 | 0xa; -+ break; -+ case 2: -+ for (i = 0; i < size; i++) -+ buf[i] = 0x50 | (i & 0xf); -+ break; -+ case 3: -+ for (i = 0; i < size; i++) -+ buf[i] = 0xa0 | (i & 0xf); -+ break; -+ case 4: -+ for (i = 0; i < size; i++) -+ buf[i] = (i & 0xf) << 4; -+ break; -+ case 5: -+ for (i = 0; i < size; i++) -+ buf[i] = i & 0xf; -+ break; -+ case 6: -+ memset(buf, 0x00, size); -+ break; -+ case 7: -+ memset(buf, 0xff, size); -+ break; -+ case 8: -+ for (i = 0; i < size; i++) -+ buf[i] = i & 0xff; -+ break; -+ case 9: -+ for (i = 0; i < size; i++) -+ buf[i] = ~(i & 0xff); -+ break; -+ case 10: -+ for (i = 0; i < size % 2; i++) { -+ buf[i * 2] = (i >> 8) & 0xff; -+ buf[i * 2 + 1] = i & 0xff; -+ } -+ if (size & 0x1) -+ buf[i * 2] = (i >> 8) & 0xff; -+ break; -+ case 11: -+ for (i = 0; i < size % 2; i++) { -+ buf[i * 2] = ~((i >> 8) & 0xff); -+ buf[i * 2 + 1] = ~(i & 0xff); -+ } -+ if (size & 0x1) -+ buf[i * 2] = ~((i >> 8) & 0xff); -+ break; -+ case 12: -+ memset(buf, 0x00, size); -+ break; -+ case 13: -+ memset(buf, 0xff, size); -+ break; -+ } -+ -+ if ((variant >= 0) && (variant <= 7)) { -+ /* Write block number in the last two bytes of each 256-byte -+ * block, big endian for easier reading of the hexdump. -+ * Note that this wraps around for chips larger than 2^24 bytes -+ * (16 MB). -+ */ -+ for (i = 0; i < size / 256; i++) { -+ buf[i * 256 + 254] = (i >> 8) & 0xff; -+ buf[i * 256 + 255] = i & 0xff; -+ } -+ } -+ -+ return 0; -+} -+ -+int check_max_decode(enum chipbustype buses, uint32_t size) -+{ -+ int limitexceeded = 0; -+ if ((buses & CHIP_BUSTYPE_PARALLEL) && -+ (max_rom_decode.parallel < size)) { -+ limitexceeded++; -+ printf_debug("Chip size %u kB is bigger than supported " -+ "size %u kB of chipset/board/programmer " -+ "for %s interface, " -+ "probe/read/erase/write may fail. ", size / 1024, -+ max_rom_decode.parallel / 1024, "Parallel"); -+ } -+ if ((buses & CHIP_BUSTYPE_LPC) && (max_rom_decode.lpc < size)) { -+ limitexceeded++; -+ printf_debug("Chip size %u kB is bigger than supported " -+ "size %u kB of chipset/board/programmer " -+ "for %s interface, " -+ "probe/read/erase/write may fail. ", size / 1024, -+ max_rom_decode.lpc / 1024, "LPC"); -+ } -+ if ((buses & CHIP_BUSTYPE_FWH) && (max_rom_decode.fwh < size)) { -+ limitexceeded++; -+ printf_debug("Chip size %u kB is bigger than supported " -+ "size %u kB of chipset/board/programmer " -+ "for %s interface, " -+ "probe/read/erase/write may fail. ", size / 1024, -+ max_rom_decode.fwh / 1024, "FWH"); -+ } -+ if ((buses & CHIP_BUSTYPE_SPI) && (max_rom_decode.spi < size)) { -+ limitexceeded++; -+ printf_debug("Chip size %u kB is bigger than supported " -+ "size %u kB of chipset/board/programmer " -+ "for %s interface, " -+ "probe/read/erase/write may fail. ", size / 1024, -+ max_rom_decode.spi / 1024, "SPI"); -+ } -+ if (!limitexceeded) -+ return 0; -+ /* Sometimes chip and programmer have more than one bus in common, -+ * and the limit is not exceeded on all buses. Tell the user. -+ */ -+ if (bitcount(buses) > limitexceeded) -+ /* FIXME: This message is designed towards CLI users. */ -+ printf_debug("There is at least one common chip/programmer " -+ "interface which can support a chip of this size. " -+ "You can try --force at your own risk.\n"); -+ return 1; -+} -+ - struct flashchip *probe_flash(struct flashchip *first_flash, int force) - { - struct flashchip *flash; -- unsigned long base = 0, size; -+ unsigned long base = 0; -+ uint32_t size; -+ enum chipbustype buses_common; - char *tmp; - - for (flash = first_flash; flash && flash->name; flash++) { - if (chip_to_probe && strcmp(flash->name, chip_to_probe) != 0) - continue; -- printf_debug("Probing for %s %s, %d KB: ", -+ msg_gdbg("Probing for %s %s, %d KB: ", - flash->vendor, flash->name, flash->total_size); - if (!flash->probe && !force) { -- printf_debug("failed! flashrom has no probe function for this flash chip.\n"); -+ msg_gdbg("failed! flashrom has no probe function for " -+ "this flash chip.\n"); - continue; - } -- if (!(buses_supported & flash->bustype)) { -+ buses_common = buses_supported & flash->bustype; -+ if (!buses_common) { - tmp = flashbuses_to_text(buses_supported); -- printf_debug("skipped. Host bus type %s ", tmp); -+ msg_gdbg("skipped."); -+ msg_gspew(" Host bus type %s ", tmp); - free(tmp); - tmp = flashbuses_to_text(flash->bustype); -- printf_debug("and chip bus type %s are incompatible.\n", tmp); -+ msg_gspew("and chip bus type %s are incompatible.", -+ tmp); - free(tmp); -+ msg_gdbg("\n"); - continue; - } - - size = flash->total_size * 1024; -+ check_max_decode(buses_common, size); - - base = flashbase ? flashbase : (0xffffffff - size + 1); - flash->virtual_memory = (chipaddr)programmer_map_flash_region("flash chip", base, size); -@@ -405,6 +928,9 @@ notfound: - flash->vendor, flash->name, flash->total_size, - flashbuses_to_text(flash->bustype), base); - -+ if (flash->printlock) -+ flash->printlock(flash); -+ - return flash; - } - -@@ -434,7 +960,7 @@ int read_flash(struct flashchip *flash, char *filename) - printf("Error: No filename specified.\n"); - return 1; - } -- if ((image = fopen(filename, "w")) == NULL) { -+ if ((image = fopen(filename, "wb")) == NULL) { - perror(filename); - exit(1); - } -@@ -455,362 +981,231 @@ int read_flash(struct flashchip *flash, char *filename) - return 0; - } - -+/* This function shares a lot of its structure with erase_flash(). -+ * Even if an error is found, the function will keep going and check the rest. -+ */ -+int selfcheck_eraseblocks(struct flashchip *flash) -+{ -+ int i, j, k; -+ int ret = 0; -+ -+ for (k = 0; k < NUM_ERASEFUNCTIONS; k++) { -+ unsigned int done = 0; -+ struct block_eraser eraser = flash->block_erasers[k]; -+ -+ for (i = 0; i < NUM_ERASEREGIONS; i++) { -+ /* Blocks with zero size are bugs in flashchips.c. */ -+ if (eraser.eraseblocks[i].count && -+ !eraser.eraseblocks[i].size) { -+ msg_gerr("ERROR: Flash chip %s erase function " -+ "%i region %i has size 0. Please report" -+ " a bug at flashrom@flashrom.org\n", -+ flash->name, k, i); -+ ret = 1; -+ } -+ /* Blocks with zero count are bugs in flashchips.c. */ -+ if (!eraser.eraseblocks[i].count && -+ eraser.eraseblocks[i].size) { -+ msg_gerr("ERROR: Flash chip %s erase function " -+ "%i region %i has count 0. Please report" -+ " a bug at flashrom@flashrom.org\n", -+ flash->name, k, i); -+ ret = 1; -+ } -+ done += eraser.eraseblocks[i].count * -+ eraser.eraseblocks[i].size; -+ } -+ /* Empty eraseblock definition with erase function. */ -+ if (!done && eraser.block_erase) -+ msg_pspew("Strange: Empty eraseblock definition with " -+ "non-empty erase function. Not an error.\n"); -+ if (!done) -+ continue; -+ if (done != flash->total_size * 1024) { -+ msg_gerr("ERROR: Flash chip %s erase function %i " -+ "region walking resulted in 0x%06x bytes total," -+ " expected 0x%06x bytes. Please report a bug at" -+ " flashrom@flashrom.org\n", flash->name, k, -+ done, flash->total_size * 1024); -+ ret = 1; -+ } -+ if (!eraser.block_erase) -+ continue; -+ /* Check if there are identical erase functions for different -+ * layouts. That would imply "magic" erase functions. The -+ * easiest way to check this is with function pointers. -+ */ -+ for (j = k + 1; j < NUM_ERASEFUNCTIONS; j++) { -+ if (eraser.block_erase == -+ flash->block_erasers[j].block_erase) { -+ msg_gerr("ERROR: Flash chip %s erase function " -+ "%i and %i are identical. Please report" -+ " a bug at flashrom@flashrom.org\n", -+ flash->name, k, j); -+ ret = 1; -+ } -+ } -+ } -+ return ret; -+} -+ - int erase_flash(struct flashchip *flash) - { -- uint32_t erasedbytes; -- unsigned long size = flash->total_size * 1024; -- unsigned char *buf = calloc(size, sizeof(char)); -+ int i, j, k, ret = 0, found = 0; -+ unsigned int start, len; -+ - printf("Erasing flash chip... "); -- if (NULL == flash->erase) { -- printf("FAILED!\n"); -+ for (k = 0; k < NUM_ERASEFUNCTIONS; k++) { -+ unsigned int done = 0; -+ struct block_eraser eraser = flash->block_erasers[k]; -+ -+ printf_debug("Looking at blockwise erase function %i... ", k); -+ if (!eraser.block_erase && !eraser.eraseblocks[0].count) { -+ printf_debug("not defined. " -+ "Looking for another erase function.\n"); -+ continue; -+ } -+ if (!eraser.block_erase && eraser.eraseblocks[0].count) { -+ printf_debug("eraseblock layout is known, but no " -+ "matching block erase function found. " -+ "Looking for another erase function.\n"); -+ continue; -+ } -+ if (eraser.block_erase && !eraser.eraseblocks[0].count) { -+ printf_debug("block erase function found, but " -+ "eraseblock layout is unknown. " -+ "Looking for another erase function.\n"); -+ continue; -+ } -+ found = 1; -+ printf_debug("trying... "); -+ for (i = 0; i < NUM_ERASEREGIONS; i++) { -+ /* count==0 for all automatically initialized array -+ * members so the loop below won't be executed for them. -+ */ -+ for (j = 0; j < eraser.eraseblocks[i].count; j++) { -+ start = done + eraser.eraseblocks[i].size * j; -+ len = eraser.eraseblocks[i].size; -+ printf_debug("0x%06x-0x%06x, ", start, -+ start + len - 1); -+ ret = eraser.block_erase(flash, start, len); -+ if (ret) -+ break; -+ } -+ if (ret) -+ break; -+ done += eraser.eraseblocks[i].count * -+ eraser.eraseblocks[i].size; -+ } -+ printf_debug("\n"); -+ /* If everything is OK, don't try another erase function. */ -+ if (!ret) -+ break; -+ } -+ if (!found) { - fprintf(stderr, "ERROR: flashrom has no erase function for this flash chip.\n"); - return 1; - } -- flash->erase(flash); - -- /* FIXME: The lines below are superfluous. We should check the result -- * of flash->erase(flash) instead. -- */ -- if (!flash->read) { -- printf("FAILED!\n"); -- fprintf(stderr, "ERROR: flashrom has no read function for this flash chip.\n"); -- return 1; -- } else -- flash->read(flash, buf, 0, size); -- -- for (erasedbytes = 0; erasedbytes < size; erasedbytes++) -- if (0xff != buf[erasedbytes]) { -- printf("FAILED!\n"); -- fprintf(stderr, "ERROR at 0x%08x: Expected=0xff, Read=0x%02x\n", -- erasedbytes, buf[erasedbytes]); -- return 1; -- } -- printf("SUCCESS.\n"); -- return 0; -+ if (ret) { -+ fprintf(stderr, "FAILED!\n"); -+ } else { -+ printf("SUCCESS.\n"); -+ } -+ return ret; - } - --void emergency_help_message() -+void emergency_help_message(void) - { - fprintf(stderr, "Your flash chip is in an unknown state.\n" -- "Get help on IRC at irc.freenode.net channel #flashrom or\n" -- "mail flashrom@flashrom.org\n" -- "------------------------------------------------------------\n" -+ "Get help on IRC at irc.freenode.net (channel #flashrom) or\n" -+ "mail flashrom@flashrom.org!\n--------------------" -+ "-----------------------------------------------------------\n" - "DO NOT REBOOT OR POWEROFF!\n"); - } - --void usage(const char *name) -+/* The way to go if you want a delimited list of programmers*/ -+void list_programmers(char *delim) - { -- const char *pname; -- int pnamelen; -- int remaining = 0; - enum programmer p; -- -- printf("usage: %s [-VfLzhR] [-E|-r file|-w file|-v file] [-c chipname]\n" -- " [-m [vendor:]part] [-l file] [-i image] [-p programmer]\n\n", name); -- -- printf("Please note that the command line interface for flashrom will " -- "change before\nflashrom 1.0. Do not use flashrom in scripts " -- "or other automated tools without\nchecking that your flashrom" -- " version won't interpret options in a different way.\n\n"); -- -- printf -- (" -r | --read: read flash and save into file\n" -- " -w | --write: write file into flash\n" -- " -v | --verify: verify flash against file\n" -- " -n | --noverify: don't verify flash against file\n" -- " -E | --erase: erase flash device\n" -- " -V | --verbose: more verbose output\n" -- " -c | --chip : probe only for specified flash chip\n" -- " -m | --mainboard <[vendor:]part>: override mainboard settings\n" -- " -f | --force: force write without checking image\n" -- " -l | --layout : read ROM layout from file\n" -- " -i | --image : only flash image name from flash layout\n" -- " -L | --list-supported: print supported devices\n" -- " -z | --list-supported-wiki: print supported devices in wiki syntax\n" -- " -p | --programmer : specify the programmer device"); -- - for (p = 0; p < PROGRAMMER_INVALID; p++) { -- pname = programmer_table[p].name; -- pnamelen = strlen(pname); -- if (remaining - pnamelen - 2 < 0) { -- printf("\n "); -- remaining = 43; -- } else { -- printf(" "); -- remaining--; -- } -- if (p == 0) { -- printf("("); -- remaining--; -- } -- printf("%s", pname); -- remaining -= pnamelen; -- if (p < PROGRAMMER_INVALID - 1) { -- printf(","); -- remaining--; -- } else { -- printf(")\n"); -- } -+ printf("%s", programmer_table[p].name); -+ if (p < PROGRAMMER_INVALID - 1) -+ printf("%s", delim); - } -- -- printf( -- " -h | --help: print this help text\n" -- " -R | --version: print the version (release)\n" -- "\nYou can specify one of -E, -r, -w, -v or no operation. If no operation is\n" -- "specified, then all that happens is that flash info is dumped.\n\n"); -- exit(1); -+ printf("\n"); -+} -+ -+void print_sysinfo(void) -+{ -+#if HAVE_UTSNAME == 1 -+ struct utsname osinfo; -+ uname(&osinfo); -+ -+ msg_ginfo(" on %s %s (%s)", osinfo.sysname, osinfo.release, -+ osinfo.machine); -+#else -+ msg_ginfo(" on unknown machine"); -+#endif -+ msg_ginfo(", built with"); -+#if NEED_PCI == 1 -+#ifdef PCILIB_VERSION -+ msg_ginfo(" libpci %s,", PCILIB_VERSION); -+#else -+ msg_ginfo(" unknown PCI library,"); -+#endif -+#endif -+#ifdef __clang__ -+ msg_ginfo(" LLVM %i/clang %i", __llvm__, __clang__); -+#elif defined(__GNUC__) -+ msg_ginfo(" GCC"); -+#ifdef __VERSION__ -+ msg_ginfo(" %s", __VERSION__); -+#else -+ msg_ginfo(" unknown version"); -+#endif -+#else -+ msg_ginfo(" unknown compiler"); -+#endif -+ msg_ginfo("\n"); - } - - void print_version(void) - { -- printf("flashrom v%s\n", flashrom_version); -+ printf("flashrom v%s", flashrom_version); -+ print_sysinfo(); - } - --int main(int argc, char *argv[]) -+int selfcheck(void) - { -- uint8_t *buf; -- unsigned long size, numbytes; -- FILE *image; -- /* Probe for up to three flash chips. */ -- struct flashchip *flash, *flashes[3]; -- const char *name; -- int namelen; -- int opt; -- int option_index = 0; -- int force = 0; -- int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; -- int dont_verify_it = 0, list_supported = 0, list_supported_wiki = 0; -- int operation_specified = 0; -- int ret = 0, i; -- -- static struct option long_options[] = { -- {"read", 0, 0, 'r'}, -- {"write", 0, 0, 'w'}, -- {"erase", 0, 0, 'E'}, -- {"verify", 0, 0, 'v'}, -- {"noverify", 0, 0, 'n'}, -- {"chip", 1, 0, 'c'}, -- {"mainboard", 1, 0, 'm'}, -- {"verbose", 0, 0, 'V'}, -- {"force", 0, 0, 'f'}, -- {"layout", 1, 0, 'l'}, -- {"image", 1, 0, 'i'}, -- {"list-supported", 0, 0, 'L'}, -- {"list-supported-wiki", 0, 0, 'z'}, -- {"programmer", 1, 0, 'p'}, -- {"help", 0, 0, 'h'}, -- {"version", 0, 0, 'R'}, -- {0, 0, 0, 0} -- }; -- -- char *filename = NULL; -- -- char *tempstr = NULL, *tempstr2 = NULL; -- -- print_version(); -- -- if (argc > 1) { -- /* Yes, print them. */ -- int i; -- printf_debug("The arguments are:\n"); -- for (i = 1; i < argc; ++i) -- printf_debug("%s\n", argv[i]); -- } -+ int ret = 0; -+ struct flashchip *flash; - -- /* Safety check. */ -+ /* Safety check. Instead of aborting after the first error, check -+ * if more errors exist. -+ */ - if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) { - fprintf(stderr, "Programmer table miscompilation!\n"); -- exit(1); -+ ret = 1; - } - if (spi_programmer_count - 1 != SPI_CONTROLLER_INVALID) { - fprintf(stderr, "SPI programmer table miscompilation!\n"); -- exit(1); -+ ret = 1; - } -- -- setbuf(stdout, NULL); -- while ((opt = getopt_long(argc, argv, "rRwvnVEfc:m:l:i:p:Lzh", -- long_options, &option_index)) != EOF) { -- switch (opt) { -- case 'r': -- if (++operation_specified > 1) { -- fprintf(stderr, "More than one operation " -- "specified. Aborting.\n"); -- exit(1); -- } -- read_it = 1; -- break; -- case 'w': -- if (++operation_specified > 1) { -- fprintf(stderr, "More than one operation " -- "specified. Aborting.\n"); -- exit(1); -- } -- write_it = 1; -- break; -- case 'v': -- if (++operation_specified > 1) { -- fprintf(stderr, "More than one operation " -- "specified. Aborting.\n"); -- exit(1); -- } -- verify_it = 1; -- break; -- case 'n': -- dont_verify_it = 1; -- break; -- case 'c': -- chip_to_probe = strdup(optarg); -- break; -- case 'V': -- verbose = 1; -- break; -- case 'E': -- if (++operation_specified > 1) { -- fprintf(stderr, "More than one operation " -- "specified. Aborting.\n"); -- exit(1); -- } -- erase_it = 1; -- break; -- case 'm': -- tempstr = strdup(optarg); -- strtok(tempstr, ":"); -- tempstr2 = strtok(NULL, ":"); -- if (tempstr2) { -- lb_vendor = tempstr; -- lb_part = tempstr2; -- } else { -- lb_vendor = NULL; -- lb_part = tempstr; -- } -- break; -- case 'f': -- force = 1; -- break; -- case 'l': -- tempstr = strdup(optarg); -- if (read_romlayout(tempstr)) -- exit(1); -- break; -- case 'i': -- tempstr = strdup(optarg); -- find_romentry(tempstr); -- break; -- case 'L': -- list_supported = 1; -- break; -- case 'z': -- list_supported_wiki = 1; -- break; -- case 'p': -- for (programmer = 0; programmer < PROGRAMMER_INVALID; programmer++) { -- name = programmer_table[programmer].name; -- namelen = strlen(name); -- if (strncmp(optarg, name, namelen) == 0) { -- switch (optarg[namelen]) { -- case ':': -- programmer_param = strdup(optarg + namelen + 1); -- break; -- case '\0': -- break; -- default: -- /* The continue refers to the -- * for loop. It is here to be -- * able to differentiate between -- * foo and foobar. -- */ -- continue; -- } -- break; -- } -- } -- if (programmer == PROGRAMMER_INVALID) { -- printf("Error: Unknown programmer %s.\n", optarg); -- exit(1); -- } -- break; -- case 'R': -- /* print_version() is always called during startup. */ -- exit(0); -- break; -- case 'h': -- default: -- usage(argv[0]); -- break; -- } -- } -- -- if (list_supported) { -- print_supported_chips(); -- print_supported_chipsets(); -- print_supported_boards(); -- printf("\nSupported PCI devices flashrom can use " -- "as programmer:\n\n"); -- print_supported_pcidevs(nics_3com); -- print_supported_pcidevs(satas_sii); -- exit(0); -- } -- -- if (list_supported_wiki) { -- print_wiki_tables(); -- exit(0); -- } -- -- if (read_it && write_it) { -- printf("Error: -r and -w are mutually exclusive.\n"); -- usage(argv[0]); -- } -- -- if (optind < argc) -- filename = argv[optind++]; -- -- if (programmer_init()) { -- fprintf(stderr, "Error: Programmer initialization failed.\n"); -- exit(1); -- } -- -- myusec_calibrate_delay(); -- -- for (i = 0; i < ARRAY_SIZE(flashes); i++) { -- flashes[i] = -- probe_flash(i ? flashes[i - 1] + 1 : flashchips, 0); -- if (!flashes[i]) -- for (i++; i < ARRAY_SIZE(flashes); i++) -- flashes[i] = NULL; -- } -- -- if (flashes[1]) { -- printf("Multiple flash chips were detected:"); -- for (i = 0; i < ARRAY_SIZE(flashes) && flashes[i]; i++) -- printf(" %s", flashes[i]->name); -- printf("\nPlease specify which chip to use with the -c option.\n"); -- exit(1); -- } else if (!flashes[0]) { -- printf("No EEPROM/flash device found.\n"); -- if (!force || !chip_to_probe) { -- printf("If you know which flash chip you have, and if this version of flashrom\n"); -- printf("supports a similar flash chip, you can try to force read your chip. Run:\n"); -- printf("flashrom -f -r -c similar_supported_flash_chip filename\n"); -- printf("\n"); -- printf("Note: flashrom can never write when the flash chip isn't found automatically.\n"); -- } -- if (force && read_it && chip_to_probe) { -- printf("Force read (-f -r -c) requested, forcing chip probe success:\n"); -- flashes[0] = probe_flash(flashchips, 1); -- if (!flashes[0]) { -- printf("flashrom does not support a flash chip named '%s'.\n", chip_to_probe); -- printf("Run flashrom -L to view the hardware supported in this flashrom version.\n"); -- exit(1); -- } -- printf("Please note that forced reads most likely contain garbage.\n"); -- return read_flash(flashes[0], filename); -- } -- // FIXME: flash writes stay enabled! -- exit(1); -+#if BITBANG_SPI_SUPPORT == 1 -+ if (bitbang_spi_master_count - 1 != BITBANG_SPI_INVALID) { -+ fprintf(stderr, "Bitbanging SPI master table miscompilation!\n"); -+ ret = 1; - } -+#endif -+ for (flash = flashchips; flash && flash->name; flash++) -+ if (selfcheck_eraseblocks(flash)) -+ ret = 1; -+ return ret; -+} - -- flash = flashes[0]; -- -+void check_chip_supported(struct flashchip *flash) -+{ - if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) { - printf("===\n"); - if (flash->tested & TEST_BAD_MASK) { -@@ -840,29 +1235,32 @@ int main(int argc, char *argv[]) - printf(" WRITE"); - printf("\n"); - } -+ /* FIXME: This message is designed towards CLI users. */ - printf("Please email a report to flashrom@flashrom.org if any " - "of the above operations\nwork correctly for you with " - "this flash part. Please include the flashrom\noutput " - "with the additional -V option for all operations you " - "tested (-V, -rV,\n-wV, -EV), and mention which " -- "mainboard you tested. Thanks for your help!\n===\n"); -- } -- -- if (!(read_it | write_it | verify_it | erase_it)) { -- printf("No operations were specified.\n"); -- // FIXME: flash writes stay enabled! -- exit(1); -+ "mainboard or programmer you tested.\nThanks for your " -+ "help!\n===\n"); - } -+} - -- if (!filename && !erase_it) { -- printf("Error: No filename specified.\n"); -- // FIXME: flash writes stay enabled! -- exit(1); -- } -+int main(int argc, char *argv[]) -+{ -+ return cli_classic(argc, argv); -+} - -- /* Always verify write operations unless -n is used. */ -- if (write_it && !dont_verify_it) -- verify_it = 1; -+/* This function signature is horrible. We need to design a better interface, -+ * but right now it allows us to split off the CLI code. -+ */ -+int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it) -+{ -+ uint8_t *buf; -+ unsigned long numbytes; -+ FILE *image; -+ int ret = 0; -+ unsigned long size; - - size = flash->total_size * 1024; - buf = (uint8_t *) calloc(size, sizeof(char)); -@@ -872,26 +1270,40 @@ int main(int argc, char *argv[]) - fprintf(stderr, "Erase is not working on this chip. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); -+ programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); - } - } -+ if (flash->unlock) -+ flash->unlock(flash); -+ - if (erase_flash(flash)) { - emergency_help_message(); -+ programmer_shutdown(); - return 1; - } - } else if (read_it) { -- if (read_flash(flash, filename)) -+ if (flash->unlock) -+ flash->unlock(flash); -+ -+ if (read_flash(flash, filename)) { -+ programmer_shutdown(); - return 1; -+ } - } else { - struct stat image_stat; - -+ if (flash->unlock) -+ flash->unlock(flash); -+ - if (flash->tested & TEST_BAD_ERASE) { - fprintf(stderr, "Erase is not working on this chip " - "and erase is needed for write. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); -+ programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); -@@ -901,29 +1313,36 @@ int main(int argc, char *argv[]) - fprintf(stderr, "Write is not working on this chip. "); - if (!force) { - fprintf(stderr, "Aborting.\n"); -+ programmer_shutdown(); - return 1; - } else { - fprintf(stderr, "Continuing anyway.\n"); - } - } -- if ((image = fopen(filename, "r")) == NULL) { -+ if ((image = fopen(filename, "rb")) == NULL) { - perror(filename); -+ programmer_shutdown(); - exit(1); - } - if (fstat(fileno(image), &image_stat) != 0) { - perror(filename); -+ programmer_shutdown(); - exit(1); - } - if (image_stat.st_size != flash->total_size * 1024) { - fprintf(stderr, "Error: Image size doesn't match\n"); -+ programmer_shutdown(); - exit(1); - } - - numbytes = fread(buf, 1, size, image); -+#if INTERNAL_SUPPORT == 1 - show_id(buf, size, force); -+#endif - fclose(image); - if (numbytes != size) { - fprintf(stderr, "Error: Failed to read file. Got %ld bytes, wanted %ld!\n", numbytes, size); -+ programmer_shutdown(); - return 1; - } - } -@@ -938,12 +1357,14 @@ int main(int argc, char *argv[]) - printf("Writing flash chip... "); - if (!flash->write) { - fprintf(stderr, "Error: flashrom has no write function for this flash chip.\n"); -+ programmer_shutdown(); - return 1; - } - ret = flash->write(flash, buf); - if (ret) { - fprintf(stderr, "FAILED!\n"); - emergency_help_message(); -+ programmer_shutdown(); - return 1; - } else { - printf("COMPLETE.\n"); -@@ -955,7 +1376,7 @@ int main(int argc, char *argv[]) - if (write_it) - programmer_delay(1000*1000); - ret = verify_flash(flash, buf); -- /* If we tried to write, and now we don't properly verify, we -+ /* If we tried to write, and verification now fails, we - * might have an emergency situation. - */ - if (ret && write_it) -diff --git a/ft2232_spi.c b/ft2232_spi.c -index 00490fe..97b4867 100644 ---- a/ft2232_spi.c -+++ b/ft2232_spi.c -@@ -26,18 +26,24 @@ - #include - #include - #include "flash.h" -+#include "chipdrivers.h" - #include "spi.h" - #include - --/* the 'H' chips can run internally at either 12Mhz or 60Mhz. -- * the non-H chips can only run at 12Mhz. */ -+/* -+ * The 'H' chips can run internally at either 12MHz or 60MHz. -+ * The non-H chips can only run at 12MHz. -+ */ - #define CLOCK_5X 1 - --/* in either case, the divisor is a simple integer clock divider. -- * if CLOCK_5X is set, this divisor divides 30Mhz, else it -- * divides 6Mhz */ --#define DIVIDE_BY 3 // e.g. '3' will give either 10Mhz or 2Mhz spi clock -+/* -+ * In either case, the divisor is a simple integer clock divider. -+ * If CLOCK_5X is set, this divisor divides 30MHz, else it divides 6MHz. -+ */ -+#define DIVIDE_BY 3 /* e.g. '3' will give either 10MHz or 2MHz SPI clock. */ - -+#define BITMODE_BITBANG_NORMAL 1 -+#define BITMODE_BITBANG_SPI 2 - - static struct ftdi_context ftdic_context; - -@@ -46,7 +52,7 @@ int send_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) - int r; - r = ftdi_write_data(ftdic, (unsigned char *) buf, size); - if (r < 0) { -- fprintf(stderr, "ftdi_write_data: %d, %s\n", r, -+ msg_perr("ftdi_write_data: %d, %s\n", r, - ftdi_get_error_string(ftdic)); - return 1; - } -@@ -58,7 +64,7 @@ int get_buf(struct ftdi_context *ftdic, const unsigned char *buf, int size) - int r; - r = ftdi_read_data(ftdic, (unsigned char *) buf, size); - if (r < 0) { -- fprintf(stderr, "ftdi_read_data: %d, %s\n", r, -+ msg_perr("ftdi_read_data: %d, %s\n", r, - ftdi_get_error_string(ftdic)); - return 1; - } -@@ -70,14 +76,13 @@ int ft2232_spi_init(void) - int f; - struct ftdi_context *ftdic = &ftdic_context; - unsigned char buf[512]; -- unsigned char port_val = 0; - char *portpos = NULL; - int ft2232_type = FTDI_FT4232H; - enum ftdi_interface ft2232_interface = INTERFACE_B; - - if (ftdi_init(ftdic) < 0) { -- fprintf(stderr, "ftdi_init failed\n"); -- return EXIT_FAILURE; -+ msg_perr("ftdi_init failed\n"); -+ return EXIT_FAILURE; // TODO - } - - if (programmer_param && !strlen(programmer_param)) { -@@ -100,49 +105,49 @@ int ft2232_spi_init(void) - ft2232_interface = INTERFACE_B; - break; - default: -- fprintf(stderr, "Invalid interface specified, " -+ msg_perr("Invalid interface specified, " - "using default.\n"); - } - } - free(programmer_param); - } -- printf_debug("Using device type %s ", -+ msg_pdbg("Using device type %s ", - (ft2232_type == FTDI_FT2232H) ? "2232H" : "4232H"); -- printf_debug("interface %s\n", -+ msg_pdbg("interface %s\n", - (ft2232_interface == INTERFACE_A) ? "A" : "B"); - - f = ftdi_usb_open(ftdic, 0x0403, ft2232_type); - - if (f < 0 && f != -5) { -- fprintf(stderr, "Unable to open ftdi device: %d (%s)\n", f, -+ msg_perr("Unable to open FTDI device: %d (%s)\n", f, - ftdi_get_error_string(ftdic)); -- exit(-1); -+ exit(-1); // TODO - } - - if (ftdi_set_interface(ftdic, ft2232_interface) < 0) { -- fprintf(stderr, "Unable to select interface: %s\n", -+ msg_perr("Unable to select interface: %s\n", - ftdic->error_str); - } - - if (ftdi_usb_reset(ftdic) < 0) { -- fprintf(stderr, "Unable to reset ftdi device\n"); -+ msg_perr("Unable to reset FTDI device\n"); - } - - if (ftdi_set_latency_timer(ftdic, 2) < 0) { -- fprintf(stderr, "Unable to set latency timer\n"); -+ msg_perr("Unable to set latency timer\n"); - } - - if (ftdi_write_data_set_chunksize(ftdic, 512)) { -- fprintf(stderr, "Unable to set chunk size\n"); -+ msg_perr("Unable to set chunk size\n"); - } - -- if (ftdi_set_bitmode(ftdic, 0x00, 2) < 0) { -- fprintf(stderr, "Unable to set bitmode\n"); -+ if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) { -+ msg_perr("Unable to set bitmode to SPI\n"); - } - - #if CLOCK_5X -- printf_debug("Disable divide-by-5 front stage\n"); -- buf[0] = 0x8a; /* disable divide-by-5 */ -+ msg_pdbg("Disable divide-by-5 front stage\n"); -+ buf[0] = 0x8a; /* Disable divide-by-5. */ - if (send_buf(ftdic, buf, 1)) - return -1; - #define MPSSE_CLK 60.0 -@@ -152,37 +157,36 @@ int ft2232_spi_init(void) - #define MPSSE_CLK 12.0 - - #endif -- printf_debug("Set clock divisor\n"); -+ msg_pdbg("Set clock divisor\n"); - buf[0] = 0x86; /* command "set divisor" */ - /* valueL/valueH are (desired_divisor - 1) */ -- buf[1] = (DIVIDE_BY-1) & 0xff; -- buf[2] = ((DIVIDE_BY-1) >> 8) & 0xff; -+ buf[1] = (DIVIDE_BY - 1) & 0xff; -+ buf[2] = ((DIVIDE_BY - 1) >> 8) & 0xff; - if (send_buf(ftdic, buf, 3)) - return -1; - -- printf("SPI clock is %fMHz\n", -- (double)(MPSSE_CLK / (((DIVIDE_BY-1) + 1) * 2))); -+ msg_pdbg("SPI clock is %fMHz\n", -+ (double)(MPSSE_CLK / (((DIVIDE_BY - 1) + 1) * 2))); - -- /* Disconnect TDI/DO to TDO/DI for Loopback */ -- printf_debug("No loopback of tdi/do tdo/di\n"); -+ /* Disconnect TDI/DO to TDO/DI for loopback. */ -+ msg_pdbg("No loopback of TDI/DO TDO/DI\n"); - buf[0] = 0x85; - if (send_buf(ftdic, buf, 1)) - return -1; - -- printf_debug("Set data bits\n"); -+ msg_pdbg("Set data bits\n"); - /* Set data bits low-byte command: - * value: 0x08 CS=high, DI=low, DO=low, SK=low - * dir: 0x0b CS=output, DI=input, DO=output, SK=output - */ - #define CS_BIT 0x08 -- - buf[0] = SET_BITS_LOW; -- buf[1] = (port_val = CS_BIT); -+ buf[1] = CS_BIT; - buf[2] = 0x0b; - if (send_buf(ftdic, buf, 3)) - return -1; - -- printf_debug("\nft2232 chosen\n"); -+ // msg_pdbg("\nft2232 chosen\n"); - - buses_supported = CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_FT2232; -@@ -195,39 +199,47 @@ int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, - { - struct ftdi_context *ftdic = &ftdic_context; - static unsigned char *buf = NULL; -- unsigned char port_val = 0; -- int i, ret = 0; -+ /* failed is special. We use bitwise ops, but it is essentially bool. */ -+ int i = 0, ret = 0, failed = 0; -+ int bufsize; -+ static int oldbufsize = 0; - - if (writecnt > 65536 || readcnt > 65536) - return SPI_INVALID_LENGTH; - -- buf = realloc(buf, writecnt + readcnt + 100); -- if (!buf) { -- fprintf(stderr, "Out of memory!\n"); -- exit(1); -+ /* buf is not used for the response from the chip. */ -+ bufsize = max(writecnt + 9, 260 + 9); -+ /* Never shrink. realloc() calls are expensive. */ -+ if (bufsize > oldbufsize) { -+ buf = realloc(buf, bufsize); -+ if (!buf) { -+ msg_perr("Out of memory!\n"); -+ exit(1); -+ } -+ oldbufsize = bufsize; - } - -- i = 0; -- -- /* minimize USB transfers by packing as many commands -- * as possible together. if we're not expecting to -- * read, we can assert CS, write, and deassert CS all -- * in one shot. if reading, we do three separate -- * operations. */ -- printf_debug("Assert CS#\n"); -+ /* -+ * Minimize USB transfers by packing as many commands as possible -+ * together. If we're not expecting to read, we can assert CS#, write, -+ * and deassert CS# all in one shot. If reading, we do three separate -+ * operations. -+ */ -+ msg_pspew("Assert CS#\n"); - buf[i++] = SET_BITS_LOW; -- buf[i++] = (port_val &= ~CS_BIT); -+ buf[i++] = 0 & ~CS_BIT; /* assertive */ - buf[i++] = 0x0b; - - if (writecnt) { - buf[i++] = 0x11; - buf[i++] = (writecnt - 1) & 0xff; - buf[i++] = ((writecnt - 1) >> 8) & 0xff; -- memcpy(buf+i, writearr, writecnt); -+ memcpy(buf + i, writearr, writecnt); - i += writecnt; - } - -- /* optionally terminate this batch of commands with a -+ /* -+ * Optionally terminate this batch of commands with a - * read command, then do the fetch of the results. - */ - if (readcnt) { -@@ -235,26 +247,36 @@ int ft2232_spi_send_command(unsigned int writecnt, unsigned int readcnt, - buf[i++] = (readcnt - 1) & 0xff; - buf[i++] = ((readcnt - 1) >> 8) & 0xff; - ret = send_buf(ftdic, buf, i); -+ failed = ret; -+ /* We can't abort here, we still have to deassert CS#. */ -+ if (ret) -+ msg_perr("send_buf failed before read: %i\n", -+ ret); - i = 0; -- if (ret) goto deassert_cs; -- -- /* FIXME: This is unreliable. There's no guarantee that we read -- * the response directly after sending the read command. -- * We may be scheduled out etc. -- */ -- ret = get_buf(ftdic, readarr, readcnt); -- -+ if (ret == 0) { -+ /* -+ * FIXME: This is unreliable. There's no guarantee that -+ * we read the response directly after sending the read -+ * command. We may be scheduled out etc. -+ */ -+ ret = get_buf(ftdic, readarr, readcnt); -+ failed |= ret; -+ /* We can't abort here either. */ -+ if (ret) -+ msg_perr("get_buf failed: %i\n", ret); -+ } - } - --deassert_cs: -- printf_debug("De-assert CS#\n"); -+ msg_pspew("De-assert CS#\n"); - buf[i++] = SET_BITS_LOW; -- buf[i++] = (port_val |= CS_BIT); -+ buf[i++] = CS_BIT; - buf[i++] = 0x0b; -- if (send_buf(ftdic, buf, i)) -- return -1; -+ ret = send_buf(ftdic, buf, i); -+ failed |= ret; -+ if (ret) -+ msg_perr("send_buf failed at end: %i\n", ret); - -- return ret; -+ return failed ? -1 : 0; - } - - int ft2232_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) -@@ -269,14 +291,14 @@ int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) - int i; - - spi_disable_blockprotect(); -- /* Erase first */ -- printf("Erasing flash before programming... "); -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ /* Erase first. */ -+ msg_pinfo("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ msg_perr("ERASE FAILED!\n"); - return -1; - } -- printf("done.\n"); -- printf_debug("total_size is %d\n", total_size); -+ msg_pinfo("done.\n"); -+ msg_pdbg("total_size is %d\n", total_size); - for (i = 0; i < total_size; i += 256) { - int l, r; - if (i + 256 <= total_size) -@@ -285,10 +307,10 @@ int ft2232_spi_write_256(struct flashchip *flash, uint8_t *buf) - l = total_size - i; - - if ((r = spi_nbyte_program(i, &buf[i], l))) { -- fprintf(stderr, "%s: write fail %d\n", __FUNCTION__, r); -+ msg_perr("%s: write fail %d\n", __func__, r); - return 1; - } -- -+ - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - /* loop */; - } -diff --git a/gfxnvidia.c b/gfxnvidia.c -new file mode 100644 -index 0000000..ec41279 ---- /dev/null -+++ b/gfxnvidia.c -@@ -0,0 +1,104 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Uwe Hermann -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include "flash.h" -+ -+#define PCI_VENDOR_ID_NVIDIA 0x10de -+ -+uint8_t *nvidia_bar; -+ -+struct pcidev_status gfx_nvidia[] = { -+ {0x10de, 0x0010, NT, "NVIDIA", "Mutara V08 [NV2]" }, -+ {0x10de, 0x0018, NT, "NVIDIA", "RIVA 128" }, -+ {0x10de, 0x0020, NT, "NVIDIA", "RIVA TNT" }, -+ {0x10de, 0x0028, NT, "NVIDIA", "RIVA TNT2/TNT2 Pro" }, -+ {0x10de, 0x0029, NT, "NVIDIA", "RIVA TNT2 Ultra" }, -+ {0x10de, 0x002c, NT, "NVIDIA", "Vanta/Vanta LT" }, -+ {0x10de, 0x002d, OK, "NVIDIA", "RIVA TNT2 Model 64/Model 64 Pro" }, -+ {0x10de, 0x00a0, NT, "NVIDIA", "Aladdin TNT2" }, -+ {0x10de, 0x0100, NT, "NVIDIA", "GeForce 256" }, -+ {0x10de, 0x0101, NT, "NVIDIA", "GeForce DDR" }, -+ {0x10de, 0x0103, NT, "NVIDIA", "Quadro" }, -+ {0x10de, 0x0110, NT, "NVIDIA", "GeForce2 MX" }, -+ {0x10de, 0x0111, NT, "NVIDIA", "GeForce2 MX" }, -+ {0x10de, 0x0112, NT, "NVIDIA", "GeForce2 GO" }, -+ {0x10de, 0x0113, NT, "NVIDIA", "Quadro2 MXR" }, -+ {0x10de, 0x0150, NT, "NVIDIA", "GeForce2 GTS/Pro" }, -+ {0x10de, 0x0151, NT, "NVIDIA", "GeForce2 GTS" }, -+ {0x10de, 0x0152, NT, "NVIDIA", "GeForce2 Ultra" }, -+ {0x10de, 0x0153, NT, "NVIDIA", "Quadro2 Pro" }, -+ {0x10de, 0x0200, NT, "NVIDIA", "GeForce 3 nFX" }, -+ {0x10de, 0x0201, NT, "NVIDIA", "GeForce 3 nFX" }, -+ {0x10de, 0x0202, NT, "NVIDIA", "GeForce 3 nFX Ultra" }, -+ {0x10de, 0x0203, NT, "NVIDIA", "Quadro 3 DDC" }, -+ -+ {}, -+}; -+ -+int gfxnvidia_init(void) -+{ -+ uint32_t reg32; -+ -+ get_io_perms(); -+ -+ io_base_addr = pcidev_init(PCI_VENDOR_ID_NVIDIA, PCI_BASE_ADDRESS_0, -+ gfx_nvidia, programmer_param); -+ io_base_addr += 0x300000; -+ msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); -+ -+ /* Allow access to flash interface (will disable screen). */ -+ reg32 = pci_read_long(pcidev_dev, 0x50); -+ reg32 &= ~(1 << 0); -+ pci_write_long(pcidev_dev, 0x50, reg32); -+ -+ nvidia_bar = physmap("NVIDIA", io_base_addr, 16 * 1024 * 1024); -+ -+ buses_supported = CHIP_BUSTYPE_PARALLEL; -+ -+ return 0; -+} -+ -+int gfxnvidia_shutdown(void) -+{ -+ uint32_t reg32; -+ -+ /* Disallow access to flash interface (and re-enable screen). */ -+ reg32 = pci_read_long(pcidev_dev, 0x50); -+ reg32 |= (1 << 0); -+ pci_write_long(pcidev_dev, 0x50, reg32); -+ -+ free(programmer_param); -+ pci_cleanup(pacc); -+ release_io_perms(); -+ return 0; -+} -+ -+void gfxnvidia_chip_writeb(uint8_t val, chipaddr addr) -+{ -+ mmio_writeb(val, nvidia_bar + addr); -+} -+ -+uint8_t gfxnvidia_chip_readb(const chipaddr addr) -+{ -+ return mmio_readb(nvidia_bar + addr); -+} -diff --git a/hwaccess.c b/hwaccess.c -new file mode 100644 -index 0000000..36ea6f4 ---- /dev/null -+++ b/hwaccess.c -@@ -0,0 +1,85 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "flash.h" -+ -+#if defined(__FreeBSD__) || defined(__DragonFly__) -+int io_fd; -+#endif -+ -+void get_io_perms(void) -+{ -+#if defined (__sun) && (defined(__i386) || defined(__amd64)) -+ if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) { -+#elif defined(__FreeBSD__) || defined (__DragonFly__) -+ if ((io_fd = open("/dev/io", O_RDWR)) < 0) { -+#elif __DJGPP__ -+ if (0) { -+#else -+ if (iopl(3) != 0) { -+#endif -+ fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n" -+ "You need to be root.\n", strerror(errno)); -+ exit(1); -+ } -+} -+ -+void release_io_perms(void) -+{ -+#if defined(__FreeBSD__) || defined(__DragonFly__) -+ close(io_fd); -+#endif -+} -+ -+void mmio_writeb(uint8_t val, void *addr) -+{ -+ *(volatile uint8_t *) addr = val; -+} -+ -+void mmio_writew(uint16_t val, void *addr) -+{ -+ *(volatile uint16_t *) addr = val; -+} -+ -+void mmio_writel(uint32_t val, void *addr) -+{ -+ *(volatile uint32_t *) addr = val; -+} -+ -+uint8_t mmio_readb(void *addr) -+{ -+ return *(volatile uint8_t *) addr; -+} -+ -+uint16_t mmio_readw(void *addr) -+{ -+ return *(volatile uint16_t *) addr; -+} -+ -+uint32_t mmio_readl(void *addr) -+{ -+ return *(volatile uint32_t *) addr; -+} -diff --git a/hwaccess.h b/hwaccess.h -new file mode 100644 -index 0000000..7a76925 ---- /dev/null -+++ b/hwaccess.h -@@ -0,0 +1,165 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Carl-Daniel Hailfinger -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * Header file for hardware access and OS abstraction. Included from flash.h. -+ */ -+ -+#ifndef __HWACCESS_H__ -+#define __HWACCESS_H__ 1 -+ -+#if defined(__GLIBC__) -+#include -+#endif -+#if NEED_PCI == 1 -+#include -+#endif -+ -+/* for iopl and outb under Solaris */ -+#if defined (__sun) && (defined(__i386) || defined(__amd64)) -+#include -+#include -+#include -+#include -+#endif -+ -+#if (defined(__MACH__) && defined(__APPLE__)) -+#define __DARWIN__ -+#endif -+ -+#if defined(__FreeBSD__) || defined(__DragonFly__) -+ #include -+ #define off64_t off_t -+ #define lseek64 lseek -+ #define OUTB(x, y) do { u_int outb_tmp = (y); outb(outb_tmp, (x)); } while (0) -+ #define OUTW(x, y) do { u_int outw_tmp = (y); outw(outw_tmp, (x)); } while (0) -+ #define OUTL(x, y) do { u_int outl_tmp = (y); outl(outl_tmp, (x)); } while (0) -+ #define INB(x) __extension__ ({ u_int inb_tmp = (x); inb(inb_tmp); }) -+ #define INW(x) __extension__ ({ u_int inw_tmp = (x); inw(inw_tmp); }) -+ #define INL(x) __extension__ ({ u_int inl_tmp = (x); inl(inl_tmp); }) -+#else -+#if defined(__DARWIN__) -+ #include -+ #define off64_t off_t -+ #define lseek64 lseek -+#endif -+#if defined (__sun) && (defined(__i386) || defined(__amd64)) -+ /* Note different order for outb */ -+ #define OUTB(x,y) outb(y, x) -+ #define OUTW(x,y) outw(y, x) -+ #define OUTL(x,y) outl(y, x) -+ #define INB inb -+ #define INW inw -+ #define INL inl -+#else -+ -+#ifdef __DJGPP__ -+ -+#include -+ -+ #define OUTB(x,y) outportb(y, x) -+ #define OUTW(x,y) outportw(y, x) -+ #define OUTL(x,y) outportl(y, x) -+ -+ #define INB inportb -+ #define INW inportw -+ #define INL inportl -+ -+#else -+ -+ #define OUTB outb -+ #define OUTW outw -+ #define OUTL outl -+ #define INB inb -+ #define INW inw -+ #define INL inl -+ -+#endif -+ -+#endif -+#endif -+ -+#if defined(__NetBSD__) -+ #define off64_t off_t -+ #define lseek64 lseek -+ #if defined(__i386__) || defined(__x86_64__) -+ #include -+ #include -+ #if defined(__i386__) -+ #define iopl i386_iopl -+ #elif defined(__x86_64__) -+ #define iopl x86_64_iopl -+ #endif -+ #include -+ -+static inline void outb(uint8_t value, uint16_t port) -+{ -+ asm volatile ("outb %b0,%w1": :"a" (value), "Nd" (port)); -+} -+ -+static inline uint8_t inb(uint16_t port) -+{ -+ uint8_t value; -+ asm volatile ("inb %w1,%0":"=a" (value):"Nd" (port)); -+ return value; -+} -+ -+static inline void outw(uint16_t value, uint16_t port) -+{ -+ asm volatile ("outw %w0,%w1": :"a" (value), "Nd" (port)); -+} -+ -+static inline uint16_t inw(uint16_t port) -+{ -+ uint16_t value; -+ asm volatile ("inw %w1,%0":"=a" (value):"Nd" (port)); -+ return value; -+} -+ -+static inline void outl(uint32_t value, uint16_t port) -+{ -+ asm volatile ("outl %0,%w1": :"a" (value), "Nd" (port)); -+} -+ -+static inline uint32_t inl(uint16_t port) -+{ -+ uint32_t value; -+ asm volatile ("inl %1,%0":"=a" (value):"Nd" (port)); -+ return value; -+} -+ #endif -+#endif -+ -+#if !defined(__DARWIN__) && !defined(__FreeBSD__) && !defined(__DragonFly__) -+typedef struct { uint32_t hi, lo; } msr_t; -+msr_t rdmsr(int addr); -+int wrmsr(int addr, msr_t msr); -+#endif -+#if defined(__FreeBSD__) || defined(__DragonFly__) -+/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */ -+#undef rdmsr -+#undef wrmsr -+#define rdmsr freebsd_rdmsr -+#define wrmsr freebsd_wrmsr -+typedef struct { uint32_t hi, lo; } msr_t; -+msr_t freebsd_rdmsr(int addr); -+int freebsd_wrmsr(int addr, msr_t msr); -+#endif -+ -+#endif /* !__HWACCESS_H__ */ -diff --git a/ichspi.c b/ichspi.c -index 831dd9d..35b9dbd 100644 ---- a/ichspi.c -+++ b/ichspi.c -@@ -5,6 +5,7 @@ - * Copyright (C) 2008 Claus Gindhart - * Copyright (C) 2008 Dominik Geyer - * Copyright (C) 2008 coresystems GmbH -+ * Copyright (C) 2009 Carl-Daniel Hailfinger - * - * 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 -@@ -34,8 +35,20 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - #include "spi.h" - -+/* Change this to #define if you want lowlevel debugging of commands -+ * sent to the ICH/VIA SPI controller. -+ */ -+#undef COMM_DEBUG -+ -+#ifdef COMM_DEBUG -+#define msg_comm_debug printf_debug -+#else -+#define msg_comm_debug(...) do {} while (0) -+#endif -+ - /* ICH9 controller register definition */ - #define ICH9_REG_FADDR 0x08 /* 32 Bits */ - #define ICH9_REG_FDATA0 0x10 /* 64 Bytes */ -@@ -105,7 +118,7 @@ typedef struct _OPCODE { - uint8_t atomic; //Use preop: (0: none, 1: preop0, 2: preop1 - } OPCODE; - --/* Opcode definition: -+/* Suggested opcode definition: - * Preop 1: Write Enable - * Preop 2: Write Status register enable - * -@@ -115,7 +128,7 @@ typedef struct _OPCODE { - * OP 3: Read Status register - * OP 4: Read ID - * OP 5: Write Status register -- * OP 6: chip private (read JDEC id) -+ * OP 6: chip private (read JEDEC id) - * OP 7: Chip erase - */ - typedef struct _OPCODES { -@@ -156,6 +169,7 @@ struct preop_opcode_pair { - uint8_t opcode; - }; - -+/* List of opcodes which need preopcodes and matching preopcodes. Unused. */ - struct preop_opcode_pair pops[] = { - {JEDEC_WREN, JEDEC_BYTE_PROGRAM}, - {JEDEC_WREN, JEDEC_SE}, /* sector erase */ -@@ -163,24 +177,30 @@ struct preop_opcode_pair pops[] = { - {JEDEC_WREN, JEDEC_BE_D8}, /* block erase */ - {JEDEC_WREN, JEDEC_CE_60}, /* chip erase */ - {JEDEC_WREN, JEDEC_CE_C7}, /* chip erase */ -+ /* FIXME: WRSR requires either EWSR or WREN depending on chip type. */ -+ {JEDEC_WREN, JEDEC_WRSR}, - {JEDEC_EWSR, JEDEC_WRSR}, - {0,} - }; - -+/* Reasonable default configuration. Needs ad-hoc modifications if we -+ * encounter unlisted opcodes. Fun. -+ */ - OPCODES O_ST_M25P = { - { - JEDEC_WREN, -- 0}, -+ JEDEC_EWSR, -+ }, - { -- {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte -+ {JEDEC_BYTE_PROGRAM, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Write Byte - {JEDEC_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data -- {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector -+ {JEDEC_BE_D8, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 0}, // Erase Sector - {JEDEC_RDSR, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg - {JEDEC_REMS, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Electronic Manufacturer Signature -- {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register -+ {JEDEC_WRSR, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Write Status Register - {JEDEC_RDID, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID -- {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase -- } -+ {JEDEC_CE_C7, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 0}, // Bulk erase -+ } - }; - - OPCODES O_EXISTING = {}; -@@ -209,14 +229,15 @@ static int find_preop(OPCODES *op, uint8_t preop) - return -1; - } - -+/* Create a struct OPCODES based on what we find in the locked down chipset. */ - static int generate_opcodes(OPCODES * op) - { -- int a, b, i; -+ int a; - uint16_t preop, optype; - uint32_t opmenu[2]; - - if (op == NULL) { -- printf_debug("\n%s: null OPCODES pointer!\n", __FUNCTION__); -+ printf_debug("\n%s: null OPCODES pointer!\n", __func__); - return -1; - } - -@@ -235,7 +256,7 @@ static int generate_opcodes(OPCODES * op) - opmenu[1] = REGREAD32(ICH9_REG_OPMENU + 4); - break; - default: -- printf_debug("%s: unsupported chipset\n", __FUNCTION__); -+ printf_debug("%s: unsupported chipset\n", __func__); - return -1; - } - -@@ -257,17 +278,10 @@ static int generate_opcodes(OPCODES * op) - opmenu[1] >>= 8; - } - -- /* atomic (link opcode with required pre-op) */ -- for (a = 4; a < 8; a++) -+ /* No preopcodes used by default. */ -+ for (a = 0; a < 8; a++) - op->opcode[a].atomic = 0; - -- for (i = 0; pops[i].opcode; i++) { -- a = find_opcode(op, pops[i].opcode); -- b = find_preop(op, pops[i].preop); -- if ((a != -1) && (b != -1)) -- op->opcode[a].atomic = (uint8_t) ++b; -- } -- - return 0; - } - -@@ -317,7 +331,7 @@ int program_opcodes(OPCODES * op) - REGWRITE32(ICH9_REG_OPMENU + 4, opmenu[1]); - break; - default: -- printf_debug("%s: unsupported chipset\n", __FUNCTION__); -+ printf_debug("%s: unsupported chipset\n", __func__); - return -1; - } - -@@ -431,14 +445,15 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset, - temp16 |= ((uint16_t) (opcode_index & 0x07)) << 4; - - /* Handle Atomic */ -- if (op.atomic != 0) { -- /* Select atomic command */ -+ switch (op.atomic) { -+ case 2: -+ /* Select second preop. */ -+ temp16 |= SPIC_SPOP; -+ /* And fall through. */ -+ case 1: -+ /* Atomic command (preop+op) */ - temp16 |= SPIC_ACS; -- /* Select prefix opcode */ -- if ((op.atomic - 1) == 1) { -- /*Select prefix opcode 2 */ -- temp16 |= SPIC_SPOP; -- } -+ break; - } - - /* Start */ -@@ -521,7 +536,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, - - /* clear error status registers */ - temp32 |= (SSFS_CDS + SSFS_FCERR); -- /* USE 20 MhZ */ -+ /* Use 20 MHz */ - temp32 |= SSFC_SCF_20MHZ; - - if (datalength != 0) { -@@ -548,14 +563,15 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, - temp32 |= ((uint32_t) (opcode_index & 0x07)) << (8 + 4); - - /* Handle Atomic */ -- if (op.atomic != 0) { -- /* Select atomic command */ -+ switch (op.atomic) { -+ case 2: -+ /* Select second preop. */ -+ temp32 |= SSFC_SPOP; -+ /* And fall through. */ -+ case 1: -+ /* Atomic command (preop+op) */ - temp32 |= SSFC_ACS; -- /* Selct prefix opcode */ -- if ((op.atomic - 1) == 1) { -- /*Select prefix opcode 2 */ -- temp32 |= SSFC_SPOP; -- } -+ break; - } - - /* Start */ -@@ -598,19 +614,31 @@ static int run_opcode(OPCODE op, uint32_t offset, - { - switch (spi_controller) { - case SPI_CONTROLLER_VIA: -- if (datalength > 16) -+ if (datalength > 16) { -+ fprintf(stderr, "%s: Internal command size error for " -+ "opcode 0x%02x, got datalength=%i, want <=16\n", -+ __func__, op.opcode, datalength); - return SPI_INVALID_LENGTH; -+ } - return ich7_run_opcode(op, offset, datalength, data, 16); - case SPI_CONTROLLER_ICH7: -- if (datalength > 64) -+ if (datalength > 64) { -+ fprintf(stderr, "%s: Internal command size error for " -+ "opcode 0x%02x, got datalength=%i, want <=16\n", -+ __func__, op.opcode, datalength); - return SPI_INVALID_LENGTH; -+ } - return ich7_run_opcode(op, offset, datalength, data, 64); - case SPI_CONTROLLER_ICH9: -- if (datalength > 64) -+ if (datalength > 64) { -+ fprintf(stderr, "%s: Internal command size error for " -+ "opcode 0x%02x, got datalength=%i, want <=16\n", -+ __func__, op.opcode, datalength); - return SPI_INVALID_LENGTH; -+ } - return ich9_run_opcode(op, offset, datalength, data); - default: -- printf_debug("%s: unsupported chipset\n", __FUNCTION__); -+ printf_debug("%s: unsupported chipset\n", __func__); - } - - /* If we ever get here, something really weird happened */ -@@ -624,7 +652,7 @@ static int ich_spi_write_page(struct flashchip *flash, uint8_t * bytes, - uint32_t remaining = page_size; - int towrite; - -- printf_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n", -+ msg_comm_debug("ich_spi_write_page: offset=%d, number=%d, buf=%p\n", - offset, page_size, bytes); - - for (; remaining > 0; remaining -= towrite) { -@@ -658,20 +686,16 @@ int ich_spi_write_256(struct flashchip *flash, uint8_t * buf) - int maxdata = 64; - - spi_disable_blockprotect(); -+ /* Erase first */ -+ printf("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ fprintf(stderr, "ERASE FAILED!\n"); -+ return -1; -+ } -+ printf("done.\n"); - - printf("Programming page: \n"); -- - for (i = 0; i < total_size / erase_size; i++) { -- /* FIMXE: call the chip-specific spi_block_erase_XX instead. -- * For this, we need to add a block erase function to -- * struct flashchip. -- */ -- rc = spi_block_erase_d8(flash, i * erase_size, erase_size); -- if (rc) { -- printf("Error erasing block at 0x%x\n", i); -- break; -- } -- - if (spi_controller == SPI_CONTROLLER_VIA) - maxdata = 16; - -@@ -690,7 +714,6 @@ int ich_spi_write_256(struct flashchip *flash, uint8_t * buf) - int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - const unsigned char *writearr, unsigned char *readarr) - { -- int a; - int result; - int opcode_index = -1; - const unsigned char cmd = *writearr; -@@ -700,21 +723,54 @@ int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - int count; - - /* find cmd in opcodes-table */ -- for (a = 0; a < 8; a++) { -- if ((curopcodes->opcode[a]).opcode == cmd) { -- opcode_index = a; -- break; -- } -- } -- -- /* unknown / not programmed command */ -+ opcode_index = find_opcode(curopcodes, cmd); - if (opcode_index == -1) { -+ /* FIXME: Reprogram opcodes if possible. Autodetect type of -+ * opcode by checking readcnt/writecnt. -+ */ - printf_debug("Invalid OPCODE 0x%02x\n", cmd); - return SPI_INVALID_OPCODE; - } - - opcode = &(curopcodes->opcode[opcode_index]); - -+ /* The following valid writecnt/readcnt combinations exist: -+ * writecnt = 4, readcnt >= 0 -+ * writecnt = 1, readcnt >= 0 -+ * writecnt >= 4, readcnt = 0 -+ * writecnt >= 1, readcnt = 0 -+ * writecnt >= 1 is guaranteed for all commands. -+ */ -+ if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) && -+ (writecnt != 4)) { -+ fprintf(stderr, "%s: Internal command size error for opcode " -+ "0x%02x, got writecnt=%i, want =4\n", __func__, cmd, -+ writecnt); -+ return SPI_INVALID_LENGTH; -+ } -+ if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) && -+ (writecnt != 1)) { -+ fprintf(stderr, "%s: Internal command size error for opcode " -+ "0x%02x, got writecnt=%i, want =1\n", __func__, cmd, -+ writecnt); -+ return SPI_INVALID_LENGTH; -+ } -+ if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) && -+ (writecnt < 4)) { -+ fprintf(stderr, "%s: Internal command size error for opcode " -+ "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd, -+ writecnt); -+ return SPI_INVALID_LENGTH; -+ } -+ if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) || -+ (opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) && -+ (readcnt)) { -+ fprintf(stderr, "%s: Internal command size error for opcode " -+ "0x%02x, got readcnt=%i, want =0\n", __func__, cmd, -+ readcnt); -+ return SPI_INVALID_LENGTH; -+ } -+ - /* if opcode-type requires an address */ - if (opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS || - opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) { -@@ -742,22 +798,72 @@ int ich_spi_send_command(unsigned int writecnt, unsigned int readcnt, - return result; - } - --int ich_spi_send_multicommand(struct spi_command *spicommands) -+int ich_spi_send_multicommand(struct spi_command *cmds) - { - int ret = 0; -- while ((spicommands->writecnt || spicommands->readcnt) && !ret) { -- ret = ich_spi_send_command(spicommands->writecnt, spicommands->readcnt, -- spicommands->writearr, spicommands->readarr); -- /* This awful hack needs to be smarter. -- */ -- if ((ret == SPI_INVALID_OPCODE) && -- ((spicommands->writearr[0] == JEDEC_WREN) || -- (spicommands->writearr[0] == JEDEC_EWSR))) { -- printf_debug(" due to SPI master limitation, ignoring" -- " and hoping it will be run as PREOP\n"); -- ret = 0; -+ int i; -+ int oppos, preoppos; -+ for (; (cmds->writecnt || cmds->readcnt) && !ret; cmds++) { -+ if ((cmds + 1)->writecnt || (cmds + 1)->readcnt) { -+ /* Next command is valid. */ -+ preoppos = find_preop(curopcodes, cmds->writearr[0]); -+ oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); -+ if ((oppos == -1) && (preoppos != -1)) { -+ /* Current command is listed as preopcode in -+ * ICH struct OPCODES, but next command is not -+ * listed as opcode in that struct. -+ * Check for command sanity, then -+ * try to reprogram the ICH opcode list. -+ */ -+ if (find_preop(curopcodes, -+ (cmds + 1)->writearr[0]) != -1) { -+ fprintf(stderr, "%s: Two subsequent " -+ "preopcodes 0x%02x and 0x%02x, " -+ "ignoring the first.\n", -+ __func__, cmds->writearr[0], -+ (cmds + 1)->writearr[0]); -+ continue; -+ } -+ /* If the chipset is locked down, we'll fail -+ * during execution of the next command anyway. -+ * No need to bother with fixups. -+ */ -+ if (!ichspi_lock) { -+ printf_debug("%s: FIXME: Add on-the-fly" -+ " reprogramming of the " -+ "chipset opcode list.\n", -+ __func__); -+ /* FIXME: Reprogram opcode menu. -+ * Find a less-useful opcode, replace it -+ * with the wanted opcode, detect optype -+ * and reprogram the opcode menu. -+ * Update oppos so the next if-statement -+ * can do something useful. -+ */ -+ //curopcodes.opcode[lessusefulindex] = (cmds + 1)->writearr[0]); -+ //update_optypes(curopcodes); -+ //program_opcodes(curopcodes); -+ //oppos = find_opcode(curopcodes, (cmds + 1)->writearr[0]); -+ continue; -+ } -+ } -+ if ((oppos != -1) && (preoppos != -1)) { -+ /* Current command is listed as preopcode in -+ * ICH struct OPCODES and next command is listed -+ * as opcode in that struct. Match them up. -+ */ -+ curopcodes->opcode[oppos].atomic = preoppos + 1; -+ continue; -+ } -+ /* If none of the above if-statements about oppos or -+ * preoppos matched, this is a normal opcode. -+ */ - } -- spicommands++; -+ ret = ich_spi_send_command(cmds->writecnt, cmds->readcnt, -+ cmds->writearr, cmds->readarr); -+ /* Reset the type of all opcodes to non-atomic. */ -+ for (i = 0; i < 8; i++) -+ curopcodes->opcode[i].atomic = 0; - } - return ret; - } -diff --git a/internal.c b/internal.c -index a3b2ae5..39edd10 100644 ---- a/internal.c -+++ b/internal.c -@@ -27,10 +27,7 @@ - #include - #include "flash.h" - --#if defined(__FreeBSD__) || defined(__DragonFly__) --int io_fd; --#endif -- -+#if NEED_PCI == 1 - struct pci_dev *pci_dev_find_filter(struct pci_filter filter) - { - struct pci_dev *temp; -@@ -42,6 +39,26 @@ struct pci_dev *pci_dev_find_filter(struct pci_filter filter) - return NULL; - } - -+struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class) -+{ -+ struct pci_dev *temp; -+ struct pci_filter filter; -+ uint16_t tmp2; -+ -+ pci_filter_init(NULL, &filter); -+ filter.vendor = vendor; -+ -+ for (temp = pacc->devices; temp; temp = temp->next) -+ if (pci_filter_match(&filter, temp)) { -+ /* Read PCI class */ -+ tmp2 = pci_read_word(temp, 0x0a); -+ if (tmp2 == class) -+ return temp; -+ } -+ -+ return NULL; -+} -+ - struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device) - { - struct pci_dev *temp; -@@ -79,33 +96,47 @@ struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device, - - return NULL; - } -- --void get_io_perms(void) --{ --#if defined (__sun) && (defined(__i386) || defined(__amd64)) -- if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) { --#elif defined(__FreeBSD__) || defined (__DragonFly__) -- if ((io_fd = open("/dev/io", O_RDWR)) < 0) { --#else -- if (iopl(3) != 0) { - #endif -- fprintf(stderr, "ERROR: Could not get I/O privileges (%s).\n" -- "You need to be root.\n", strerror(errno)); -- exit(1); -- } --} - --void release_io_perms(void) -+#if INTERNAL_SUPPORT == 1 -+struct superio superio = {}; -+int force_boardenable = 0; -+ -+void probe_superio(void) - { --#if defined(__FreeBSD__) || defined(__DragonFly__) -- close(io_fd); -+ superio = probe_superio_ite(); -+#if 0 -+ /* Winbond Super I/O code is not yet available. */ -+ if (superio.vendor == SUPERIO_VENDOR_NONE) -+ superio = probe_superio_winbond(); - #endif - } - -+int is_laptop; -+ - int internal_init(void) - { - int ret = 0; - -+ if (programmer_param && !strlen(programmer_param)) { -+ free(programmer_param); -+ programmer_param = NULL; -+ } -+ if (programmer_param) { -+ char *arg; -+ arg = extract_param(&programmer_param, "boardenable=", ",:"); -+ if (arg && !strcmp(arg,"force")) -+ force_boardenable = 1; -+ else if (arg) -+ msg_perr("Unknown argument for boardenable: %s\n", arg); -+ free(arg); -+ -+ if (strlen(programmer_param)) -+ msg_perr("Unhandled programmer parameters: %s\n", -+ programmer_param); -+ free(programmer_param); -+ programmer_param = NULL; -+ } - get_io_perms(); - - /* Initialize PCI access for flash enables */ -@@ -118,6 +149,20 @@ int internal_init(void) - * mainboard specific flash enable sequence. - */ - coreboot_init(); -+ dmi_init(); -+ -+ /* Probe for the Super I/O chip and fill global struct superio. */ -+ probe_superio(); -+ -+ /* Warn if a laptop is detected. */ -+ if (is_laptop) -+ printf("========================================================================\n" -+ "WARNING! You seem to be running flashrom on a laptop.\n" -+ "Laptops, notebooks and netbooks are difficult to support and we recommend\n" -+ "to use the vendor flashing utility. The embedded controller (EC) in these\n" -+ "machines often interacts badly with flashing.\n" -+ "See http://www.flashrom.org/Laptops for details.\n" -+ "========================================================================\n"); - - /* try to enable it. Failure IS an option, since not all motherboards - * really need this to be done, etc., etc. -@@ -128,6 +173,9 @@ int internal_init(void) - "will most likely fail.\n"); - } - -+ /* Probe for IT87* LPC->SPI translation unconditionally. */ -+ it87xx_probe_spi_flash(NULL); -+ - board_flash_enable(lb_vendor, lb_part); - - /* Even if chipset init returns an error code, we don't want to abort. -@@ -143,6 +191,7 @@ int internal_shutdown(void) - - return 0; - } -+#endif - - void internal_chip_writeb(uint8_t val, chipaddr addr) - { -@@ -179,115 +228,3 @@ void internal_chip_readn(uint8_t *buf, const chipaddr addr, size_t len) - memcpy(buf, (void *)addr, len); - return; - } -- --void mmio_writeb(uint8_t val, void *addr) --{ -- *(volatile uint8_t *) addr = val; --} -- --void mmio_writew(uint16_t val, void *addr) --{ -- *(volatile uint16_t *) addr = val; --} -- --void mmio_writel(uint32_t val, void *addr) --{ -- *(volatile uint32_t *) addr = val; --} -- --uint8_t mmio_readb(void *addr) --{ -- return *(volatile uint8_t *) addr; --} -- --uint16_t mmio_readw(void *addr) --{ -- return *(volatile uint16_t *) addr; --} -- --uint32_t mmio_readl(void *addr) --{ -- return *(volatile uint32_t *) addr; --} -- --void internal_delay(int usecs) --{ -- /* If the delay is >1 s, use usleep because timing does not need to -- * be so precise. -- */ -- if (usecs > 1000000) { -- usleep(usecs); -- } else { -- myusec_delay(usecs); -- } --} -- --/* Fallback shutdown() for programmers which don't need special handling */ --int fallback_shutdown(void) --{ -- return 0; --} -- --/* Fallback map() for programmers which don't need special handling */ --void *fallback_map(const char *descr, unsigned long phys_addr, size_t len) --{ -- return 0; --} -- --/* Fallback unmap() for programmers which don't need special handling */ --void fallback_unmap(void *virt_addr, size_t len) --{ --} -- --/* No-op fallback for drivers not supporting addr/data pair accesses */ --void fallback_chip_writeb(uint8_t val, chipaddr addr) --{ --} -- --/* Little-endian fallback for drivers not supporting 16 bit accesses */ --void fallback_chip_writew(uint16_t val, chipaddr addr) --{ -- chip_writeb(val & 0xff, addr); -- chip_writeb((val >> 8) & 0xff, addr + 1); --} -- --/* Little-endian fallback for drivers not supporting 16 bit accesses */ --uint16_t fallback_chip_readw(const chipaddr addr) --{ -- uint16_t val; -- val = chip_readb(addr); -- val |= chip_readb(addr + 1) << 8; -- return val; --} -- --/* Little-endian fallback for drivers not supporting 32 bit accesses */ --void fallback_chip_writel(uint32_t val, chipaddr addr) --{ -- chip_writew(val & 0xffff, addr); -- chip_writew((val >> 16) & 0xffff, addr + 2); --} -- --/* Little-endian fallback for drivers not supporting 32 bit accesses */ --uint32_t fallback_chip_readl(const chipaddr addr) --{ -- uint32_t val; -- val = chip_readw(addr); -- val |= chip_readw(addr + 2) << 16; -- return val; --} -- --void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len) --{ -- size_t i; -- for (i = 0; i < len; i++) -- chip_writeb(buf[i], addr + i); -- return; --} -- --void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len) --{ -- size_t i; -- for (i = 0; i < len; i++) -- buf[i] = chip_readb(addr + i); -- return; --} -diff --git a/it87spi.c b/it87spi.c -index 299725c..0ee7d12 100644 ---- a/it87spi.c -+++ b/it87spi.c -@@ -26,6 +26,7 @@ - #include - #include - #include "flash.h" -+#include "chipdrivers.h" - #include "spi.h" - - #define ITE_SUPERIO_PORT1 0x2e -@@ -54,68 +55,122 @@ void exit_conf_mode_ite(uint16_t port) - sio_write(port, 0x02, 0x02); - } - --static uint16_t find_ite_spi_flash_port(uint16_t port) -+uint16_t probe_id_ite(uint16_t port) - { -- uint8_t tmp = 0; -- char *portpos = NULL; -- uint16_t id, flashport = 0; -+ uint16_t id; - - enter_conf_mode_ite(port); -- - id = sio_read(port, CHIP_ID_BYTE1_REG) << 8; - id |= sio_read(port, CHIP_ID_BYTE2_REG); -+ exit_conf_mode_ite(port); - -- /* TODO: Handle more IT87xx if they support flash translation */ -- if (0x8716 == id || 0x8718 == id) { -+ return id; -+} -+ -+struct superio probe_superio_ite(void) -+{ -+ struct superio ret = {}; -+ uint16_t ite_ports[] = {ITE_SUPERIO_PORT1, ITE_SUPERIO_PORT2, 0}; -+ uint16_t *i = ite_ports; -+ -+ ret.vendor = SUPERIO_VENDOR_ITE; -+ for (; *i; i++) { -+ ret.port = *i; -+ ret.model = probe_id_ite(ret.port); -+ switch (ret.model >> 8) { -+ case 0x82: -+ case 0x86: -+ case 0x87: -+ msg_pinfo("Found ITE Super I/O, id %04hx\n", -+ ret.model); -+ return ret; -+ } -+ } -+ -+ /* No good ID found. */ -+ ret.vendor = SUPERIO_VENDOR_NONE; -+ ret.port = 0; -+ ret.model = 0; -+ return ret; -+} -+ -+static uint16_t find_ite_spi_flash_port(uint16_t port, uint16_t id) -+{ -+ uint8_t tmp = 0; -+ char *portpos = NULL; -+ uint16_t flashport = 0; -+ -+ switch (id) { -+ case 0x8716: -+ case 0x8718: -+ case 0x8720: -+ enter_conf_mode_ite(port); - /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ - tmp = sio_read(port, 0x24) & 0xFE; -- printf("Serial flash segment 0x%08x-0x%08x %sabled\n", -+ /* If IT87SPI was not explicitly selected, we want to check -+ * quickly if LPC->SPI translation is active. -+ */ -+ if ((programmer == PROGRAMMER_INTERNAL) && !(tmp & (0x0E))) { -+ msg_pdbg("No IT87* serial flash segment enabled.\n"); -+ exit_conf_mode_ite(port); -+ break; -+ } -+ msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis"); -- printf("Serial flash segment 0x%08x-0x%08x %sabled\n", -+ msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis"); -- printf("Serial flash segment 0x%08x-0x%08x %sabled\n", -+ msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis"); -- printf("Serial flash segment 0x%08x-0x%08x %sabled\n", -+ msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", - 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis"); -- printf("LPC write to serial flash %sabled\n", -+ msg_pdbg("LPC write to serial flash %sabled\n", - (tmp & 1 << 4) ? "en" : "dis"); - /* The LPC->SPI force write enable below only makes sense for - * non-programmer mode. - */ - /* If any serial flash segment is enabled, enable writing. */ - if ((tmp & 0xe) && (!(tmp & 1 << 4))) { -- printf("Enabling LPC write to serial flash\n"); -+ msg_pdbg("Enabling LPC write to serial flash\n"); - tmp |= 1 << 4; - sio_write(port, 0x24, tmp); - } -- printf("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); -+ msg_pdbg("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); - /* LDN 0x7, reg 0x64/0x65 */ - sio_write(port, 0x07, 0x7); - flashport = sio_read(port, 0x64) << 8; - flashport |= sio_read(port, 0x65); -- printf("Serial flash port 0x%04x\n", flashport); -+ msg_pdbg("Serial flash port 0x%04x\n", flashport); - if (programmer_param && !strlen(programmer_param)) { - free(programmer_param); - programmer_param = NULL; - } -- if (programmer_param && (portpos = strstr(programmer_param, "port="))) { -- portpos += 5; -- flashport = strtol(portpos, (char **)NULL, 0); -- printf("Forcing serial flash port 0x%04x\n", flashport); -- sio_write(port, 0x64, (flashport >> 8)); -- sio_write(port, 0x65, (flashport & 0xff)); -+ if (programmer_param) { -+ portpos = extract_param(&programmer_param, -+ "it87spiport=", ",:"); -+ if (portpos) { -+ flashport = strtol(portpos, (char **)NULL, 0); -+ msg_pinfo("Forcing serial flash port 0x%04x\n", -+ flashport); -+ sio_write(port, 0x64, (flashport >> 8)); -+ sio_write(port, 0x65, (flashport & 0xff)); -+ free(portpos); -+ } - } -+ exit_conf_mode_ite(port); -+ break; -+ /* TODO: Handle more IT87xx if they support flash translation */ -+ default: -+ msg_pdbg("SuperI/O ID %04hx is not on the controller list.\n", id); - } -- exit_conf_mode_ite(port); - return flashport; - } - - int it87spi_common_init(void) - { -- it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT1); -+ if (superio.vendor != SUPERIO_VENDOR_ITE) -+ return 1; - -- if (!it8716f_flashport) -- it8716f_flashport = find_ite_spi_flash_port(ITE_SUPERIO_PORT2); -+ it8716f_flashport = find_ite_spi_flash_port(superio.port, superio.model); - - if (it8716f_flashport) - spi_controller = SPI_CONTROLLER_IT87XX; -@@ -129,6 +184,8 @@ int it87spi_init(void) - int ret; - - get_io_perms(); -+ /* Probe for the Super I/O chip and fill global struct superio. */ -+ probe_superio(); - ret = it87spi_common_init(); - if (!ret) { - buses_supported = CHIP_BUSTYPE_SPI; -@@ -143,8 +200,11 @@ int it87xx_probe_spi_flash(const char *name) - int ret; - - ret = it87spi_common_init(); -- if (!ret) -+ if (!ret) { -+ if (buses_supported & CHIP_BUSTYPE_SPI) -+ msg_pdbg("Overriding chipset SPI with IT87 SPI.\n"); - buses_supported |= CHIP_BUSTYPE_SPI; -+ } - return ret; - } - -@@ -167,8 +227,8 @@ int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, - busy = INB(it8716f_flashport) & 0x80; - } while (busy); - if (readcnt > 3) { -- printf("%s called with unsupported readcnt %i.\n", -- __FUNCTION__, readcnt); -+ msg_pinfo("%s called with unsupported readcnt %i.\n", -+ __func__, readcnt); - return SPI_INVALID_LENGTH; - } - switch (writecnt) { -@@ -197,8 +257,8 @@ int it8716f_spi_send_command(unsigned int writecnt, unsigned int readcnt, - writeenc = 0x3; - break; - default: -- printf("%s called with unsupported writecnt %i.\n", -- __FUNCTION__, writecnt); -+ msg_pinfo("%s called with unsupported writecnt %i.\n", -+ __func__, writecnt); - return SPI_INVALID_LENGTH; - } - /* -@@ -278,12 +338,12 @@ int it8716f_spi_chip_write_256(struct flashchip *flash, uint8_t *buf) - } else { - spi_disable_blockprotect(); - /* Erase first */ -- printf("Erasing flash before programming... "); -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_pinfo("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ msg_perr("ERASE FAILED!\n"); - return -1; - } -- printf("done.\n"); -+ msg_pinfo("done.\n"); - for (i = 0; i < total_size / 256; i++) { - it8716f_spi_page_program(flash, i, buf); - } -diff --git a/jedec.c b/jedec.c -index 0e426d6..30c343f 100644 ---- a/jedec.c -+++ b/jedec.c -@@ -5,6 +5,7 @@ - * Copyright (C) 2006 Giampiero Giancipoli - * Copyright (C) 2006 coresystems GmbH - * Copyright (C) 2007 Carl-Daniel Hailfinger -+ * Copyright (C) 2009 Sean Nelson - * - * 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 -@@ -22,8 +23,12 @@ - */ - - #include "flash.h" -+#include "chipdrivers.h" - - #define MAX_REFLASH_TRIES 0x10 -+#define MASK_FULL 0xffff -+#define MASK_2AA 0x7ff -+#define MASK_AAA 0xfff - - /* Check one byte for odd parity */ - uint8_t oddparity(uint8_t val) -@@ -33,7 +38,7 @@ uint8_t oddparity(uint8_t val) - return (val ^ (val >> 1)) & 0x1; - } - --void toggle_ready_jedec(chipaddr dst) -+void toggle_ready_jedec_common(chipaddr dst, int delay) - { - unsigned int i = 0; - uint8_t tmp1, tmp2; -@@ -41,12 +46,33 @@ void toggle_ready_jedec(chipaddr dst) - tmp1 = chip_readb(dst) & 0x40; - - while (i++ < 0xFFFFFFF) { -+ if (delay) -+ programmer_delay(delay); - tmp2 = chip_readb(dst) & 0x40; - if (tmp1 == tmp2) { - break; - } - tmp1 = tmp2; - } -+ if (i > 0x100000) -+ msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i); -+} -+ -+void toggle_ready_jedec(chipaddr dst) -+{ -+ toggle_ready_jedec_common(dst, 0); -+} -+ -+/* Some chips require a minimum delay between toggle bit reads. -+ * The Winbond W39V040C wants 50 ms between reads on sector erase toggle, -+ * but experiments show that 2 ms are already enough. Pick a safety factor -+ * of 4 and use an 8 ms delay. -+ * Given that erase is slow on all chips, it is recommended to use -+ * toggle_ready_jedec_slow in erase functions. -+ */ -+void toggle_ready_jedec_slow(chipaddr dst) -+{ -+ toggle_ready_jedec_common(dst, 8 * 1000); - } - - void data_polling_jedec(chipaddr dst, uint8_t data) -@@ -62,30 +88,19 @@ void data_polling_jedec(chipaddr dst, uint8_t data) - break; - } - } -+ if (i > 0x100000) -+ msg_cdbg("%s: excessive loops, i=0x%x\n", __func__, i); - } - --void unprotect_jedec(chipaddr bios) --{ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x80, bios + 0x5555); -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x20, bios + 0x5555); -- -- programmer_delay(200); --} -- --void protect_jedec(chipaddr bios) -+void start_program_jedec_common(struct flashchip *flash, unsigned int mask) - { -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -- -- programmer_delay(200); -+ chipaddr bios = flash->virtual_memory; -+ chip_writeb(0xAA, bios + (0x5555 & mask)); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); -+ chip_writeb(0xA0, bios + (0x5555 & mask)); - } - --int probe_jedec(struct flashchip *flash) -+int probe_jedec_common(struct flashchip *flash, unsigned int mask) - { - chipaddr bios = flash->virtual_memory; - uint8_t id1, id2; -@@ -98,26 +113,26 @@ int probe_jedec(struct flashchip *flash) - else if (flash->probe_timing == TIMING_ZERO) { /* No delay. */ - probe_timing_enter = probe_timing_exit = 0; - } else if (flash->probe_timing == TIMING_FIXME) { /* == _IGNORED */ -- printf_debug("Chip lacks correct probe timing information, " -+ msg_cdbg("Chip lacks correct probe timing information, " - "using default 10mS/40uS. "); - probe_timing_enter = 10000; - probe_timing_exit = 40; - } else { -- printf("Chip has negative value in probe_timing, failing " -+ msg_cerr("Chip has negative value in probe_timing, failing " - "without chip access\n"); - return 0; - } - - /* Issue JEDEC Product ID Entry command */ -- chip_writeb(0xAA, bios + 0x5555); -- programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -- programmer_delay(10); -- chip_writeb(0x90, bios + 0x5555); -- /* Older chips may need up to 100 us to respond. The ATMEL 29C020 -- * needs 10 ms according to the data sheet. -- */ -- programmer_delay(probe_timing_enter); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); -+ if (probe_timing_enter) -+ programmer_delay(10); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); -+ if (probe_timing_enter) -+ programmer_delay(10); -+ chip_writeb(0x90, bios + (0x5555 & mask)); -+ if (probe_timing_enter) -+ programmer_delay(probe_timing_enter); - - /* Read product ID */ - id1 = chip_readb(bios); -@@ -138,16 +153,22 @@ int probe_jedec(struct flashchip *flash) - } - - /* Issue JEDEC Product ID Exit command */ -- chip_writeb(0xAA, bios + 0x5555); -- programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -- programmer_delay(10); -- chip_writeb(0xF0, bios + 0x5555); -- programmer_delay(probe_timing_exit); -+ if ((flash->feature_bits & FEATURE_SHORT_RESET) == FEATURE_LONG_RESET) -+ { -+ chip_writeb(0xAA, bios + (0x5555 & mask)); -+ if (probe_timing_exit) -+ programmer_delay(10); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); -+ if (probe_timing_exit) -+ programmer_delay(10); -+ } -+ chip_writeb(0xF0, bios + (0x5555 & mask)); -+ if (probe_timing_exit) -+ programmer_delay(probe_timing_exit); - -- printf_debug("%s: id1 0x%02x, id2 0x%02x", __FUNCTION__, largeid1, largeid2); -+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2); - if (!oddparity(id1)) -- printf_debug(", id1 parity violation"); -+ msg_cdbg(", id1 parity violation"); - - /* Read the product ID location again. We should now see normal flash contents. */ - flashcontent1 = chip_readb(bios); -@@ -164,121 +185,171 @@ int probe_jedec(struct flashchip *flash) - } - - if (largeid1 == flashcontent1) -- printf_debug(", id1 is normal flash content"); -+ msg_cdbg(", id1 is normal flash content"); - if (largeid2 == flashcontent2) -- printf_debug(", id2 is normal flash content"); -+ msg_cdbg(", id2 is normal flash content"); -+ -+ msg_cdbg("\n"); -+ if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id) -+ return 0; - -- printf_debug("\n"); -- if (largeid1 == flash->manufacture_id && largeid2 == flash->model_id) -- return 1; -+ if (flash->feature_bits & FEATURE_REGISTERMAP) -+ map_flash_registers(flash); - -- return 0; -+ return 1; - } - --int erase_sector_jedec(struct flashchip *flash, unsigned int page, int pagesize) -+int erase_sector_jedec_common(struct flashchip *flash, unsigned int page, -+ unsigned int pagesize, unsigned int mask) - { - chipaddr bios = flash->virtual_memory; - - /* Issue the Sector Erase command */ -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); -- chip_writeb(0x80, bios + 0x5555); -+ chip_writeb(0x80, bios + (0x5555 & mask)); - programmer_delay(10); - -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); - chip_writeb(0x30, bios + page); - programmer_delay(10); - - /* wait for Toggle bit ready */ -- toggle_ready_jedec(bios); -+ toggle_ready_jedec_slow(bios); - - if (check_erased_range(flash, page, pagesize)) { -- fprintf(stderr,"ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --int erase_block_jedec(struct flashchip *flash, unsigned int block, int blocksize) -+int erase_block_jedec_common(struct flashchip *flash, unsigned int block, -+ unsigned int blocksize, unsigned int mask) - { - chipaddr bios = flash->virtual_memory; - - /* Issue the Sector Erase command */ -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); -- chip_writeb(0x80, bios + 0x5555); -+ chip_writeb(0x80, bios + (0x5555 & mask)); - programmer_delay(10); - -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); - chip_writeb(0x50, bios + block); - programmer_delay(10); - - /* wait for Toggle bit ready */ -- toggle_ready_jedec(bios); -+ toggle_ready_jedec_slow(bios); - - if (check_erased_range(flash, block, blocksize)) { -- fprintf(stderr,"ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --int erase_chip_jedec(struct flashchip *flash) -+int erase_chip_jedec_common(struct flashchip *flash, unsigned int mask) - { - int total_size = flash->total_size * 1024; - chipaddr bios = flash->virtual_memory; - - /* Issue the JEDEC Chip Erase command */ -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); -- chip_writeb(0x80, bios + 0x5555); -+ chip_writeb(0x80, bios + (0x5555 & mask)); - programmer_delay(10); - -- chip_writeb(0xAA, bios + 0x5555); -+ chip_writeb(0xAA, bios + (0x5555 & mask)); - programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -+ chip_writeb(0x55, bios + (0x2AAA & mask)); - programmer_delay(10); -- chip_writeb(0x10, bios + 0x5555); -+ chip_writeb(0x10, bios + (0x5555 & mask)); - programmer_delay(10); - -- toggle_ready_jedec(bios); -+ toggle_ready_jedec_slow(bios); - - if (check_erased_range(flash, 0, total_size)) { -- fprintf(stderr,"ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --int write_page_write_jedec(struct flashchip *flash, uint8_t *src, -- int start, int page_size) -+int write_byte_program_jedec_common(struct flashchip *flash, uint8_t *src, -+ chipaddr dst, unsigned int mask) - { -- int i, tried = 0, start_index = 0, ok; -+ int tried = 0, failed = 0; -+ chipaddr bios = flash->virtual_memory; -+ -+ /* If the data is 0xFF, don't program it and don't complain. */ -+ if (*src == 0xFF) { -+ return 0; -+ } -+ -+retry: -+ /* Issue JEDEC Byte Program command */ -+ start_program_jedec_common(flash, mask); -+ -+ /* transfer data from source to destination */ -+ chip_writeb(*src, dst); -+ toggle_ready_jedec(bios); -+ -+ if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) { -+ goto retry; -+ } -+ -+ if (tried >= MAX_REFLASH_TRIES) -+ failed = 1; -+ -+ return failed; -+} -+ -+int write_sector_jedec_common(struct flashchip *flash, uint8_t *src, -+ chipaddr dst, unsigned int page_size, unsigned int mask) -+{ -+ int i, failed = 0; -+ chipaddr olddst; -+ -+ olddst = dst; -+ for (i = 0; i < page_size; i++) { -+ if (write_byte_program_jedec_common(flash, src, dst, mask)) -+ failed = 1; -+ dst++, src++; -+ } -+ if (failed) -+ msg_cerr(" writing sector at 0x%lx failed!\n", olddst); -+ -+ return failed; -+} -+ -+int write_page_write_jedec_common(struct flashchip *flash, uint8_t *src, -+ int start, int page_size, unsigned int mask) -+{ -+ int i, tried = 0, failed; - uint8_t *s = src; - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios + start; - chipaddr d = dst; - - retry: -- /* Issue JEDEC Data Unprotect comand */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -+ /* Issue JEDEC Start Program command */ -+ start_program_jedec_common(flash, mask); - - /* transfer data from source to destination */ -- for (i = start_index; i < page_size; i++) { -+ for (i = 0; i < page_size; i++) { - /* If the data is 0xFF, don't program it */ - if (*src != 0xFF) - chip_writeb(*src, dst); -@@ -290,83 +361,138 @@ retry: - - dst = d; - src = s; -- ok = !verify_range(flash, src, start, page_size, NULL); -+ failed = verify_range(flash, src, start, page_size, NULL); - -- if (!ok && tried++ < MAX_REFLASH_TRIES) { -- start_index = i; -+ if (failed && tried++ < MAX_REFLASH_TRIES) { -+ msg_cerr("retrying.\n"); - goto retry; - } -- if (!ok) { -- fprintf(stderr, " page 0x%lx failed!\n", -+ if (failed) { -+ msg_cerr(" page 0x%lx failed!\n", - (d - bios) / page_size); - } -- return !ok; -+ return failed; - } - --int write_byte_program_jedec(chipaddr bios, uint8_t *src, -- chipaddr dst) -+int getaddrmask(struct flashchip *flash) - { -- int tried = 0, ok = 1; -- -- /* If the data is 0xFF, don't program it */ -- if (*src == 0xFF) { -- return -1; -+ switch (flash->feature_bits & FEATURE_ADDR_MASK) { -+ case FEATURE_ADDR_FULL: -+ return MASK_FULL; -+ break; -+ case FEATURE_ADDR_2AA: -+ return MASK_2AA; -+ break; -+ case FEATURE_ADDR_AAA: -+ return MASK_AAA; -+ break; -+ default: -+ msg_cerr("%s called with unknown mask\n", __func__); -+ return 0; -+ break; - } -+} - --retry: -- /* Issue JEDEC Byte Program command */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -+int write_jedec(struct flashchip *flash, uint8_t *buf) -+{ -+ int mask; -+ int i, failed = 0; -+ int total_size = flash->total_size * 1024; -+ int page_size = flash->page_size; - -- /* transfer data from source to destination */ -- chip_writeb(*src, dst); -- toggle_ready_jedec(bios); -+ mask = getaddrmask(flash); - -- if (chip_readb(dst) != *src && tried++ < MAX_REFLASH_TRIES) { -- goto retry; -+ if (erase_chip_jedec(flash)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; - } -+ -+ msg_cinfo("Programming page: "); -+ for (i = 0; i < total_size / page_size; i++) { -+ msg_cinfo("%04d at address: 0x%08x", i, i * page_size); -+ if (write_page_write_jedec_common(flash, buf + i * page_size, -+ i * page_size, page_size, mask)) -+ failed = 1; -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ } -+ msg_cinfo("DONE!\n"); - -- if (tried >= MAX_REFLASH_TRIES) -- ok = 0; -- -- return !ok; -+ return failed; - } - --int write_sector_jedec(chipaddr bios, uint8_t *src, -- chipaddr dst, unsigned int page_size) -+int write_jedec_1(struct flashchip *flash, uint8_t * buf) - { - int i; -+ chipaddr bios = flash->virtual_memory; -+ chipaddr dst = bios; -+ int mask; - -- for (i = 0; i < page_size; i++) { -- write_byte_program_jedec(bios, src, dst); -- dst++, src++; -+ mask = getaddrmask(flash); -+ -+ programmer_delay(10); -+ if (erase_flash(flash)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; - } - -+ msg_cinfo("Programming page: "); -+ for (i = 0; i < flash->total_size; i++) { -+ if ((i & 0x3) == 0) -+ msg_cinfo("address: 0x%08lx", (unsigned long)i * 1024); -+ -+ write_sector_jedec_common(flash, buf + i * 1024, dst + i * 1024, 1024, mask); -+ -+ if ((i & 0x3) == 0) -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ } -+ -+ msg_cinfo("DONE!\n"); - return 0; - } - --int write_jedec(struct flashchip *flash, uint8_t *buf) -+/* erase chip with block_erase() prototype */ -+int erase_chip_block_jedec(struct flashchip *flash, unsigned int addr, -+ unsigned int blocksize) - { -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -+ int mask; - -- if (erase_chip_jedec(flash)) { -- fprintf(stderr,"ERASE FAILED!\n"); -+ mask = getaddrmask(flash); -+ if ((addr != 0) || (blocksize != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); - return -1; - } -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- printf("%04d at address: 0x%08x", i, i * page_size); -- write_page_write_jedec(flash, buf + i * page_size, -- i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- printf("\n"); -- protect_jedec(bios); -+ return erase_chip_jedec_common(flash, mask); -+} - -- return 0; -+int probe_jedec(struct flashchip *flash) -+{ -+ int mask; -+ -+ mask = getaddrmask(flash); -+ return probe_jedec_common(flash, mask); -+} -+ -+int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned int size) -+{ -+ int mask; -+ -+ mask = getaddrmask(flash); -+ return erase_sector_jedec_common(flash, page, size, mask); -+} -+ -+int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int size) -+{ -+ int mask; -+ -+ mask = getaddrmask(flash); -+ return erase_block_jedec_common(flash, page, size, mask); -+} -+ -+int erase_chip_jedec(struct flashchip *flash) -+{ -+ int mask; -+ -+ mask = getaddrmask(flash); -+ return erase_chip_jedec_common(flash, mask); - } -diff --git a/layout.c b/layout.c -index c432ebe..26b7c6a 100644 ---- a/layout.c -+++ b/layout.c -@@ -23,8 +23,10 @@ - #include - #include "flash.h" - -+#if INTERNAL_SUPPORT == 1 - char *mainboard_vendor = NULL; - char *mainboard_part = NULL; -+#endif - int romimages = 0; - - #define MAX_ROMLAYOUT 16 -@@ -38,6 +40,7 @@ typedef struct { - - romlayout_t rom_entries[MAX_ROMLAYOUT]; - -+#if INTERNAL_SUPPORT == 1 /* FIXME: Move the whole block to cbtable.c? */ - static char *def_name = "DEFAULT"; - - int show_id(uint8_t *bios, int size, int force) -@@ -126,6 +129,7 @@ int show_id(uint8_t *bios, int size, int force) - - return 0; - } -+#endif - - int read_romlayout(char *name) - { -diff --git a/m29f002.c b/m29f002.c -deleted file mode 100644 -index 00cbbc1..0000000 ---- a/m29f002.c -+++ /dev/null -@@ -1,126 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2009 Peter Stuge -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --int erase_m29f002(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- chip_writeb(0xaa, bios + 0x555); -- chip_writeb(0x55, bios + 0xaaa); -- chip_writeb(0x80, bios + 0x555); -- chip_writeb(0xaa, bios + 0x555); -- chip_writeb(0x55, bios + 0xaaa); -- chip_writeb(0x10, bios + 0x555); -- programmer_delay(10); -- toggle_ready_jedec(bios); -- if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --static int rewrite_block(struct flashchip *flash, uint8_t *src, -- unsigned long start, int size) --{ -- chipaddr bios = flash->virtual_memory; -- chipaddr dst = bios + start; -- -- /* erase */ -- chip_writeb(0xaa, bios + 0x555); -- chip_writeb(0x55, bios + 0xaaa); -- chip_writeb(0x80, bios + 0x555); -- chip_writeb(0xaa, bios + 0x555); -- chip_writeb(0x55, bios + 0xaaa); -- chip_writeb(0x30, dst); -- programmer_delay(10); -- toggle_ready_jedec(bios); -- if (check_erased_range(flash, start, size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- /* program */ -- while (size--) { -- chip_writeb(0xaa, bios + 0x555); -- chip_writeb(0x55, bios + 0xaaa); -- chip_writeb(0xa0, bios + 0x555); -- chip_writeb(*src, dst); -- toggle_ready_jedec(dst); -- dst++; -- src++; -- } -- return 0; --} -- --static int do_block(struct flashchip *flash, uint8_t *src, int i, -- unsigned long start, int size) --{ -- int ret; -- printf("%d at address: 0x%08lx", i, start); -- ret = rewrite_block(flash, src + start, start, size); -- if (ret) -- return ret; -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- return 0; --} -- --int write_m29f002t(struct flashchip *flash, uint8_t *buf) --{ -- int i, page_size = flash->page_size; -- -- /* M29F002(N)T has 7 blocks. From bottom to top their sizes are: -- * 64k 64k 64k 32k 8k 8k 16k -- * flash->page_size is set to 64k in flashchips.c -- */ -- -- printf("Programming block: "); -- for (i = 0; i < 3; i++) -- do_block(flash, buf, i, i * page_size, page_size); -- do_block(flash, buf, i++, 0x30000, 32 * 1024); -- do_block(flash, buf, i++, 0x38000, 8 * 1024); -- do_block(flash, buf, i++, 0x3a000, 8 * 1024); -- do_block(flash, buf, i, 0x3c000, 16 * 1024); -- -- printf("\n"); -- return 0; --} -- --int write_m29f002b(struct flashchip *flash, uint8_t *buf) --{ -- int i = 0, page_size = flash->page_size; -- -- /* M29F002B has 7 blocks. From bottom to top their sizes are: -- * 16k 8k 8k 32k 64k 64k 64k -- * flash->page_size is set to 64k in flashchips.c -- */ -- -- printf("Programming block: "); -- do_block(flash, buf, i++, 0x00000, 16 * 1024); -- do_block(flash, buf, i++, 0x04000, 8 * 1024); -- do_block(flash, buf, i++, 0x06000, 8 * 1024); -- do_block(flash, buf, i++, 0x08000, 32 * 1024); -- for (; i < 7; i++) -- do_block(flash, buf, i, (i - 3) * page_size, page_size); -- -- printf("\n"); -- return 0; --} -diff --git a/m29f400bt.c b/m29f400bt.c -index ace6dae..c8ed5d8 100644 ---- a/m29f400bt.c -+++ b/m29f400bt.c -@@ -19,15 +19,13 @@ - */ - - #include "flash.h" -+#include "chipdrivers.h" - --void protect_m29f400bt(chipaddr bios) --{ -- chip_writeb(0xAA, bios + 0xAAA); -- chip_writeb(0x55, bios + 0x555); -- chip_writeb(0xA0, bios + 0xAAA); -- -- programmer_delay(200); --} -+/* WARNING! -+ This chip uses the standard JEDEC Addresses in 16-bit mode as word -+ addresses. In byte mode, 0xAAA has to be used instead of 0x555 and -+ 0x555 instead of 0x2AA. Do *not* blindly replace with standard JEDEC -+ functions. */ - - void write_page_m29f400bt(chipaddr bios, uint8_t *src, - chipaddr dst, int page_size) -@@ -44,8 +42,7 @@ void write_page_m29f400bt(chipaddr bios, uint8_t *src, - //chip_writeb(0xF0, bios); - //programmer_delay(5); - toggle_ready_jedec(dst); -- printf -- ("Value in the flash at address 0x%lx = %#x, want %#x\n", -+ msg_cerr("Value in the flash at address 0x%lx = %#x, want %#x\n", - (dst - bios), chip_readb(dst), *src); - dst++; - src++; -@@ -75,7 +72,7 @@ int probe_m29f400bt(struct flashchip *flash) - - programmer_delay(10); - -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; -@@ -99,13 +96,13 @@ int erase_m29f400bt(struct flashchip *flash) - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --int block_erase_m29f400bt(struct flashchip *flash, int start, int len) -+int block_erase_m29f400bt(struct flashchip *flash, unsigned int start, unsigned int len) - { - chipaddr bios = flash->virtual_memory; - chipaddr dst = bios + start; -@@ -123,12 +120,22 @@ int block_erase_m29f400bt(struct flashchip *flash, int start, int len) - toggle_ready_jedec(bios); - - if (check_erased_range(flash, start, len)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - -+int block_erase_chip_m29f400bt(struct flashchip *flash, unsigned int address, unsigned int blocklen) -+{ -+ if ((address != 0) || (blocklen != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); -+ return -1; -+ } -+ return erase_m29f400bt(flash); -+} -+ - int write_m29f400bt(struct flashchip *flash, uint8_t *buf) - { - int i; -@@ -137,7 +144,7 @@ int write_m29f400bt(struct flashchip *flash, uint8_t *buf) - chipaddr bios = flash->virtual_memory; - - //erase_m29f400bt (flash); -- printf("Programming page:\n "); -+ msg_cinfo("Programming page:\n "); - /********************************* - *Pages for M29F400BT: - * 16 0x7c000 0x7ffff TOP -@@ -153,48 +160,47 @@ int write_m29f400bt(struct flashchip *flash, uint8_t *buf) - * 64 0x10000 0x1ffff - * 64 0x00000 0x0ffff BOTTOM - *********************************/ -- printf("total_size/page_size = %d\n", total_size / page_size); -+ msg_cinfo("total_size/page_size = %d\n", total_size / page_size); - for (i = 0; i < (total_size / page_size) - 1; i++) { -- printf("%04d at address: 0x%08x\n", i, i * page_size); -+ msg_cinfo("%04d at address: 0x%08x\n", i, i * page_size); - if (block_erase_m29f400bt(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + i * page_size, - bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } - -- printf("%04d at address: 0x%08x\n", 7, 0x70000); -+ msg_cinfo("%04d at address: 0x%08x\n", 7, 0x70000); - if (block_erase_m29f400bt(flash, 0x70000, 32 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x70000, bios + 0x70000, 32 * 1024); - -- printf("%04d at address: 0x%08x\n", 8, 0x78000); -+ msg_cinfo("%04d at address: 0x%08x\n", 8, 0x78000); - if (block_erase_m29f400bt(flash, 0x78000, 8 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x78000, bios + 0x78000, 8 * 1024); - -- printf("%04d at address: 0x%08x\n", 9, 0x7a000); -+ msg_cinfo("%04d at address: 0x%08x\n", 9, 0x7a000); - if (block_erase_m29f400bt(flash, 0x7a000, 8 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x7a000, bios + 0x7a000, 8 * 1024); - -- printf("%04d at address: 0x%08x\n", 10, 0x7c000); -+ msg_cinfo("%04d at address: 0x%08x\n", 10, 0x7c000); - if (block_erase_m29f400bt(flash, 0x7c000, 16 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x7c000, bios + 0x7c000, 16 * 1024); - -- printf("\n"); -- //protect_m29f400bt (bios); -+ msg_cinfo("\n"); - - return 0; - } -@@ -203,7 +209,7 @@ int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf) - { - chipaddr bios = flash->virtual_memory; - -- printf("Programming page:\n "); -+ msg_cinfo("Programming page:\n "); - /********************************* - *Pages for M29F400BT: - * 16 0x7c000 0x7ffff TOP -@@ -219,36 +225,35 @@ int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf) - * 64 0x10000 0x1ffff - * 64 0x00000 0x0ffff BOTTOM - *********************************/ -- printf("%04d at address: 0x%08x\n", 7, 0x00000); -+ msg_cinfo("%04d at address: 0x%08x\n", 7, 0x00000); - if (block_erase_m29f400bt(flash, 0x00000, 64 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x00000, bios + 0x00000, 64 * 1024); - -- printf("%04d at address: 0x%08x\n", 7, 0x10000); -+ msg_cinfo("%04d at address: 0x%08x\n", 7, 0x10000); - if (block_erase_m29f400bt(flash, 0x10000, 64 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x10000, bios + 0x10000, 64 * 1024); - -- printf("%04d at address: 0x%08x\n", 7, 0x20000); -+ msg_cinfo("%04d at address: 0x%08x\n", 7, 0x20000); - if (block_erase_m29f400bt(flash, 0x20000, 64 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x20000, bios + 0x20000, 64 * 1024); - -- printf("%04d at address: 0x%08x\n", 7, 0x30000); -+ msg_cinfo("%04d at address: 0x%08x\n", 7, 0x30000); - if (block_erase_m29f400bt(flash, 0x30000, 64 * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - write_page_m29f400bt(bios, buf + 0x30000, bios + 0x30000, 64 * 1024); - -- printf("\n"); -- //protect_m29f400bt (bios); -+ msg_cinfo("\n"); - - return 0; - } -diff --git a/mx29f002.c b/mx29f002.c -deleted file mode 100644 -index d5c6041..0000000 ---- a/mx29f002.c -+++ /dev/null -@@ -1,100 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2000 Silicon Integrated System Corporation -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --int probe_29f002(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x90, bios + 0x5555); -- -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- chip_writeb(0xF0, bios); -- -- programmer_delay(10); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- if (id1 == flash->manufacture_id && id2 == flash->model_id) -- return 1; -- -- return 0; --} -- --int erase_29f002(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- -- chip_writeb(0xF0, bios + 0x555); -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x80, bios + 0x555); -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0x10, bios + 0x555); -- -- programmer_delay(100); -- toggle_ready_jedec(bios); -- -- if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int write_29f002(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- chipaddr bios = flash->virtual_memory; -- chipaddr dst = bios; -- -- chip_writeb(0xF0, bios); -- programmer_delay(10); -- if (erase_29f002(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- printf("Programming page: "); -- for (i = 0; i < total_size; i++) { -- /* write to the sector */ -- if ((i & 0xfff) == 0) -- printf("address: 0x%08lx", (unsigned long)i); -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -- chip_writeb(*buf++, dst++); -- -- /* wait for Toggle bit ready */ -- toggle_ready_jedec(dst); -- -- if ((i & 0xfff) == 0) -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/nic3com.c b/nic3com.c -index 075e760..d3dcce5 100644 ---- a/nic3com.c -+++ b/nic3com.c -@@ -36,20 +36,20 @@ uint16_t id; - - struct pcidev_status nics_3com[] = { - /* 3C90xB */ -- {0x10b7, 0x9055, PCI_OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"}, -- {0x10b7, 0x9001, PCI_NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" }, -- {0x10b7, 0x9004, PCI_OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" }, -- {0x10b7, 0x9005, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" }, -- {0x10b7, 0x9006, PCI_NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" }, -- {0x10b7, 0x900a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FL" }, -- {0x10b7, 0x905a, PCI_NT, "3COM", "3C90xB: PCI 10BASE-FX" }, -- {0x10b7, 0x9058, PCI_OK, "3COM", "3C905B: Cyclone 10/100/BNC" }, -+ {0x10b7, 0x9055, OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"}, -+ {0x10b7, 0x9001, NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" }, -+ {0x10b7, 0x9004, OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" }, -+ {0x10b7, 0x9005, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" }, -+ {0x10b7, 0x9006, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" }, -+ {0x10b7, 0x900a, NT, "3COM", "3C90xB: PCI 10BASE-FL" }, -+ {0x10b7, 0x905a, NT, "3COM", "3C90xB: PCI 10BASE-FX" }, -+ {0x10b7, 0x9058, OK, "3COM", "3C905B: Cyclone 10/100/BNC" }, - - /* 3C905C */ -- {0x10b7, 0x9200, PCI_OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" }, -+ {0x10b7, 0x9200, OK, "3COM", "3C905C: EtherLink 10/100 PCI (TX)" }, - - /* 3C980C */ -- {0x10b7, 0x9805, PCI_NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" }, -+ {0x10b7, 0x9805, NT, "3COM", "3C980C: EtherLink Server 10/100 PCI (TX)" }, - - {}, - }; -@@ -58,7 +58,8 @@ int nic3com_init(void) - { - get_io_perms(); - -- io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, nics_3com, programmer_param); -+ io_base_addr = pcidev_init(PCI_VENDOR_ID_3COM, PCI_BASE_ADDRESS_0, -+ nics_3com, programmer_param); - id = pcidev_dev->device_id; - - /* 3COM 3C90xB cards need a special fixup. */ -diff --git a/pcidev.c b/pcidev.c -index 580ebae..818819a 100644 ---- a/pcidev.c -+++ b/pcidev.c -@@ -28,23 +28,44 @@ struct pci_access *pacc; - struct pci_filter filter; - struct pci_dev *pcidev_dev = NULL; - --uint32_t pcidev_validate(struct pci_dev *dev, struct pcidev_status *devs) -+uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar, -+ struct pcidev_status *devs) - { - int i; -+ /* FIXME: 64 bit memory BARs need a 64 bit addr. */ - uint32_t addr; - - for (i = 0; devs[i].device_name != NULL; i++) { - if (dev->device_id != devs[i].device_id) - continue; - -- /* Don't use dev->base_addr[0], won't work on older libpci. */ -- addr = pci_read_long(dev, PCI_BASE_ADDRESS_0) & ~0x03; -- -+ /* -+ * Don't use dev->base_addr[x] (as value for 'bar'), won't -+ * work on older libpci. -+ */ -+ addr = pci_read_long(dev, bar); -+ - printf("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n", -- devs[i].vendor_name, devs[i].device_name, dev->vendor_id, -- dev->device_id, dev->bus, dev->dev, dev->func); -+ devs[i].vendor_name, devs[i].device_name, -+ dev->vendor_id, dev->device_id, dev->bus, dev->dev, -+ dev->func); -+ msg_pdbg("Requested BAR is %s", (addr & 0x1) ? "IO" : "MEM"); -+ if (addr & 0x1) { -+ /* Mask off IO space indicator and reserved bit. */ -+ msg_pdbg("\n"); -+ addr &= ~0x3; -+ } else { -+ msg_pdbg(", %sbit, %sprefetchable\n", -+ ((addr & 0x6) == 0x0) ? "32" : -+ (((addr & 0x6) == 0x4) ? "64" : "reserved"), -+ (addr & 0x8) ? "" : "not "); -+ /* Mask off Mem space indicator, 32/64bit type indicator -+ * and Prefetchable indicator. -+ */ -+ addr &= ~0xf; -+ } - -- if (devs[i].status == PCI_NT) { -+ if (devs[i].status == NT) { - printf("===\nThis PCI device is UNTESTED. Please " - "report the 'flashrom -p xxxx' output \n" - "to flashrom@flashrom.org if it works " -@@ -57,7 +78,8 @@ uint32_t pcidev_validate(struct pci_dev *dev, struct pcidev_status *devs) - return 0; - } - --uint32_t pcidev_init(uint16_t vendor_id, struct pcidev_status *devs, char *pcidev_bdf) -+uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar, -+ struct pcidev_status *devs, char *pcidev_bdf) - { - struct pci_dev *dev; - char *msg = NULL; -@@ -80,7 +102,7 @@ uint32_t pcidev_init(uint16_t vendor_id, struct pcidev_status *devs, char *pcide - - for (dev = pacc->devices; dev; dev = dev->next) { - if (pci_filter_match(&filter, dev)) { -- if ((addr = pcidev_validate(dev, devs)) != 0) { -+ if ((addr = pcidev_validate(dev, bar, devs)) != 0) { - curaddr = addr; - pcidev_dev = dev; - found++; -@@ -94,7 +116,7 @@ uint32_t pcidev_init(uint16_t vendor_id, struct pcidev_status *devs, char *pcide - exit(1); - } else if (found > 1) { - fprintf(stderr, "Error: Multiple supported PCI devices found. " -- "Use 'flashrom -p xxxx=bb:dd.f' \n" -+ "Use 'flashrom -p xxxx:bb:dd.f' \n" - "to explicitly select the card with the given BDF " - "(PCI bus, device, function).\n"); - exit(1); -@@ -111,6 +133,6 @@ void print_supported_pcidevs(struct pcidev_status *devs) - printf("%s %s [%02x:%02x]%s\n", devs[i].vendor_name, - devs[i].device_name, devs[i].vendor_id, - devs[i].device_id, -- (devs[i].status == PCI_NT) ? " (untested)" : ""); -+ (devs[i].status == NT) ? " (untested)" : ""); - } - } -diff --git a/physmap.c b/physmap.c -index 778a783..0e3ce60 100644 ---- a/physmap.c -+++ b/physmap.c -@@ -3,6 +3,8 @@ - * - * Copyright (C) 2009 Peter Stuge - * Copyright (C) 2009 coresystems GmbH -+ * Copyright (C) 2010 Carl-Daniel Hailfinger -+ * Copyright (C) 2010 Rudolf Marek - * - * 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 -@@ -26,7 +28,78 @@ - #include - #include "flash.h" - --#ifdef __DARWIN__ -+#ifdef __DJGPP__ -+#include -+#include -+ -+#define MEM_DEV "dpmi" -+ -+static void *realmem_map; -+ -+static void *map_first_meg(unsigned long phys_addr, size_t len) -+{ -+ -+ if (realmem_map) { -+ return realmem_map + phys_addr; -+ } -+ -+ realmem_map = valloc(1024 * 1024); -+ -+ if (!realmem_map) { -+ return NULL; -+ } -+ -+ if (__djgpp_map_physical_memory(realmem_map, (1024 * 1024), 0)) { -+ return NULL; -+ } -+ -+ return realmem_map + phys_addr; -+} -+ -+void *sys_physmap(unsigned long phys_addr, size_t len) -+{ -+ int ret; -+ __dpmi_meminfo mi; -+ -+ /* enable 4GB limit on DS descriptor */ -+ if (!__djgpp_nearptr_enable()) { -+ return NULL; -+ } -+ -+ if ((phys_addr + len - 1) < (1024 * 1024)) { -+ /* we need to use another method to map first 1MB */ -+ return map_first_meg(phys_addr, len); -+ } -+ -+ mi.address = phys_addr; -+ mi.size = len; -+ ret = __dpmi_physical_address_mapping (&mi); -+ -+ if (ret != 0) { -+ return NULL; -+ } -+ -+ return (void *) mi.address + __djgpp_conventional_base; -+} -+ -+#define sys_physmap_rw_uncached sys_physmap -+#define sys_physmap_ro_cached sys_physmap -+ -+void physunmap(void *virt_addr, size_t len) -+{ -+ __dpmi_meminfo mi; -+ -+ /* we ignore unmaps for our first 1MB */ -+ if ((virt_addr >= realmem_map) && ((virt_addr + len) <= (realmem_map + (1024 * 1024)))) { -+ return; -+ } -+ -+ mi.address = (unsigned long) virt_addr; -+ __dpmi_free_physical_address_mapping(&mi); -+} -+ -+#elif defined(__DARWIN__) -+ - #include - - #define MEM_DEV "DirectIO" -@@ -36,6 +109,10 @@ void *sys_physmap(unsigned long phys_addr, size_t len) - return map_physical(phys_addr, len); - } - -+/* The OS X driver does not differentiate between mapping types. */ -+#define sys_physmap_rw_uncached sys_physmap -+#define sys_physmap_ro_cached sys_physmap -+ - void physunmap(void *virt_addr, size_t len) - { - unmap_physical(virt_addr, len); -@@ -51,8 +128,10 @@ void physunmap(void *virt_addr, size_t len) - #endif - - static int fd_mem = -1; -+static int fd_mem_cached = -1; - --void *sys_physmap(unsigned long phys_addr, size_t len) -+/* For MMIO access. Must be uncached, doesn't make sense to restrict to ro. */ -+void *sys_physmap_rw_uncached(unsigned long phys_addr, size_t len) - { - void *virt_addr; - -@@ -69,6 +148,26 @@ void *sys_physmap(unsigned long phys_addr, size_t len) - return MAP_FAILED == virt_addr ? NULL : virt_addr; - } - -+/* For reading DMI/coreboot/whatever tables. We should never write, and we -+ * do not care about caching. -+ */ -+void *sys_physmap_ro_cached(unsigned long phys_addr, size_t len) -+{ -+ void *virt_addr; -+ -+ if (-1 == fd_mem_cached) { -+ /* Open the memory device CACHED. */ -+ if (-1 == (fd_mem_cached = open(MEM_DEV, O_RDWR))) { -+ perror("Critical error: open(" MEM_DEV ")"); -+ exit(2); -+ } -+ } -+ -+ virt_addr = mmap(0, len, PROT_READ, MAP_SHARED, -+ fd_mem_cached, (off_t)phys_addr); -+ return MAP_FAILED == virt_addr ? NULL : virt_addr; -+} -+ - void physunmap(void *virt_addr, size_t len) - { - if (len == 0) { -@@ -80,7 +179,12 @@ void physunmap(void *virt_addr, size_t len) - } - #endif - --void *physmap(const char *descr, unsigned long phys_addr, size_t len) -+#define PHYSMAP_NOFAIL 0 -+#define PHYSMAP_MAYFAIL 1 -+#define PHYSMAP_RW 0 -+#define PHYSMAP_RO 1 -+ -+void *physmap_common(const char *descr, unsigned long phys_addr, size_t len, int mayfail, int readonly) - { - void *virt_addr; - -@@ -100,7 +204,11 @@ void *physmap(const char *descr, unsigned long phys_addr, size_t len) - descr, (unsigned long)len, phys_addr); - } - -- virt_addr = sys_physmap(phys_addr, len); -+ if (readonly) { -+ virt_addr = sys_physmap_ro_cached(phys_addr, len); -+ } else { -+ virt_addr = sys_physmap_rw_uncached(phys_addr, len); -+ } - - if (NULL == virt_addr) { - if (NULL == descr) -@@ -114,12 +222,23 @@ void *physmap(const char *descr, unsigned long phys_addr, size_t len) - fprintf(stderr, "You can override CONFIG_X86_PAT at boot with the nopat kernel parameter but\n"); - fprintf(stderr, "disabling the other option unfortunately requires a kernel recompile. Sorry!\n"); - } -- exit(3); -+ if (!mayfail) -+ exit(3); - } - - return virt_addr; - } - -+void *physmap(const char *descr, unsigned long phys_addr, size_t len) -+{ -+ return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL, PHYSMAP_RW); -+} -+ -+void *physmap_try_ro(const char *descr, unsigned long phys_addr, size_t len) -+{ -+ return physmap_common(descr, phys_addr, len, PHYSMAP_MAYFAIL, PHYSMAP_RO); -+} -+ - #ifdef __linux__ - /* - * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr, -@@ -133,7 +252,7 @@ static int fd_msr = -1; - - msr_t rdmsr(int addr) - { -- uint8_t buf[8]; -+ uint32_t buf[2]; - msr_t msr = { 0xffffffff, 0xffffffff }; - - if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) { -@@ -143,8 +262,8 @@ msr_t rdmsr(int addr) - } - - if (read(fd_msr, buf, 8) == 8) { -- msr.lo = *(uint32_t *)buf; -- msr.hi = *(uint32_t *)(buf + 4); -+ msr.lo = buf[0]; -+ msr.hi = buf[1]; - - return msr; - } -diff --git a/pm29f002.c b/pm29f002.c -deleted file mode 100644 -index a01df88..0000000 ---- a/pm29f002.c -+++ /dev/null -@@ -1,56 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2009 Uwe Hermann -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --int write_pm29f002(struct flashchip *flash, uint8_t *buf) --{ -- int i, total_size = flash->total_size * 1024; -- chipaddr bios = flash->virtual_memory; -- chipaddr dst = bios; -- -- /* Pm29F002T/B use the same erase method... */ -- if (erase_29f040b(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- printf("Programming page: "); -- for (i = 0; i < total_size; i++) { -- if ((i & 0xfff) == 0) -- printf("address: 0x%08lx", (unsigned long)i); -- -- /* Pm29F002T/B only support byte-wise programming. */ -- chip_writeb(0xAA, bios + 0x555); -- chip_writeb(0x55, bios + 0x2AA); -- chip_writeb(0xA0, bios + 0x555); -- chip_writeb(*buf++, dst++); -- -- /* Wait for Toggle bit ready. */ -- toggle_ready_jedec(dst); -- -- if ((i & 0xfff) == 0) -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- -- printf("\n"); -- -- return 0; --} -diff --git a/pm49fl00x.c b/pm49fl00x.c -index 27a1163..fd93ef6 100644 ---- a/pm49fl00x.c -+++ b/pm49fl00x.c -@@ -21,6 +21,7 @@ - */ - - #include "flash.h" -+#include "chipdrivers.h" - - void write_lockbits_49fl00x(chipaddr bios, int size, - unsigned char bits, int block_size) -@@ -36,81 +37,14 @@ void write_lockbits_49fl00x(chipaddr bios, int size, - } - } - --int probe_49fl00x(struct flashchip *flash) -+int unlock_49fl00x(struct flashchip *flash) - { -- int ret = probe_jedec(flash); -- -- if (ret == 1) -- map_flash_registers(flash); -- -- return ret; --} -- --int erase_49fl00x(struct flashchip *flash) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- -- /* unprotected */ -- write_lockbits_49fl00x(flash->virtual_registers, -- total_size, 0, page_size); -- -- /* -- * erase_chip_jedec() will not work... Datasheet says -- * "Chip erase is available in A/A Mux Mode only". -- */ -- printf("Erasing page: "); -- for (i = 0; i < total_size / page_size; i++) { -- /* erase the page */ -- if (erase_block_jedec(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- printf("%04d at address: 0x%08x", i, i * page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- fflush(stdout); -- } -- printf("\n"); -- -- /* protected */ -- write_lockbits_49fl00x(flash->virtual_registers, -- total_size, 1, page_size); -- -+ write_lockbits_49fl00x(flash->virtual_registers, flash->total_size * 1024, 0, flash->page_size); - return 0; - } - --int write_49fl00x(struct flashchip *flash, uint8_t *buf) -+int lock_49fl00x(struct flashchip *flash) - { -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- /* unprotected */ -- write_lockbits_49fl00x(flash->virtual_registers, total_size, 0, -- page_size); -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- /* erase the page before programming */ -- if (erase_block_jedec(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- /* write to the sector */ -- printf("%04d at address: 0x%08x", i, i * page_size); -- write_sector_jedec(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- fflush(stdout); -- } -- printf("\n"); -- -- /* protected */ -- write_lockbits_49fl00x(flash->virtual_registers, total_size, 1, -- page_size); -- -+ write_lockbits_49fl00x(flash->virtual_registers, flash->total_size * 1024, 1, flash->page_size); - return 0; - } -diff --git a/print.c b/print.c -index ce46e1b..2a2c81b 100644 ---- a/print.c -+++ b/print.c -@@ -21,22 +21,9 @@ - - #include - #include --#include - #include "flash.h" - #include "flashchips.h" - --struct board_info_url { -- const char *vendor; -- const char *name; -- const char *url; --}; -- --struct board_info_notes { -- const char *vendor; -- const char *name; -- const char *note; --}; -- - /* - * Return a string corresponding to the bustype parameter. - * Memory is obtained with malloc() and can be freed with free(). -@@ -157,6 +144,7 @@ void print_supported_chips(void) - } - } - -+#if INTERNAL_SUPPORT == 1 - void print_supported_chipsets(void) - { - int i, j, chipsetcount = 0; -@@ -194,7 +182,7 @@ void print_supported_boards_helper(const struct board_info *b, const char *msg) - for (j = 0; j < 25 - strlen(b[i].vendor); j++) - printf(" "); - printf("%s", b[i].name); -- for (j = 0; j < 23 - strlen(b[i].name); j++) -+ for (j = 0; j < 28 - strlen(b[i].name); j++) - printf(" "); - printf("\n"); - } -@@ -209,7 +197,7 @@ void print_supported_boards(void) - boardcount++; - - printf("\nSupported boards which need write-enable code (total: %d):" -- "\n\nVendor: Board: " -+ "\n\nVendor: Board: " - "Required option:\n\n", boardcount); - - for (i = 0; b[i].vendor_name != NULL; i++) { -@@ -217,7 +205,7 @@ void print_supported_boards(void) - for (j = 0; j < 25 - strlen(b[i].vendor_name); j++) - printf(" "); - printf("%s", b[i].board_name); -- for (j = 0; j < 25 - strlen(b[i].board_name); j++) -+ for (j = 0; j < 30 - strlen(b[i].board_name); j++) - printf(" "); - if (b[i].lb_vendor != NULL) - printf("-m %s:%s\n", b[i].lb_vendor, b[i].lb_part); -@@ -234,505 +222,206 @@ void print_supported_boards(void) - print_supported_boards_helper(laptops_bad, - "Laptops which have been verified to NOT work yet"); - } -+#endif - --const char *wiki_header = "= Supported devices =\n\n\ --
\n\ --Please do '''not''' edit these tables in the wiki directly, they are \ --generated by pasting '''flashrom -z''' output.
\ --'''Last update:''' %s(generated by flashrom %s)\n
\n"; -- --const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\ --|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ --! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\ --! align=\"left\" | Status\n\n"; -- --const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \ --valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ --! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n"; -- --const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \ --valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ --! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\ --! align=\"left\" | Status\n\n"; -- --const char *board_intro = "\ --\n== Supported mainboards ==\n\n\ --In general, it is very likely that flashrom works out of the box even if your \ --mainboard is not listed below.\n\nThis is a list of mainboards where we have \ --verified that they either do or do not need any special initialization to \ --make flashrom work (given flashrom supports the respective chipset and flash \ --chip), or that they do not yet work at all. If they do not work, support may \ --or may not be added later.\n\n\ --Mainboards which don't appear in the list may or may not work (we don't \ --know, someone has to give it a try). Please report any further verified \ --mainboards on the [[Mailinglist|mailing list]].\n"; -- --const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \ --valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ --! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\ --! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\ --|- bgcolor=\"#6699ff\"\n| colspan=\"4\" |  \n\ --| Probe\n| Read\n| Write\n| Erase\n\n"; -- --const char *programmer_section = "\ --\n== Supported programmers ==\n\nThis is a list \ --of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \ --valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \ --smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ --! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\ --! align=\"left\" | Status\n\n"; -- --const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\ --In general, flashing laptops is more difficult because laptops\n\n\ --* often use the flash chip for stuff besides the BIOS,\n\ --* often have special protection stuff which has to be handled by flashrom,\n\ --* often use flash translation circuits which need drivers in flashrom.\n\n\ --
\n\ --'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \ --untested laptops unless you have a means to recover from a flashing that goes \ --wrong (a working backup flash chip and/or good soldering skills).\n
\n"; -- --/* Please keep these lists alphabetically ordered by vendor/board. */ --const struct board_info_url boards_url[] = { -- /* Verified working boards that don't need write-enables. */ -- { "Abit", "AX8", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" }, -- { "Abit", "Fatal1ty F-I90HD", "http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" }, -- { "Advantech", "PCM-5820", "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" }, -- { "ASI", "MB-5BLMP", "http://www.hojerteknik.com/winnet.htm" }, -- { "ASRock", "A770CrossFire", "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" }, -- { "ASUS", "A7N8X Deluxe", "http://www.asus.com/Product.aspx?P_ID=wAsRYm41KTp78MFC" }, -- { "ASUS", "A7N8X-E Deluxe", "http://www.asus.com/products.aspx?l1=3&l2=13&l3=56&l4=0&model=217&modelmenu=1" }, -- { "ASUS", "A7V400-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=63&l4=0&model=228&modelmenu=1" }, -- { "ASUS", "A7V8X-MX", "http://www.asus.com.tw/products.aspx?l1=3&l2=13&l3=64&l4=0&model=229&modelmenu=1" }, -- { "ASUS", "A8N-E", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=171&l4=0&model=455&modelmenu=2" }, -- { "ASUS", "A8NE-FM/S", "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" }, -- { "ASUS", "A8N-SLI", "http://asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" }, -- { "ASUS", "A8N-SLI Premium", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=148&l4=0&model=539&modelmenu=1" }, -- { "ASUS", "A8V Deluxe", "http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" }, -- { "ASUS", "A8V-E Deluxe", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=376&modelmenu=1" }, -- { "ASUS", "A8V-E SE", "http://www.asus.com.tw/products.aspx?l1=3&l2=15&l3=143&l4=0&model=576&modelmenu=1" }, -- { "ASUS", "M2A-MX", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=583&l4=0&model=1909&modelmenu=1" }, -- { "ASUS", "M2A-VM", "http://www.asus.com.tw/products.aspx?l1=3&l2=101&l3=496&l4=0&model=1568&modelmenu=1" }, -- { "ASUS", "M2N-E", "http://www.asus.com/products.aspx?l1=3&l2=101&l3=308&l4=0&model=1181&modelmenu=1" }, -- { "ASUS", "M2V", "http://asus.com/Product.aspx?P_ID=OqYlEDFfF6ZqZGvp" }, -- { "ASUS", "P2B", "http://www.motherboard.cz/mb/asus/P2B.htm" }, -- { "ASUS", "P2B-D", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" }, -- { "ASUS", "P2B-DS", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" }, -- { "ASUS", "P2B-F", "http://www.motherboard.cz/mb/asus/P2B-F.htm" }, -- { "ASUS", "P2L97-S", "http://www.motherboard.cz/mb/asus/P2L97-S.htm" }, -- { "ASUS", "P5B-Deluxe", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-Deluxe/" }, -- { "ASUS", "P5KC", "http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" }, -- { "ASUS", "P5L-MX", "http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" }, -- { "ASUS", "P6T Deluxe V2", "http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" }, -- { "A-Trend", "ATC-6220", "http://www.motherboard.cz/mb/atrend/atc6220.htm" }, -- { "BCOM", "WinNET100", "http://www.coreboot.org/BCOM_WINNET100" }, -- { "GIGABYTE", "GA-6BXC", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ClassValue=Motherboard&ProductID=1445&ProductName=GA-6BXC" }, -- { "GIGABYTE", "GA-6BXDU", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" }, -- { "GIGABYTE", "GA-6ZMA", "http://www.gigabyte.de/Support/Motherboard/BIOS_Model.aspx?ProductID=3289" }, -- { "GIGABYTE", "GA-EX58-UD4P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2986" }, -- { "GIGABYTE", "GA-EP35-DS3L", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2778" }, -- { "GIGABYTE", "GA-MA790GP-DS4H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" }, -- { "GIGABYTE", "GA-MA78GPM-DS2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" }, -- { "Intel", "EP80759", NULL }, -- { "Jetway", "J7F4K1G5D-PB", "http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" }, -- { "MSI", "MS-6570 (K7N2)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=519&maincat_no=1" }, -- { "MSI", "MS-7065", "http://browse.geekbench.ca/geekbench2/view/53114" }, -- { "MSI", "MS-7168 (Orion)", "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" }, -- { "MSI", "MS-7236 (945PL Neo3)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" }, -- { "MSI", "MS-7255 (P4M890M)", "http://www.tcsbahamas.com/P4M89.htm" }, -- { "MSI", "MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=prodcpusupport&maincat_no=1&cat2_no=170&cat3_no=&prod_no=1261" }, -- { "NEC", "PowerMate 2000", "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" }, -- { "PC Engines", "Alix.1c", "http://pcengines.ch/alix1c.htm" }, -- { "PC Engines", "Alix.2c2", "http://pcengines.ch/alix2c2.htm" }, -- { "PC Engines", "Alix.2c3", "http://pcengines.ch/alix2c3.htm" }, -- { "PC Engines", "Alix.3c3", "http://pcengines.ch/alix3c3.htm" }, -- { "PC Engines", "Alix.3d3", "http://pcengines.ch/alix3d3.htm" }, -- { "RCA", "RM4100", "http://www.settoplinux.org/index.php?title=RCA_RM4100" }, -- { "Sun", "Blade x6250", "http://www.sun.com/servers/blades/x6250/" }, -- { "Supermicro", "H8QC8", "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" }, -- { "Thomson", "IP1000", "http://www.settoplinux.org/index.php?title=Thomson_IP1000" }, -- { "TriGem", "Lomita", "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" }, -- { "T-Online", "S-100", "http://wiki.freifunk-hannover.de/T-Online_S_100" }, -- { "Tyan", "iS5375-1U", "http://www.tyan.com/product_board_detail.aspx?pid=610" }, -- { "Tyan", "S1846", "http://www.tyan.com/archive/products/html/tsunamiatx.html" }, -- { "Tyan", "S2466", "http://www.tyan.com/product_board_detail.aspx?pid=461" }, -- { "Tyan", "S2881", "http://www.tyan.com/product_board_detail.aspx?pid=115" }, -- { "Tyan", "S2882", "http://www.tyan.com/product_board_detail.aspx?pid=121" }, -- { "Tyan", "S2882-D", "http://www.tyan.com/product_board_detail.aspx?pid=127" }, -- { "Tyan", "S2891", "http://www.tyan.com/product_board_detail.aspx?pid=144" }, -- { "Tyan", "S2892", "http://www.tyan.com/product_board_detail.aspx?pid=145" }, -- { "Tyan", "S2895", "http://www.tyan.com/archive/products/html/thunderk8we.html" }, -- { "Tyan", "S3095", "http://www.tyan.com/product_board_detail.aspx?pid=181" }, -- { "Tyan", "S5180", "http://www.tyan.com/product_board_detail.aspx?pid=456" }, -- { "Tyan", "S5191", "http://www.tyan.com/product_board_detail.aspx?pid=343" }, -- { "Tyan", "S5197", "http://www.tyan.com/product_board_detail.aspx?pid=349" }, -- { "Tyan", "S5211", "http://www.tyan.com/product_board_detail.aspx?pid=591" }, -- { "Tyan", "S5211-1U", "http://www.tyan.com/product_board_detail.aspx?pid=593" }, -- { "Tyan", "S5220", "http://www.tyan.com/product_board_detail.aspx?pid=597" }, -- { "Tyan", "S5375", "http://www.tyan.com/product_board_detail.aspx?pid=566" }, -- { "Tyan", "S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" }, -- { "Tyan", "S5377", "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" }, -- { "Tyan", "S5397", "http://www.tyan.com/product_board_detail.aspx?pid=560" }, -- { "VIA", "EPIA-EX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" }, -- { "VIA", "EPIA-LN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" }, -- { "VIA", "EPIA-M700", "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" }, -- { "VIA", "EPIA-NX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" }, -- { "VIA", "NAB74X0", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" }, -- { "VIA", "pc2500e", "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" }, -- { "VIA", "VB700X", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" }, -- -- /* Verified working boards that DO need write-enables. */ -- { "Acorp", "6A815EPD", "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" }, -- { "agami", "Aruma", "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" }, -- { "Albatron", "PM266A Pro", "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */ -- { "AOpen", "vKM400Am-S", "http://usa.aopen.com/products_detail.aspx?Auno=824" }, -- { "Artec Group", "DBE61", "http://wiki.thincan.org/DBE61" }, -- { "Artec Group", "DBE62", "http://wiki.thincan.org/DBE62" }, -- { "ASUS", "A7V600-X", "http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" }, -- { "ASUS", "A7V8X-MX SE", "http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" }, -- { "ASUS", "P4B266", "http://www.ciao.co.uk/ASUS_Intel_845D_Chipset_P4B266__5409807#productdetail" }, -- { "ASUS", "P4P800-E Deluxe", "http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" }, -- { "ASUS", "P5A", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" }, -- { "Biostar", "P4M80-M4", "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" }, -- { "Elitegroup", "K7VTA3", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" }, -- { "EPoX", "EP-8K5A2", "http://www.epox.com/product.asp?ID=EP-8K5A2" }, -- { "EPoX", "EP-BX3", "http://www.epox.com/product.asp?ID=EP-BX3" }, -- { "GIGABYTE", "GA-2761GXDK", "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" }, -- { "GIGABYTE", "GA-7VT600", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" }, -- { "GIGABYTE", "GA-7ZM", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" }, -- { "GIGABYTE", "GA-K8N-SLI", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" }, -- { "GIGABYTE", "GA-M57SLI-S4", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Overview.aspx?ProductID=2287&ModelName=GA-M57SLI-S4" }, -- { "GIGABYTE", "GA-M61P-S3", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" }, -- { "GIGABYTE", "GA-MA78G-DS3H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */ -- { "GIGABYTE", "GA-MA78GM-S2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */ -- { "GIGABYTE", "GA-MA790FX-DQ6", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" }, -- { "HP", "DL145 G3", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" }, -- { "IBM", "x3455", "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" }, -- { "Intel", "D201GLY", "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" }, -- { "IWILL", "DK8-HTX", "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" }, -- { "Kontron", "986LCD-M", "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" }, -- { "Mitac", "6513WU", "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" }, -- { "MSI", "MS-6590 (KT4 Ultra)", "http://www.msicomputer.com/product/p_spec.asp?model=KT4_Ultra&class=mb" }, -- { "MSI", "MS-6702E (K8T Neo2-F)","http://www.msicomputer.com/product/p_spec.asp?model=K8T_Neo2-F&class=mb" }, -- { "MSI", "MS-6712 (KT4V)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&cat2_no=&cat3_no=&prod_no=505" }, -- { "MSI", "MS-7046", "http://www.heimir.de/ms7046/" }, -- { "MSI", "MS-7135 (K8N Neo3)", "http://www.msi-computer.de/index.php?func=proddesc&prod_no=170&maincat_no=1" }, -- { "Shuttle", "AK38N", "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" }, -- { "Soyo", "SY-7VCA", "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" }, -- { "Tyan", "S2498 (Tomcat K7M)", "http://www.tyan.com/archive/products/html/tomcatk7m.html" }, -- { "VIA", "EPIA-CN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" }, -- { "VIA", "EPIA M/MII/...", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */ -- { "VIA", "EPIA-N/NL", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */ -- { "VIA", "EPIA SP", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" }, -- { "VIA", "PC3500G", "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" }, -- -- /* Verified non-working boards (for now). */ -- { "Abit", "IS-10", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" }, -- { "ASRock", "K7VT4A+", "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" }, -- { "ASUS", "MEW-AM", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" }, -- { "ASUS", "MEW-VM", "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" }, -- { "ASUS", "P3B-F", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" }, -- { "ASUS", "P5B", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" }, -- { "ASUS", "P5BV-M", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" }, -- { "Biostar", "M6TBA", "ftp://ftp.biostar-usa.com/manuals/M6TBA/" }, -- { "Boser", "HS-6637", "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" }, -- { "DFI", "855GME-MGF", "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" }, -- { "FIC", "VA-502", "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" }, -- { "MSI", "MS-6178", "http://www.msi-technology.de/index.php?func=proddesc&prod_no=343&maincat_no=1" }, -- { "MSI", "MS-7260 (K9N Neo)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" }, -- { "Soyo", "SY-5VD", "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" }, -- { "Sun", "Fire x4540", "http://www.sun.com/servers/x64/x4540/" }, -- { "Sun", "Fire x4150", "http://www.sun.com/servers/x64/x4150/" }, -- { "Sun", "Fire x4200", "http://www.sun.com/servers/entry/x4200/" }, -- { "Sun", "Fire x4600", "http://www.sun.com/servers/x64/x4600/" }, -- -- /* Verified working laptops. */ -- { "Lenovo", "3000 V100 TF05Cxx", "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" }, -+void print_supported(void) -+{ -+ print_supported_chips(); -+#if INTERNAL_SUPPORT == 1 -+ print_supported_chipsets(); -+ print_supported_boards(); -+#endif -+#if (NIC3COM_SUPPORT == 1) || (GFXNVIDIA_SUPPORT == 1) || (DRKAISER_SUPPORT == 1) || (SATASII_SUPPORT == 1) -+ printf("\nSupported PCI devices flashrom can use " -+ "as programmer:\n\n"); -+#endif -+#if NIC3COM_SUPPORT == 1 -+ print_supported_pcidevs(nics_3com); -+#endif -+#if GFXNVIDIA_SUPPORT == 1 -+ print_supported_pcidevs(gfx_nvidia); -+#endif -+#if DRKAISER_SUPPORT == 1 -+ print_supported_pcidevs(drkaiser_pcidev); -+#endif -+#if SATASII_SUPPORT == 1 -+ print_supported_pcidevs(satas_sii); -+#endif -+} - -- /* Verified non-working laptops (for now). */ -- { "Acer", "Aspire One", NULL }, -- { "ASUS", "Eee PC 701 4G", "http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" }, -- { "Dell", "Latitude CPi A366XT", "http://www.coreboot.org/Dell_Latitude_CPi_A366XT" }, -- { "HP/Compaq", "nx9010", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" }, -- { "IBM/Lenovo", "Thinkpad T40p", "http://www.thinkwiki.org/wiki/Category:T40p" }, -- { "IBM/Lenovo", "240", "http://www.stanford.edu/~bresnan//tp240.html" }, -- -- { NULL, NULL, 0 }, --}; - --/* Please keep these lists alphabetically ordered by vendor/board. */ --const struct board_info_notes boards_notes[] = { -+#if INTERNAL_SUPPORT == 1 -+/* Please keep this list alphabetically ordered by vendor/board. */ -+const struct board_info boards_ok[] = { - /* Verified working boards that don't need write-enables. */ -- { "ASI", "MB-5BLMP", "Used in the IGEL WinNET III thin client." }, -- { "ASUS", "A8V-E SE", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." }, -- { "ASUS", "M2A-VM", "See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." }, -- { "BCOM", "WinNET100", "Used in the IGEL-316 thin client." }, -- { "GIGABYTE", "GA-7ZM", "Works fine iff you remove jumper JP9 on the board and disable the flash protection BIOS option." }, -- -- /* Verified working boards that DO need write-enables. */ -- { "Acer", "Aspire One", "See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." }, -+ { "Abit", "AX8", }, -+ { "Abit", "Fatal1ty F-I90HD", }, -+ { "Advantech", "PCM-5820", }, -+ { "ASI", "MB-5BLMP", }, -+ { "ASRock", "A770CrossFire", }, -+ { "ASRock", "K8S8X", }, -+ { "ASRock", "M3A790GXH/128M" }, -+ { "ASUS", "A7N8X Deluxe", }, -+ { "ASUS", "A7N8X-E Deluxe", }, -+ { "ASUS", "A7V133", }, -+ { "ASUS", "A7V400-MX", }, -+ { "ASUS", "A7V8X-MX", }, -+ { "ASUS", "A8N-E", }, -+ { "ASUS", "A8NE-FM/S", }, -+ { "ASUS", "A8N-SLI", }, -+ { "ASUS", "A8N-SLI Premium", }, -+ { "ASUS", "A8V Deluxe", }, -+ { "ASUS", "A8V-E Deluxe", }, -+ { "ASUS", "A8V-E SE", }, -+ { "ASUS", "K8V", }, -+ { "ASUS", "K8V SE Deluxe", }, -+ { "ASUS", "K8V-X SE", }, -+ { "ASUS", "M2A-MX", }, -+ { "ASUS", "M2A-VM", }, -+ { "ASUS", "M2N-E", }, -+ { "ASUS", "M2V", }, -+ { "ASUS", "M3A78-EM", }, -+ { "ASUS", "P2B", }, -+ { "ASUS", "P2B-D", }, -+ { "ASUS", "P2B-DS", }, -+ { "ASUS", "P2B-F", }, -+ { "ASUS", "P2L97-S", }, -+ { "ASUS", "P5B", }, -+ { "ASUS", "P5B-Deluxe", }, -+ { "ASUS", "P5KC", }, -+ { "ASUS", "P5L-MX", }, -+ { "ASUS", "P6T Deluxe", }, -+ { "ASUS", "P6T Deluxe V2", }, -+ { "A-Trend", "ATC-6220", }, -+ { "BCOM", "WinNET100", }, -+ { "DFI", "Blood-Iron P35 T2RL", }, -+ { "Elitegroup", "K7S5A", }, -+ { "Elitegroup", "P6VAP-A+", }, -+ { "GIGABYTE", "GA-2761GXDK", }, -+ { "GIGABYTE", "GA-6BXC", }, -+ { "GIGABYTE", "GA-6BXDU", }, -+ { "GIGABYTE", "GA-6ZMA", }, -+ { "GIGABYTE", "GA-7ZM", }, -+ { "GIGABYTE", "GA-965P-DS4", }, -+ { "GIGABYTE", "GA-EP35-DS3L", }, -+ { "GIGABYTE", "GA-EX58-UD4P", }, -+ { "GIGABYTE", "GA-M57SLI-S4", }, -+ { "GIGABYTE", "GA-M61P-S3", }, -+ { "GIGABYTE", "GA-MA69VM-S2", }, -+ { "GIGABYTE", "GA-MA770T-UD3P", }, -+ { "GIGABYTE", "GA-MA78G-DS3H", }, -+ { "GIGABYTE", "GA-MA78GM-S2H", }, -+ { "GIGABYTE", "GA-MA78GPM-DS2H", }, -+ { "GIGABYTE", "GA-MA790FX-DQ6", }, -+ { "GIGABYTE", "GA-MA790GP-DS4H", }, -+ { "Intel", "EP80759", }, -+ { "Jetway", "J7F4K1G5D-PB", }, -+ { "MSI", "MS-6153", }, -+ { "MSI", "MS-6156", }, -+ { "MSI", "MS-6330 (K7T Turbo)", }, -+ { "MSI", "MS-6570 (K7N2)", }, -+ { "MSI", "MS-7065", }, -+ { "MSI", "MS-7168 (Orion)", }, -+ { "MSI", "MS-7236 (945PL Neo3)", }, -+ { "MSI", "MS-7255 (P4M890M)", }, -+ { "MSI", "MS-7312 (K9MM-V)", }, -+ { "MSI", "MS-7345 (P35 Neo2-FIR)", }, -+ { "MSI", "MS-7368 (K9AG Neo2-Digital)", }, -+ { "MSI", "MS-7376 (K9A2 Platinum)", }, -+ { "NEC", "PowerMate 2000", }, -+ { "PC Engines", "Alix.1c", }, -+ { "PC Engines", "Alix.2c2", }, -+ { "PC Engines", "Alix.2c3", }, -+ { "PC Engines", "Alix.3c3", }, -+ { "PC Engines", "Alix.3d3", }, -+ { "PC Engines", "WRAP.2E", }, -+ { "RCA", "RM4100", }, -+ { "Shuttle", "FD37", }, -+ { "Sun", "Blade x6250", }, -+ { "Supermicro", "H8QC8", }, -+ { "Supermicro", "X8DTT-F", }, -+ { "Thomson", "IP1000", }, -+ { "TriGem", "Lomita", }, -+ { "T-Online", "S-100", }, -+ { "Tyan", "iS5375-1U", }, -+ { "Tyan", "S1846", }, -+ { "Tyan", "S2466", }, -+ { "Tyan", "S2881", }, -+ { "Tyan", "S2882", }, -+ { "Tyan", "S2882-D", }, -+ { "Tyan", "S2891", }, -+ { "Tyan", "S2892", }, -+ { "Tyan", "S2895", }, -+ { "Tyan", "S3095", }, -+ { "Tyan", "S5180", }, -+ { "Tyan", "S5191", }, -+ { "Tyan", "S5197", }, -+ { "Tyan", "S5211", }, -+ { "Tyan", "S5211-1U", }, -+ { "Tyan", "S5220", }, -+ { "Tyan", "S5375", }, -+ { "Tyan", "S5376G2NR/S5376WAG2NR", }, -+ { "Tyan", "S5377", }, -+ { "Tyan", "S5382 (Tempest i5000PW)", }, -+ { "Tyan", "S5397", }, -+ { "VIA", "EPIA-CN", }, -+ { "VIA", "EPIA-EX15000G", }, -+ { "VIA", "EPIA-LN", }, -+ { "VIA", "EPIA-M700", }, -+ { "VIA", "EPIA-NX15000G", }, -+ { "VIA", "EPIA-SP", }, -+ { "VIA", "NAB74X0", }, -+ { "VIA", "pc2500e", }, -+ { "VIA", "PC3500G", }, -+ { "VIA", "VB700X", }, -+ -+ {}, -+}; - -+/* Please keep this list alphabetically ordered by vendor/board. */ -+const struct board_info boards_bad[] = { - /* Verified non-working boards (for now). */ -- { "MSI", "MS-6178", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." }, -- { "MSI", "MS-7260 (K9N Neo)", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." }, -+ { "Abit", "IS-10", }, -+ { "ASRock", "K7VT4A+", }, -+ { "ASUS", "MEW-AM", }, -+ { "ASUS", "MEW-VM", }, -+ { "ASUS", "P3B-F", }, -+ { "ASUS", "P5BV-M", }, -+ { "Biostar", "M6TBA", }, -+ { "Boser", "HS-6637", }, -+ { "DFI", "855GME-MGF", }, -+ { "FIC", "VA-502", }, -+ { "MSI", "MS-6178", }, -+ { "MSI", "MS-7260 (K9N Neo)", }, -+ { "Soyo", "SY-5VD", }, -+ { "Sun", "Fire x4150", }, -+ { "Sun", "Fire x4200", }, -+ { "Sun", "Fire x4540", }, -+ { "Sun", "Fire x4600", }, -+ -+ {}, -+}; - -+/* Please keep this list alphabetically ordered by vendor/board. */ -+const struct board_info laptops_ok[] = { - /* Verified working laptops. */ -- /* None which need comments, yet... */ -- -- /* Verified non-working laptops (for now). */ -- { "Acer", "Aspire One", "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" }, -- { "ASUS", "Eee PC 701 4G", "It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." }, -- { "Dell", "Latitude CPi A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." }, -- { "HP/Compaq", "nx9010", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)." }, -- { "IBM/Lenovo", "Thinkpad T40p", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." }, -+ { "Lenovo", "3000 V100 TF05Cxx", }, -+ { "Acer", "Aspire 1520", }, - -- { NULL, NULL, 0 }, -+ {}, - }; - --static int url(const char *vendor, const char *board) --{ -- int i; -- const struct board_info_url *b = boards_url; -- -- for (i = 0; b[i].vendor != NULL; i++) { -- if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name)) -- return i; -- } -- -- return -1; --} -- --static int note(const char *vendor, const char *board) --{ -- int i; -- const struct board_info_notes *n = boards_notes; -- -- for (i = 0; n[i].vendor != NULL; i++) { -- if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name)) -- return i; -- } -- -- return -1; --} -- --void print_supported_chipsets_wiki(void) --{ -- int i, j, enablescount = 0, color = 1; -- const struct penable *e; -- -- for (e = chipset_enables; e->vendor_name != NULL; e++) -- enablescount++; -- -- printf("\n== Supported chipsets ==\n\nTotal amount of supported " -- "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| " -- "valign=\"top\"|\n\n%s", enablescount, chipset_th); -- -- e = chipset_enables; -- for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) { -- /* Alternate colors if the vendor changes. */ -- if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name)) -- color = !color; -- -- printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s " -- "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd", -- e[i].vendor_name, e[i].device_name, -- e[i].vendor_id, e[i].device_id, -- (e[i].status == OK) ? "{{OK}}" : "?"); -- -- /* Split table in three columns. */ -- if (j >= (enablescount / 3 + 1)) { -- printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th); -- j = 0; -- } -- } -- -- printf("\n|}\n\n|}\n"); --} -- --static void wiki_helper(const char *heading, const char *status, -- int cols, const struct board_info boards[]) --{ -- int i, j, k, c, boardcount = 0, color = 1, num_notes = 0; -- const struct board_info *b; -- const struct board_info_url *u = boards_url; -- char *notes = calloc(1, 1); -- char tmp[900 + 1]; -- -- for (b = boards; b->vendor != NULL; b++) -- boardcount++; -- -- printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" -- "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", -- heading, boardcount, board_th); -- -- for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) { -- /* Alternate colors if the vendor changes. */ -- if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor)) -- color = !color; -- -- k = url(b[i].vendor, b[i].name); -- c = note(b[i].vendor, b[i].name); -- -- printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||" -- " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor, -- (k != -1 && u[k].url) ? "[" : "", -- (k != -1 && u[k].url) ? u[k].url : "", -- b[i].name, (k != -1 && u[k].url) ? "]" : "", status); -- -- if (c != -1) { -- printf("%d\n", num_notes + 1); -- snprintf((char *)&tmp, 900, "%d %s
\n", -- 1 + num_notes++, boards_notes[c].note); -- notes = strcat_realloc(notes, (char *)&tmp); -- } else { -- printf("\n"); -- } -- -- /* Split table in 'cols' columns. */ -- if (j >= (boardcount / cols + 1)) { -- printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th); -- j = 0; -- } -- } -- -- printf("\n|}\n\n|}\n"); -- -- if (num_notes > 0) -- printf("\n\n%s\n", notes); -- free(notes); --} -- --static void wiki_helper2(const char *heading, int cols) --{ -- int i, j, k, boardcount = 0, color = 1; -- struct board_pciid_enable *b; -- const struct board_info_url *u = boards_url; -- -- for (b = board_pciid_enables; b->vendor_name != NULL; b++) -- boardcount++; -- -- printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" -- "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", -- heading, boardcount, board_th2); -- -- b = board_pciid_enables; -- for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) { -- /* Alternate colors if the vendor changes. */ -- if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name)) -- color = !color; -- -- k = url(b[i].vendor_name, b[i].board_name); -- -- printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s " -- "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd", -- b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "", -- (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name, -- (k != -1 && u[k].url) ? "]" : "", -- (b[i].lb_vendor) ? "-m " : "—", -- (b[i].lb_vendor) ? b[i].lb_vendor : "", -- (b[i].lb_vendor) ? ":" : "", -- (b[i].lb_vendor) ? b[i].lb_part : ""); -- -- /* Split table in three columns. */ -- if (j >= (boardcount / cols + 1)) { -- printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2); -- j = 0; -- } -- } -- -- printf("\n|}\n\n|}\n"); --} -- --void print_supported_boards_wiki(void) --{ -- printf("%s", board_intro); -- wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok); -- wiki_helper2("Known good (with write-enable code in flashrom)", 3); -- wiki_helper("Not supported (yet)", "No", 3, boards_bad); -- -- printf("%s", laptop_intro); -- wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok); -- wiki_helper("Not supported (yet)", "No", 1, laptops_bad); --} -- --void print_supported_chips_wiki(void) --{ -- int i = 0, c = 1, chipcount = 0; -- struct flashchip *f, *old = NULL; -- uint32_t t; -- -- for (f = flashchips; f->name != NULL; f++) -- chipcount++; -- -- printf("\n== Supported chips ==\n\nTotal amount of supported " -- "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n" -- "| valign=\"top\"|\n\n%s", chipcount, chip_th); -- -- for (f = flashchips; f->name != NULL; f++, i++) { -- /* Don't print "unknown XXXX SPI chip" entries. */ -- if (!strncmp(f->name, "unknown", 7)) -- continue; -- -- /* Alternate colors if the vendor changes. */ -- if (old != NULL && strcmp(old->vendor, f->vendor)) -- c = !c; -- -- t = f->tested; -- printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d " -- "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n", -- (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name, -- f->total_size, flashbuses_to_text(f->bustype), -- (t & TEST_OK_PROBE) ? "OK" : -- (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"), -- (t & TEST_OK_READ) ? "OK" : -- (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"), -- (t & TEST_OK_ERASE) ? "OK" : -- (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"), -- (t & TEST_OK_WRITE) ? "OK" : -- (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?")); -- -- /* Split table into three columns. */ -- if (i >= (chipcount / 3 + 1)) { -- printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th); -- i = 0; -- } -- -- old = f; -- } -- -- printf("\n|}\n\n|}\n"); --} -- --void print_supported_pcidevs_wiki(struct pcidev_status *devs) --{ -- int i = 0; -- static int c = 0; -- -- /* Alternate colors if the vendor changes. */ -- c = !c; -- -- for (i = 0; devs[i].vendor_name != NULL; i++) { -- printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || " -- "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd", -- devs[i].vendor_name, devs[i].device_name, -- devs[i].vendor_id, devs[i].device_id, -- (devs[i].status == PCI_NT) ? (c) ? "?2" : "?" : "OK"); -- } --} -- --void print_wiki_tables(void) --{ -- time_t t = time(NULL); -- -- printf(wiki_header, ctime(&t), flashrom_version); -- print_supported_chips_wiki(); -- print_supported_chipsets_wiki(); -- print_supported_boards_wiki(); -- printf("%s", programmer_section); -- print_supported_pcidevs_wiki(nics_3com); -- print_supported_pcidevs_wiki(satas_sii); -- printf("\n|}\n"); --} -+/* Please keep this list alphabetically ordered by vendor/board. */ -+const struct board_info laptops_bad[] = { -+ /* Verified non-working laptops (for now). */ -+ { "Acer", "Aspire One", }, -+ { "ASUS", "Eee PC 701 4G", }, -+ { "Dell", "Latitude CPi A366XT", }, -+ { "HP/Compaq", "nx9010", }, -+ { "IBM/Lenovo", "Thinkpad T40p", }, -+ { "IBM/Lenovo", "240", }, -+ -+ {}, -+}; -+#endif - -diff --git a/print_wiki.c b/print_wiki.c -new file mode 100644 -index 0000000..87adf4d ---- /dev/null -+++ b/print_wiki.c -@@ -0,0 +1,600 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Uwe Hermann -+ * Copyright (C) 2009 Carl-Daniel Hailfinger -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include "flash.h" -+#include "flashchips.h" -+ -+struct board_info_url { -+ const char *vendor; -+ const char *name; -+ const char *url; -+}; -+ -+struct board_info_notes { -+ const char *vendor; -+ const char *name; -+ const char *note; -+}; -+ -+const char *wiki_header = "= Supported devices =\n\n\ -+
\n\ -+Please do '''not''' edit these tables in the wiki directly, they are \ -+generated by pasting '''flashrom -z''' output.
\ -+'''Last update:''' %s(generated by flashrom %s)\n
\n"; -+ -+const char *chipset_th = "{| border=\"0\" style=\"font-size: smaller\"\n\ -+|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -+! align=\"left\" | Southbridge\n! align=\"left\" | PCI IDs\n\ -+! align=\"left\" | Status\n\n"; -+ -+const char *board_th = "{| border=\"0\" style=\"font-size: smaller\" \ -+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -+! align=\"left\" | Mainboard\n! align=\"left\" | Status\n\n"; -+ -+const char *board_th2 = "{| border=\"0\" style=\"font-size: smaller\" \ -+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -+! align=\"left\" | Mainboard\n! align=\"left\" | Required option\n\ -+! align=\"left\" | Status\n\n"; -+ -+const char *board_intro = "\ -+\n== Supported mainboards ==\n\n\ -+In general, it is very likely that flashrom works out of the box even if your \ -+mainboard is not listed below.\n\nThis is a list of mainboards where we have \ -+verified that they either do or do not need any special initialization to \ -+make flashrom work (given flashrom supports the respective chipset and flash \ -+chip), or that they do not yet work at all. If they do not work, support may \ -+or may not be added later.\n\n\ -+Mainboards which don't appear in the list may or may not work (we don't \ -+know, someone has to give it a try). Please report any further verified \ -+mainboards on the [[Mailinglist|mailing list]].\n"; -+ -+const char *chip_th = "{| border=\"0\" style=\"font-size: smaller\" \ -+valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -+! align=\"left\" | Device\n! align=\"left\" | Size / KB\n\ -+! align=\"left\" | Type\n! align=\"left\" colspan=\"4\" | Status\n\n\ -+|- bgcolor=\"#6699ff\"\n| colspan=\"4\" |  \n\ -+| Probe\n| Read\n| Erase\n| Write\n\n"; -+ -+const char *programmer_section = "\ -+\n== Supported programmers ==\n\nThis is a list \ -+of supported PCI devices flashrom can use as programmer:\n\n{| border=\"0\" \ -+valign=\"top\"\n| valign=\"top\"|\n\n{| border=\"0\" style=\"font-size: \ -+smaller\" valign=\"top\"\n|- bgcolor=\"#6699dd\"\n! align=\"left\" | Vendor\n\ -+! align=\"left\" | Device\n! align=\"left\" | PCI IDs\n\ -+! align=\"left\" | Status\n\n"; -+ -+const char *laptop_intro = "\n== Supported laptops/notebooks ==\n\n\ -+In general, flashing laptops is more difficult because laptops\n\n\ -+* often use the flash chip for stuff besides the BIOS,\n\ -+* often have special protection stuff which has to be handled by flashrom,\n\ -+* often use flash translation circuits which need drivers in flashrom.\n\n\ -+
\n\ -+'''IMPORTANT:''' At this point we recommend to '''not''' use flashrom on \ -+untested laptops unless you have a means to recover from a flashing that goes \ -+wrong (a working backup flash chip and/or good soldering skills).\n
\n"; -+ -+/* Please keep these lists alphabetically ordered by vendor/board. */ -+const struct board_info_url boards_url[] = { -+ /* Verified working boards that don't need write-enables. */ -+ { "Abit", "AX8", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?DEFTITLE=Y&fMTYPE=Socket%20939&pMODEL_NAME=AX8" }, -+ { "Abit", "Fatal1ty F-I90HD", "http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?pMODEL_NAME=Fatal1ty+F-I90HD&fMTYPE=LGA775" }, -+ { "Advantech", "PCM-5820", "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm" }, -+ { "ASI", "MB-5BLMP", "http://www.hojerteknik.com/winnet.htm" }, -+ { "ASRock", "A770CrossFire", "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire&s=AM2\%2b" }, -+ { "ASRock", "K8S8X", "http://www.asrock.com/mb/overview.asp?Model=K8S8X" }, -+ { "ASRock", "M3A790GXH/128M" "http://www.asrock.com/MB/overview.asp?Model=M3A790GXH/128M" }, -+ { "ASUS", "A7N8X Deluxe", "http://www.asus.com/product.aspx?P_ID=wAsRYm41KTp78MFC" }, -+ { "ASUS", "A7N8X-E Deluxe", "http://www.asus.com/product.aspx?P_ID=TmQtPJv4jIxmL9C2" }, -+ { "ASUS", "A7V133", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socka/kt133a/a7v133/" }, -+ { "ASUS", "A7V400-MX", "http://www.asus.com/product.aspx?P_ID=hORgEHRBDLMfwAwx" }, -+ { "ASUS", "A7V8X-MX", "http://www.asus.com/product.aspx?P_ID=SEJOOYqfuQPitx2H" }, -+ { "ASUS", "A8N-E", "http://www.asus.com/product.aspx?P_ID=DzbA8hgqchMBOVRz" }, -+ { "ASUS", "A8NE-FM/S", "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM" }, -+ { "ASUS", "A8N-SLI", "http://www.asus.com/product.aspx?P_ID=J9FKa8z2xVId3pDK" }, -+ { "ASUS", "A8N-SLI Premium", "http://www.asus.com/product.aspx?P_ID=nbulqxniNmzf0mH1" }, -+ { "ASUS", "A8V Deluxe", "http://www.asus.com/product.aspx?P_ID=tvpdgPNCPaABZRVU" }, -+ { "ASUS", "A8V-E Deluxe", "http://www.asus.com/product.aspx?P_ID=hQBPIJWEZnnGAZEh" }, -+ { "ASUS", "A8V-E SE", "http://www.asus.com/product.aspx?P_ID=VMfiJJRYTHM4gXIi" }, -+ { "ASUS", "K8V", "http://www.asus.com/product.aspx?P_ID=fG2KZOWF7v6MRFRm" }, -+ { "ASUS", "K8V SE Deluxe", "http://www.asus.com/product.aspx?P_ID=65HeDI8XM1u6Uy6o" }, -+ { "ASUS", "K8V-X SE", "http://www.asus.com/product.aspx?P_ID=lzDXlbBVHkdckHVr" }, -+ { "ASUS", "M2A-MX", "http://www.asus.com/product.aspx?P_ID=BmaOnPewi1JgltOZ" }, -+ { "ASUS", "M2A-VM", "http://www.asus.com/product.aspx?P_ID=St3pWpym8xXpROQS" }, -+ { "ASUS", "M2N-E", "http://www.asus.com/product.aspx?P_ID=NFlvt10av3F7ayQ9" }, -+ { "ASUS", "M2V", "http://www.asus.com/product.aspx?P_ID=OqYlEDFfF6ZqZGvp" }, -+ { "ASUS", "M3A78-EM", "http://www.asus.com/product.aspx?P_ID=KjpYqzmAd9vsTM2D" }, -+ { "ASUS", "P2B", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b/" }, -+ { "ASUS", "P2B-D", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" }, -+ { "ASUS", "P2B-DS", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-ds/" }, -+ { "ASUS", "P2B-F", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p2b-d/" }, -+ { "ASUS", "P2L97-S", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440lx/p2l97-s/" }, -+ { "ASUS", "P5B", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B/" }, -+ { "ASUS", "P5B-Deluxe", "http://www.asus.com/product.aspx?P_ID=bswT66IBSb2rEWNa" }, -+ { "ASUS", "P5KC", "http://www.asus.com/product.aspx?P_ID=fFZ8oUIGmLpwNMjj" }, -+ { "ASUS", "P5L-MX", "http://www.asus.com/product.aspx?P_ID=X70d3NCzH2DE9vWH" }, -+ { "ASUS", "P6T Deluxe", "http://www.asus.com/product.aspx?P_ID=vXixf82co6Q5v0BZ" }, -+ { "ASUS", "P6T Deluxe V2", "http://www.asus.com/product.aspx?P_ID=iRlP8RG9han6saZx" }, -+ { "A-Trend", "ATC-6220", "http://www.motherboard.cz/mb/atrend/atc6220.htm" }, -+ { "BCOM", "WinNET100", "http://www.coreboot.org/BCOM_WINNET100" }, -+ { "DFI", "Blood-Iron P35 T2RL", "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1" }, -+ { "Elitegroup", "K7S5A", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=279&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, -+ { "Elitegroup", "P6VAP-A+", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=117&CategoryID=1&DetailName=Specification&MenuID=1&LanID=0" }, -+ { "GIGABYTE", "GA-6BXC", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1445" }, -+ { "GIGABYTE", "GA-6BXDU", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1429" }, -+ { "GIGABYTE", "GA-6ZMA", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1541" }, -+ { "GIGABYTE", "GA-965P-DS4", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2288" }, -+ { "GIGABYTE", "GA-EX58-UD4P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2986" }, -+ { "GIGABYTE", "GA-EP35-DS3L", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2778" }, -+ { "GIGABYTE", "GA-MA69VM-S2", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2500" }, -+ { "GIGABYTE", "GA-MA790GP-DS4H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2887" }, -+ { "GIGABYTE", "GA-MA78GPM-DS2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2859" }, -+ { "GIGABYTE", "GA-MA770T-UD3P", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=3096" }, -+ { "Intel", "EP80759", NULL }, -+ { "Jetway", "J7F4K1G5D-PB", "http://www.jetway.com.tw/jetway/system/productshow2.asp?id=389&proname=J7F4K1G5D-P" }, -+ { "MSI", "MS-6153", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=336" }, -+ { "MSI", "MS-6156", "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm" }, -+ { "MSI", "MS-6330 (K7T Turbo)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=327" }, -+ { "MSI", "MS-6570 (K7N2)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=519" }, -+ { "MSI", "MS-7065", "http://browse.geekbench.ca/geekbench2/view/53114" }, -+ { "MSI", "MS-7168 (Orion)", "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart" }, -+ { "MSI", "MS-7236 (945PL Neo3)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1173" }, -+ { "MSI", "MS-7255 (P4M890M)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1082" }, -+ { "MSI", "MS-7345 (P35 Neo2-FIR)","http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1261" }, -+ { "MSI", "MS-7312 (K9MM-V)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1104" }, -+ { "MSI", "MS-7368 (K9AG Neo2-Digital)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1241" }, -+ { "MSI", "MS-7376 (K9A2 Platinum)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=1332" }, -+ { "NEC", "PowerMate 2000", "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/" }, -+ { "PC Engines", "Alix.1c", "http://pcengines.ch/alix1c.htm" }, -+ { "PC Engines", "Alix.2c2", "http://pcengines.ch/alix2c2.htm" }, -+ { "PC Engines", "Alix.2c3", "http://pcengines.ch/alix2c3.htm" }, -+ { "PC Engines", "Alix.3c3", "http://pcengines.ch/alix3c3.htm" }, -+ { "PC Engines", "Alix.3d3", "http://pcengines.ch/alix3d3.htm" }, -+ { "PC Engines", "WRAP.2E", "http://pcengines.ch/wrap2e1.htm" }, -+ { "RCA", "RM4100", "http://www.settoplinux.org/index.php?title=RCA_RM4100" }, -+ { "Shuttle", "FD37", "http://www.shuttle.eu/products/discontinued/barebones/sd37p2/" }, -+ { "Sun", "Blade x6250", "http://www.sun.com/servers/blades/x6250/" }, -+ { "Supermicro", "H8QC8", "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm" }, -+ { "Supermicro", "X8DTT-F", "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-F.cfm" }, -+ { "Tekram", "P6Pro-A5", "http://www.motherboard.cz/mb/tekram/P6Pro-A5.htm" }, -+ { "Thomson", "IP1000", "http://www.settoplinux.org/index.php?title=Thomson_IP1000" }, -+ { "TriGem", "Lomita", "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml" }, -+ { "T-Online", "S-100", "http://wiki.freifunk-hannover.de/T-Online_S_100" }, -+ { "Tyan", "iS5375-1U", "http://www.tyan.com/product_board_detail.aspx?pid=610" }, -+ { "Tyan", "S1846", "http://www.tyan.com/archive/products/html/tsunamiatx.html" }, -+ { "Tyan", "S2466", "http://www.tyan.com/product_board_detail.aspx?pid=461" }, -+ { "Tyan", "S2881", "http://www.tyan.com/product_board_detail.aspx?pid=115" }, -+ { "Tyan", "S2882", "http://www.tyan.com/product_board_detail.aspx?pid=121" }, -+ { "Tyan", "S2882-D", "http://www.tyan.com/product_board_detail.aspx?pid=127" }, -+ { "Tyan", "S2891", "http://www.tyan.com/product_board_detail.aspx?pid=144" }, -+ { "Tyan", "S2892", "http://www.tyan.com/product_board_detail.aspx?pid=145" }, -+ { "Tyan", "S2895", "http://www.tyan.com/archive/products/html/thunderk8we.html" }, -+ { "Tyan", "S3095", "http://www.tyan.com/product_board_detail.aspx?pid=181" }, -+ { "Tyan", "S5180", "http://www.tyan.com/product_board_detail.aspx?pid=456" }, -+ { "Tyan", "S5191", "http://www.tyan.com/product_board_detail.aspx?pid=343" }, -+ { "Tyan", "S5197", "http://www.tyan.com/product_board_detail.aspx?pid=349" }, -+ { "Tyan", "S5211", "http://www.tyan.com/product_board_detail.aspx?pid=591" }, -+ { "Tyan", "S5211-1U", "http://www.tyan.com/product_board_detail.aspx?pid=593" }, -+ { "Tyan", "S5220", "http://www.tyan.com/product_board_detail.aspx?pid=597" }, -+ { "Tyan", "S5375", "http://www.tyan.com/product_board_detail.aspx?pid=566" }, -+ { "Tyan", "S5376G2NR/S5376WAG2NR","http://www.tyan.com/product_board_detail.aspx?pid=605" }, -+ { "Tyan", "S5377", "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017" }, -+ { "Tyan", "S5382 (Tempest i5000PW)", "http://www.tyan.com/product_board_detail.aspx?pid=439" }, -+ { "Tyan", "S5397", "http://www.tyan.com/product_board_detail.aspx?pid=560" }, -+ { "VIA", "EPIA-EX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450" }, -+ { "VIA", "EPIA-LN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473" }, -+ { "VIA", "EPIA-M700", "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700" }, -+ { "VIA", "EPIA-NX15000G", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470" }, -+ { "VIA", "NAB74X0", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590" }, -+ { "VIA", "pc2500e", "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp" }, -+ { "VIA", "VB700X", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490" }, -+ -+ /* Verified working boards that DO need write-enables. */ -+ { "Abit", "VT6X4", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=Slot%201&pMODEL_NAME=VT6X4" }, -+ { "Abit", "IP35", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35" }, -+ { "Abit", "IP35 Pro", "http://www.abit.com.tw/page/de/motherboard/motherboard_detail.php?fMTYPE=LGA775&pMODEL_NAME=IP35%20Pro" }, -+ { "Abit", "NF7-S", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?fMTYPE=Socket%20A&pMODEL_NAME=NF7-S"}, -+ { "Acorp", "6A815EPD", "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp" }, -+ { "agami", "Aruma", "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series" }, -+ { "Albatron", "PM266A Pro", "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56" }, /* FIXME */ -+ { "AOpen", "vKM400Am-S", "http://usa.aopen.com/products_detail.aspx?Auno=824" }, -+ { "Artec Group", "DBE61", "http://wiki.thincan.org/DBE61" }, -+ { "Artec Group", "DBE62", "http://wiki.thincan.org/DBE62" }, -+ { "ASUS", "A7V600-X", "http://www.asus.com/product.aspx?P_ID=L2XYS0rmtCjeOr4k" }, -+ { "ASUS", "A7V8X", "http://www.asus.com/product.aspx?P_ID=qfpaGrAy2kLVo0f2" }, -+ { "ASUS", "A7V8X-MX SE", "http://www.asus.com/product.aspx?P_ID=1guVBT1qV5oqhHyZ" }, -+ { "ASUS", "A7V8X-X", "http://www.asus.com/product.aspx?P_ID=YcXfRrWHZ9RKoVmw" }, -+ { "ASUS", "M2NBP-VM CSM", "http://www.asus.com/product.aspx?P_ID=MnOfzTGd2KkwG0rF" }, -+ { "ASUS", "M2V-MX", "http://www.asus.com/product.aspx?P_ID=7grf8Ci4yxnqzt3z" }, -+ { "ASUS", "P4B266", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock478/p4b266/" }, -+ { "ASUS", "P4C800-E Deluxe", "http://www.asus.com/product.aspx?P_ID=cFuVCr9bXXCckmcK" }, -+ { "ASUS", "P4B266-LM", "http://esupport.sony.com/US/perl/swu-list.pl?mdl=PCVRX650" }, -+ { "ASUS", "P4P800-E Deluxe", "http://www.asus.com/product.aspx?P_ID=INIJUvLlif7LHp3g" }, -+ { "ASUS", "P5ND2-SLI Deluxe", "http://www.asus.com/product.aspx?P_ID=WY7XroDuUImVbgp5" }, -+ { "ASUS", "P5A", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock7/ali/p5a/" }, -+ { "Biostar", "P4M80-M4", "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4" }, -+ { "Dell", "PowerEdge 1850", "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm" }, -+ { "Elitegroup", "K7S6A", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=77&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" }, -+ { "Elitegroup", "K7VTA3", "http://www.ecs.com.tw/ECSWebSite/Products/ProductsDetail.aspx?detailid=264&CategoryID=1&DetailName=Specification&MenuID=52&LanID=0" }, -+ { "EPoX", "EP-8K5A2", "http://www.epox.com/product.asp?ID=EP-8K5A2" }, -+ { "EPoX", "EP-8RDA3+", "http://www.epox.com/product.asp?ID=EP-8RDA3plus" }, -+ { "EPoX", "EP-BX3", "http://www.epox.com/product.asp?ID=EP-BX3" }, -+ { "GIGABYTE", "GA-2761GXDK", "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/" }, -+ { "GIGABYTE", "GA-7VT600", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1666" }, -+ { "GIGABYTE", "GA-7ZM", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1366" }, -+ { "GIGABYTE", "GA-K8N-SLI", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=1928" }, -+ { "GIGABYTE", "GA-M57SLI-S4", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2287" }, -+ { "GIGABYTE", "GA-M61P-S3", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2434" }, -+ { "GIGABYTE", "GA-MA78G-DS3H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2800" }, /* TODO: Rev 1.x or 2.x? */ -+ { "GIGABYTE", "GA-MA78GM-S2H", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2758" }, /* TODO: Rev. 1.0, 1.1, or 2.x? */ -+ { "GIGABYTE", "GA-MA790FX-DQ6", "http://www.gigabyte.com.tw/Products/Motherboard/Products_Spec.aspx?ProductID=2690" }, -+ { "HP", "DL145 G3", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351" }, -+ { "HP", "Vectra VL400 PC", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060658&lang=en&cc=us" }, -+ { "HP", "Vectra VL420 SFF PC", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060661&lang=en&cc=us" }, -+ { "IBM", "x3455", "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html" }, -+ { "Intel", "D201GLY", "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm" }, -+ { "IWILL", "DK8-HTX", "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98" }, -+ { "Kontron", "986LCD-M", "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html" }, -+ { "Mitac", "6513WU", "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm" }, -+ { "MSI", "MS-6590 (KT4 Ultra)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=502" }, -+ { "MSI", "MS-6702E (K8T Neo2-F)","http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=588" }, -+ { "MSI", "MS-6712 (KT4V)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=505" }, -+ { "MSI", "MS-7005 (651M-L)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=559" }, -+ { "MSI", "MS-7046", "http://www.heimir.de/ms7046/" }, -+ { "MSI", "MS-7135 (K8N Neo3)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=170" }, -+ { "Shuttle", "AK31", "http://www.motherboard.cz/mb/shuttle/AK31.htm" }, -+ { "Shuttle", "AK38N", "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/" }, -+ { "Shuttle", "FN25", "http://www.shuttle.eu/products/discontinued/barebones/sn25p/?0=" }, -+ { "Soyo", "SY-7VCA", "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html" }, -+ { "Tyan", "S2498 (Tomcat K7M)", "http://www.tyan.com/archive/products/html/tomcatk7m.html" }, -+ { "VIA", "EPIA-CN", "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400" }, -+ { "VIA", "EPIA M/MII/...", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202" }, /* EPIA-MII link for now */ -+ { "VIA", "EPIA-N/NL", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221" }, /* EPIA-N link for now */ -+ { "VIA", "EPIA SP", "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261" }, -+ { "VIA", "PC3500G", "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp" }, -+ -+ /* Verified non-working boards (for now). */ -+ { "Abit", "IS-10", "http://www.abit.com.tw/page/en/motherboard/motherboard_detail.php?pMODEL_NAME=IS-10&fMTYPE=Socket+478" }, -+ { "ASRock", "K7VT4A+", "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%%2b&s=" }, -+ { "ASUS", "MEW-AM", "ftp://ftp.asus.com.tw/pub/ASUS/mb/sock370/810/mew-am/" }, -+ { "ASUS", "MEW-VM", "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm" }, -+ { "ASUS", "P3B-F", "ftp://ftp.asus.com.tw/pub/ASUS/mb/slot1/440bx/p3b-f/" }, -+ { "ASUS", "P5BV-M", "ftp://ftp.asus.com.tw/pub/ASUS/mb/socket775/P5B-VM/" }, -+ { "Biostar", "M6TBA", "ftp://ftp.biostar-usa.com/manuals/M6TBA/" }, -+ { "Boser", "HS-6637", "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf" }, -+ { "DFI", "855GME-MGF", "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433" }, -+ { "FIC", "VA-502", "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/" }, -+ { "MSI", "MS-6178", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=343" }, -+ { "MSI", "MS-7260 (K9N Neo)", "http://www.msi.com/index.php?func=proddesc&maincat_no=1&prod_no=255" }, -+ { "Soyo", "SY-5VD", "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English" }, -+ { "Sun", "Fire x4540", "http://www.sun.com/servers/x64/x4540/" }, -+ { "Sun", "Fire x4150", "http://www.sun.com/servers/x64/x4150/" }, -+ { "Sun", "Fire x4200", "http://www.sun.com/servers/entry/x4200/" }, -+ { "Sun", "Fire x4600", "http://www.sun.com/servers/x64/x4600/" }, -+ -+ /* Verified working laptops. */ -+ { "Acer", "Aspire 1520", "http://support.acer.com/us/en/acerpanam/notebook/0000/Acer/Aspire1520/Aspire1520nv.shtml" }, -+ { "Lenovo", "3000 V100 TF05Cxx", "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop" }, -+ -+ /* Verified non-working laptops (for now). */ -+ { "Acer", "Aspire One", NULL }, -+ { "ASUS", "Eee PC 701 4G", "http://www.asus.com/product.aspx?P_ID=h6SPd3tEzLEsrEiS" }, -+ { "Dell", "Latitude CPi A366XT", "http://www.coreboot.org/Dell_Latitude_CPi_A366XT" }, -+ { "HP/Compaq", "nx9010", "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514" }, -+ { "IBM/Lenovo", "Thinkpad T40p", "http://www.thinkwiki.org/wiki/Category:T40p" }, -+ { "IBM/Lenovo", "240", "http://www.stanford.edu/~bresnan//tp240.html" }, -+ -+ { NULL, NULL, 0 }, -+}; -+ -+/* Please keep these lists alphabetically ordered by vendor/board. */ -+const struct board_info_notes boards_notes[] = { -+ /* Verified working boards that don't need write-enables. */ -+ { "ASI", "MB-5BLMP", "Used in the IGEL WinNET III thin client." }, -+ { "ASRock", "K8S8X", "The Super I/O isn't found on this board. See http://www.flashrom.org/pipermail/flashrom/2009-November/000937.html." }, -+ { "ASUS", "A8V-E SE", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html." }, -+ { "ASUS", "M2A-VM", "See http://www.coreboot.org/pipermail/coreboot/2007-September/025281.html." }, -+ { "BCOM", "WinNET100", "Used in the IGEL-316 thin client." }, -+ { "GIGABYTE", "GA-7ZM", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option." }, -+ { "ASUS", "M2N-E", "If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See http://www.flashrom.org/pipermail/flashrom/2009-November/000879.html" }, -+ -+ /* Verified working boards that DO need write-enables. */ -+ { "Acer", "Aspire One", "See http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html." }, -+ -+ /* Verified non-working boards (for now). */ -+ { "MSI", "MS-6178", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot." }, -+ { "MSI", "MS-7260 (K9N Neo)", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot." }, -+ -+ /* Verified working laptops. */ -+ /* None which need comments, yet... */ -+ -+ /* Verified non-working laptops (for now). */ -+ { "Acer", "Aspire One", "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html" }, -+ { "ASUS", "Eee PC 701 4G", "It seems the chip (25X40VSIG) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)." }, -+ { "Dell", "Latitude CPi A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop." }, -+ { "HP/Compaq", "nx9010", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)." }, -+ { "IBM/Lenovo", "Thinkpad T40p", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later." }, -+ -+ { NULL, NULL, 0 }, -+}; -+ -+static int url(const char *vendor, const char *board) -+{ -+ int i; -+ const struct board_info_url *b = boards_url; -+ -+ for (i = 0; b[i].vendor != NULL; i++) { -+ if (!strcmp(vendor, b[i].vendor) && !strcmp(board, b[i].name)) -+ return i; -+ } -+ -+ return -1; -+} -+ -+static int note(const char *vendor, const char *board) -+{ -+ int i; -+ const struct board_info_notes *n = boards_notes; -+ -+ for (i = 0; n[i].vendor != NULL; i++) { -+ if (!strcmp(vendor, n[i].vendor) && !strcmp(board, n[i].name)) -+ return i; -+ } -+ -+ return -1; -+} -+ -+void print_supported_chipsets_wiki(void) -+{ -+ int i, j, enablescount = 0, color = 1; -+ const struct penable *e; -+ -+ for (e = chipset_enables; e->vendor_name != NULL; e++) -+ enablescount++; -+ -+ printf("\n== Supported chipsets ==\n\nTotal amount of supported " -+ "chipsets: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n| " -+ "valign=\"top\"|\n\n%s", enablescount, chipset_th); -+ -+ e = chipset_enables; -+ for (i = 0, j = 0; e[i].vendor_name != NULL; i++, j++) { -+ /* Alternate colors if the vendor changes. */ -+ if (i > 0 && strcmp(e[i].vendor_name, e[i - 1].vendor_name)) -+ color = !color; -+ -+ printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s " -+ "|| %04x:%04x || %s\n", (color) ? "eeeeee" : "dddddd", -+ e[i].vendor_name, e[i].device_name, -+ e[i].vendor_id, e[i].device_id, -+ (e[i].status == OK) ? "{{OK}}" : "?"); -+ -+ /* Split table in three columns. */ -+ if (j >= (enablescount / 3 + 1)) { -+ printf("\n|}\n\n| valign=\"top\"|\n\n%s", chipset_th); -+ j = 0; -+ } -+ } -+ -+ printf("\n|}\n\n|}\n"); -+} -+ -+static void wiki_helper(const char *heading, const char *status, -+ int cols, const struct board_info boards[]) -+{ -+ int i, j, k, c, boardcount = 0, color = 1, num_notes = 0; -+ const struct board_info *b; -+ const struct board_info_url *u = boards_url; -+ char *notes = calloc(1, 1); -+ char tmp[900 + 1]; -+ -+ for (b = boards; b->vendor != NULL; b++) -+ boardcount++; -+ -+ printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" -+ "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", -+ heading, boardcount, board_th); -+ -+ for (i = 0, j = 0, b = boards; b[i].vendor != NULL; i++, j++) { -+ /* Alternate colors if the vendor changes. */ -+ if (i > 0 && strcmp(b[i].vendor, b[i - 1].vendor)) -+ color = !color; -+ -+ k = url(b[i].vendor, b[i].name); -+ c = note(b[i].vendor, b[i].name); -+ -+ printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s ||" -+ " {{%s}}", (color) ? "eeeeee" : "dddddd", b[i].vendor, -+ (k != -1 && u[k].url) ? "[" : "", -+ (k != -1 && u[k].url) ? u[k].url : "", -+ b[i].name, (k != -1 && u[k].url) ? "]" : "", status); -+ -+ if (c != -1) { -+ printf("%d\n", num_notes + 1); -+ snprintf((char *)&tmp, 900, "%d %s
\n", -+ 1 + num_notes++, boards_notes[c].note); -+ notes = strcat_realloc(notes, (char *)&tmp); -+ } else { -+ printf("\n"); -+ } -+ -+ /* Split table in 'cols' columns. */ -+ if (j >= (boardcount / cols + 1)) { -+ printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th); -+ j = 0; -+ } -+ } -+ -+ printf("\n|}\n\n|}\n"); -+ -+ if (num_notes > 0) -+ printf("\n\n%s\n", notes); -+ free(notes); -+} -+ -+static void wiki_helper2(const char *heading, int cols) -+{ -+ int i, j, k, boardcount = 0, color = 1; -+ struct board_pciid_enable *b; -+ const struct board_info_url *u = boards_url; -+ -+ for (b = board_pciid_enables; b->vendor_name != NULL; b++) -+ boardcount++; -+ -+ printf("\n'''%s'''\n\nTotal amount of boards: '''%d'''\n\n" -+ "{| border=\"0\" valign=\"top\"\n| valign=\"top\"|\n\n%s", -+ heading, boardcount, board_th2); -+ -+ b = board_pciid_enables; -+ for (i = 0, j = 0; b[i].vendor_name != NULL; i++, j++) { -+ /* Alternate colors if the vendor changes. */ -+ if (i > 0 && strcmp(b[i].vendor_name, b[i - 1].vendor_name)) -+ color = !color; -+ -+ k = url(b[i].vendor_name, b[i].board_name); -+ -+ printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s%s %s%s " -+ "|| %s%s%s%s || {{OK}}\n", (color) ? "eeeeee" : "dddddd", -+ b[i].vendor_name, (k != -1 && u[k].url) ? "[" : "", -+ (k != -1 && u[k].url) ? u[k].url : "", b[i].board_name, -+ (k != -1 && u[k].url) ? "]" : "", -+ (b[i].lb_vendor) ? "-m " : "—", -+ (b[i].lb_vendor) ? b[i].lb_vendor : "", -+ (b[i].lb_vendor) ? ":" : "", -+ (b[i].lb_vendor) ? b[i].lb_part : ""); -+ -+ /* Split table in three columns. */ -+ if (j >= (boardcount / cols + 1)) { -+ printf("\n|}\n\n| valign=\"top\"|\n\n%s", board_th2); -+ j = 0; -+ } -+ } -+ -+ printf("\n|}\n\n|}\n"); -+} -+ -+void print_supported_boards_wiki(void) -+{ -+ printf("%s", board_intro); -+ wiki_helper("Known good (worked out of the box)", "OK", 3, boards_ok); -+ wiki_helper2("Known good (with write-enable code in flashrom)", 3); -+ wiki_helper("Not supported (yet)", "No", 3, boards_bad); -+ -+ printf("%s", laptop_intro); -+ wiki_helper("Known good (worked out of the box)", "OK", 1, laptops_ok); -+ wiki_helper("Not supported (yet)", "No", 1, laptops_bad); -+} -+ -+void print_supported_chips_wiki(void) -+{ -+ int i = 0, c = 1, chipcount = 0; -+ struct flashchip *f, *old = NULL; -+ uint32_t t; -+ -+ for (f = flashchips; f->name != NULL; f++) -+ chipcount++; -+ -+ printf("\n== Supported chips ==\n\nTotal amount of supported " -+ "chips: '''%d'''\n\n{| border=\"0\" valign=\"top\"\n" -+ "| valign=\"top\"|\n\n%s", chipcount, chip_th); -+ -+ for (f = flashchips; f->name != NULL; f++, i++) { -+ /* Don't print "unknown XXXX SPI chip" entries. */ -+ if (!strncmp(f->name, "unknown", 7)) -+ continue; -+ -+ /* Alternate colors if the vendor changes. */ -+ if (old != NULL && strcmp(old->vendor, f->vendor)) -+ c = !c; -+ -+ t = f->tested; -+ printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || %d " -+ "|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}\n", -+ (c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name, -+ f->total_size, flashbuses_to_text(f->bustype), -+ (t & TEST_OK_PROBE) ? "OK" : -+ (t & TEST_BAD_PROBE) ? "No" : ((c) ? "?2" : "?"), -+ (t & TEST_OK_READ) ? "OK" : -+ (t & TEST_BAD_READ) ? "No" : ((c) ? "?2" : "?"), -+ (t & TEST_OK_ERASE) ? "OK" : -+ (t & TEST_BAD_ERASE) ? "No" : ((c) ? "?2" : "?"), -+ (t & TEST_OK_WRITE) ? "OK" : -+ (t & TEST_BAD_WRITE) ? "No" : ((c) ? "?2" : "?")); -+ -+ /* Split table into three columns. */ -+ if (i >= (chipcount / 3 + 1)) { -+ printf("\n|}\n\n| valign=\"top\"|\n\n%s", chip_th); -+ i = 0; -+ } -+ -+ old = f; -+ } -+ -+ printf("\n|}\n\n|}\n"); -+} -+ -+void print_supported_pcidevs_wiki(struct pcidev_status *devs) -+{ -+ int i = 0; -+ static int c = 0; -+ -+ /* Alternate colors if the vendor changes. */ -+ c = !c; -+ -+ for (i = 0; devs[i].vendor_name != NULL; i++) { -+ printf("|- bgcolor=\"#%s\" valign=\"top\"\n| %s || %s || " -+ "%04x:%04x || {{%s}}\n", (c) ? "eeeeee" : "dddddd", -+ devs[i].vendor_name, devs[i].device_name, -+ devs[i].vendor_id, devs[i].device_id, -+ (devs[i].status == NT) ? (c) ? "?2" : "?" : "OK"); -+ } -+} -+ -+void print_supported_wiki(void) -+{ -+ time_t t = time(NULL); -+ -+ printf(wiki_header, ctime(&t), flashrom_version); -+ print_supported_chips_wiki(); -+ print_supported_chipsets_wiki(); -+ print_supported_boards_wiki(); -+ printf("%s", programmer_section); -+#if NIC3COM_SUPPORT == 1 -+ print_supported_pcidevs_wiki(nics_3com); -+#endif -+#if GFXNVIDIA_SUPPORT == 1 -+ print_supported_pcidevs_wiki(gfx_nvidia); -+#endif -+#if DRKAISER_SUPPORT == 1 -+ print_supported_pcidevs_wiki(drkaiser_pcidev); -+#endif -+#if SATASII_SUPPORT == 1 -+ print_supported_pcidevs_wiki(satas_sii); -+#endif -+#if ATAHPT_SUPPORT == 1 -+ print_supported_pcidevs_wiki(ata_hpt); -+#endif -+ printf("\n|}\n"); -+} -+ -diff --git a/programmer.c b/programmer.c -new file mode 100644 -index 0000000..ca641e1 ---- /dev/null -+++ b/programmer.c -@@ -0,0 +1,99 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include "flash.h" -+ -+/* No-op shutdown() for programmers which don't need special handling */ -+int noop_shutdown(void) -+{ -+ return 0; -+} -+ -+/* Fallback map() for programmers which don't need special handling */ -+void *fallback_map(const char *descr, unsigned long phys_addr, size_t len) -+{ -+ /* FIXME: Should return phys_addr. */ -+ return 0; -+} -+ -+/* No-op/fallback unmap() for programmers which don't need special handling */ -+void fallback_unmap(void *virt_addr, size_t len) -+{ -+} -+ -+/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ -+uint8_t noop_chip_readb(const chipaddr addr) -+{ -+ return 0xff; -+} -+ -+/* No-op chip_writeb() for drivers not supporting addr/data pair accesses */ -+void noop_chip_writeb(uint8_t val, chipaddr addr) -+{ -+} -+ -+/* Little-endian fallback for drivers not supporting 16 bit accesses */ -+void fallback_chip_writew(uint16_t val, chipaddr addr) -+{ -+ chip_writeb(val & 0xff, addr); -+ chip_writeb((val >> 8) & 0xff, addr + 1); -+} -+ -+/* Little-endian fallback for drivers not supporting 16 bit accesses */ -+uint16_t fallback_chip_readw(const chipaddr addr) -+{ -+ uint16_t val; -+ val = chip_readb(addr); -+ val |= chip_readb(addr + 1) << 8; -+ return val; -+} -+ -+/* Little-endian fallback for drivers not supporting 32 bit accesses */ -+void fallback_chip_writel(uint32_t val, chipaddr addr) -+{ -+ chip_writew(val & 0xffff, addr); -+ chip_writew((val >> 16) & 0xffff, addr + 2); -+} -+ -+/* Little-endian fallback for drivers not supporting 32 bit accesses */ -+uint32_t fallback_chip_readl(const chipaddr addr) -+{ -+ uint32_t val; -+ val = chip_readw(addr); -+ val |= chip_readw(addr + 2) << 16; -+ return val; -+} -+ -+void fallback_chip_writen(uint8_t *buf, chipaddr addr, size_t len) -+{ -+ size_t i; -+ for (i = 0; i < len; i++) -+ chip_writeb(buf[i], addr + i); -+ return; -+} -+ -+void fallback_chip_readn(uint8_t *buf, chipaddr addr, size_t len) -+{ -+ size_t i; -+ for (i = 0; i < len; i++) -+ buf[i] = chip_readb(addr + i); -+ return; -+} -diff --git a/satasii.c b/satasii.c -index 2564436..90d38bd 100644 ---- a/satasii.c -+++ b/satasii.c -@@ -30,12 +30,12 @@ uint8_t *sii_bar; - uint16_t id; - - struct pcidev_status satas_sii[] = { -- {0x1095, 0x0680, PCI_OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"}, -- {0x1095, 0x3112, PCI_OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"}, -- {0x1095, 0x3114, PCI_OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"}, -- {0x1095, 0x3124, PCI_NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"}, -- {0x1095, 0x3132, PCI_OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"}, -- {0x1095, 0x3512, PCI_NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"}, -+ {0x1095, 0x0680, OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"}, -+ {0x1095, 0x3112, OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"}, -+ {0x1095, 0x3114, OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"}, -+ {0x1095, 0x3124, NT, "Silicon Image", "SiI 3124 PCI-X SATA Ctrl"}, -+ {0x1095, 0x3132, OK, "Silicon Image", "SiI 3132 SATA Raid II Ctrl"}, -+ {0x1095, 0x3512, NT, "Silicon Image", "SiI 3512 [SATALink/SATARaid] SATA Ctrl"}, - - {}, - }; -@@ -47,7 +47,8 @@ int satasii_init(void) - - get_io_perms(); - -- pcidev_init(PCI_VENDOR_ID_SII, satas_sii, programmer_param); -+ pcidev_init(PCI_VENDOR_ID_SII, PCI_BASE_ADDRESS_0, satas_sii, -+ programmer_param); - id = pcidev_dev->device_id; - - if ((id == 0x3132) || (id == 0x3124)) { -@@ -62,7 +63,7 @@ int satasii_init(void) - - /* Check if ROM cycle are OK. */ - if ((id != 0x0680) && (!(mmio_readl(sii_bar) & (1 << 26)))) -- printf("Warning: Flash seems unconnected.\n"); -+ msg_pinfo("Warning: Flash seems unconnected.\n"); - - buses_supported = CHIP_BUSTYPE_PARALLEL; - -diff --git a/sb600spi.c b/sb600spi.c -index c853f42..0cf797c 100644 ---- a/sb600spi.c -+++ b/sb600spi.c -@@ -22,6 +22,7 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - #include "spi.h" - - /* This struct is unused, but helps visualize the SB600 SPI BAR layout. -@@ -48,30 +49,35 @@ int sb600_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) - /* FIXME: SB600 can write 5 bytes per transaction. */ - int sb600_spi_write_1(struct flashchip *flash, uint8_t *buf) - { -- int rc = 0, i; -+ int i; - int total_size = flash->total_size * 1024; -- int result; -+ int result = 0; - - spi_disable_blockprotect(); - /* Erase first */ -- printf("Erasing flash before programming... "); -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_pinfo("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ msg_perr("ERASE FAILED!\n"); - return -1; - } -- printf("done.\n"); -+ msg_pinfo("done.\n"); - -- printf("Programming flash"); -+ msg_pinfo("Programming flash"); - for (i = 0; i < total_size; i++, buf++) { -- result = spi_byte_program(i, *buf); -+ result = spi_nbyte_program(i, buf, 1); -+ if (result) { -+ msg_perr("Write error!\n"); -+ return result; -+ } -+ - /* wait program complete. */ - if (i % 0x8000 == 0) -- printf("."); -+ msg_pspew("."); - while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) - ; - } -- printf(" done.\n"); -- return rc; -+ msg_pinfo(" done.\n"); -+ return result; - } - - static void reset_internal_fifo_pointer(void) -@@ -79,7 +85,7 @@ static void reset_internal_fifo_pointer(void) - mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2); - - while (mmio_readb(sb600_spibar + 0xD) & 0x7) -- printf("reset\n"); -+ msg_pspew("reset\n"); - } - - static void execute_command(void) -@@ -100,17 +106,17 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, - - writecnt--; - -- printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n", -- __func__, cmd, writecnt, readcnt); -+ msg_pspew("%s, cmd=%x, writecnt=%x, readcnt=%x\n", -+ __func__, cmd, writecnt, readcnt); - - if (readcnt > 8) { -- printf("%s, SB600 SPI controller can not receive %d bytes, " -+ msg_pinfo("%s, SB600 SPI controller can not receive %d bytes, " - "it is limited to 8 bytes\n", __func__, readcnt); - return SPI_INVALID_LENGTH; - } - - if (writecnt > 8) { -- printf("%s, SB600 SPI controller can not send %d bytes, " -+ msg_pinfo("%s, SB600 SPI controller can not send %d bytes, " - "it is limited to 8 bytes\n", __func__, writecnt); - return SPI_INVALID_LENGTH; - } -@@ -130,10 +136,10 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, - - /* Send the write byte to FIFO. */ - for (count = 0; count < writecnt; count++, writearr++) { -- printf_debug(" [%x]", *writearr); -+ msg_pspew(" [%x]", *writearr); - mmio_writeb(*writearr, sb600_spibar + 0xC); - } -- printf_debug("\n"); -+ msg_pspew("\n"); - - /* - * We should send the data by sequence, which means we need to reset -@@ -159,16 +165,16 @@ int sb600_spi_send_command(unsigned int writecnt, unsigned int readcnt, - /* Skip the bytes we sent. */ - for (count = 0; count < writecnt; count++) { - cmd = mmio_readb(sb600_spibar + 0xC); -- printf_debug("[ %2x]", cmd); -+ msg_pspew("[ %2x]", cmd); - } - -- printf_debug("The FIFO pointer after skipping is %d.\n", -- mmio_readb(sb600_spibar + 0xd) & 0x07); -+ msg_pspew("The FIFO pointer after skipping is %d.\n", -+ mmio_readb(sb600_spibar + 0xd) & 0x07); - for (count = 0; count < readcnt; count++, readarr++) { - *readarr = mmio_readb(sb600_spibar + 0xC); -- printf_debug("[%02x]", *readarr); -+ msg_pspew("[%02x]", *readarr); - } -- printf_debug("\n"); -+ msg_pspew("\n"); - - return 0; - } -diff --git a/serial.c b/serial.c -new file mode 100644 -index 0000000..37f2549 ---- /dev/null -+++ b/serial.c -@@ -0,0 +1,232 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2009 Urja Rannikko -+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+#include "flash.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef _WIN32 -+#include -+#else -+#include -+#endif -+ -+fdtype sp_fd; -+ -+void __attribute__((noreturn)) sp_die(char *msg) -+{ -+ perror(msg); -+ exit(1); -+} -+ -+#ifndef _WIN32 -+struct baudentry { -+ int flag; -+ unsigned int baud; -+}; -+ -+/* I'd like if the C preprocessor could have directives in macros */ -+#define BAUDENTRY(baud) { B##baud, baud }, -+static const struct baudentry sp_baudtable[] = { -+ BAUDENTRY(9600) -+ BAUDENTRY(19200) -+ BAUDENTRY(38400) -+ BAUDENTRY(57600) -+ BAUDENTRY(115200) -+#ifdef B230400 -+ BAUDENTRY(230400) -+#endif -+#ifdef B460800 -+ BAUDENTRY(460800) -+#endif -+#ifdef B500000 -+ BAUDENTRY(500000) -+#endif -+#ifdef B576000 -+ BAUDENTRY(576000) -+#endif -+#ifdef B921600 -+ BAUDENTRY(921600) -+#endif -+#ifdef B1000000 -+ BAUDENTRY(1000000) -+#endif -+#ifdef B1152000 -+ BAUDENTRY(1152000) -+#endif -+#ifdef B1500000 -+ BAUDENTRY(1500000) -+#endif -+#ifdef B2000000 -+ BAUDENTRY(2000000) -+#endif -+#ifdef B2500000 -+ BAUDENTRY(2500000) -+#endif -+#ifdef B3000000 -+ BAUDENTRY(3000000) -+#endif -+#ifdef B3500000 -+ BAUDENTRY(3500000) -+#endif -+#ifdef B4000000 -+ BAUDENTRY(4000000) -+#endif -+ {0, 0} /* Terminator */ -+}; -+#endif -+ -+fdtype sp_openserport(char *dev, unsigned int baud) -+{ -+#ifdef _WIN32 -+ HANDLE fd; -+ char *dev2 = dev; -+ if ((strlen(dev) > 3) && (tolower(dev[0]) == 'c') -+ && (tolower(dev[1]) == 'o') && (tolower(dev[2]) == 'm')) { -+ dev2 = malloc(strlen(dev) + 5); -+ strcpy(dev2, "\\\\.\\"); -+ strcpy(dev2 + 4, dev); -+ } -+ fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL, -+ OPEN_EXISTING, 0, NULL); -+ if (dev2 != dev) -+ free(dev2); -+ if (fd == INVALID_HANDLE_VALUE) { -+ sp_die("Error: cannot open serial port"); -+ } -+ DCB dcb; -+ if (!GetCommState(fd, &dcb)) { -+ sp_die("Error: Could not fetch serial port configuration"); -+ } -+ switch (baud) { -+ case 9600: dcb.BaudRate = CBR_9600; break; -+ case 19200: dcb.BaudRate = CBR_19200; break; -+ case 38400: dcb.BaudRate = CBR_38400; break; -+ case 57600: dcb.BaudRate = CBR_57600; break; -+ case 115200: dcb.BaudRate = CBR_115200; break; -+ default: sp_die("Error: Could not set baud rate"); -+ } -+ dcb.ByteSize = 8; -+ dcb.Parity = NOPARITY; -+ dcb.StopBits = ONESTOPBIT; -+ if (!SetCommState(fd, &dcb)) { -+ sp_die("Error: Could not change serial port configuration"); -+ } -+ return fd; -+#else -+ struct termios options; -+ int fd, i; -+ fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); -+ if (fd < 0) -+ sp_die("Error: cannot open serial port"); -+ fcntl(fd, F_SETFL, 0); -+ tcgetattr(fd, &options); -+ for (i = 0;; i++) { -+ if (sp_baudtable[i].baud == 0) { -+ close(fd); -+ msg_perr("Error: cannot configure for baudrate %d\n", -+ baud); -+ exit(1); -+ } -+ if (sp_baudtable[i].baud == baud) { -+ cfsetispeed(&options, sp_baudtable[i].flag); -+ cfsetospeed(&options, sp_baudtable[i].flag); -+ break; -+ } -+ } -+ options.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); -+ options.c_cflag |= (CS8 | CLOCAL | CREAD); -+ options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); -+ options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR); -+ options.c_oflag &= ~OPOST; -+ tcsetattr(fd, TCSANOW, &options); -+ return fd; -+#endif -+} -+ -+void sp_flush_incoming(void) -+{ -+#ifdef _WIN32 -+ PurgeComm(sp_fd, PURGE_RXCLEAR); -+#else -+ tcflush(sp_fd, TCIFLUSH); -+#endif -+ return; -+} -+ -+int serialport_shutdown(void) -+{ -+#ifdef _WIN32 -+ CloseHandle(sp_fd); -+#else -+ close(sp_fd); -+#endif -+ return 0; -+} -+ -+int serialport_write(unsigned char *buf, unsigned int writecnt) -+{ -+ long tmp = 0; -+ -+ while (writecnt > 0) { -+#ifdef _WIN32 -+ WriteFile(sp_fd, buf, writecnt, &tmp, NULL); -+#else -+ tmp = write(sp_fd, buf, writecnt); -+#endif -+ if (tmp == -1) -+ return 1; -+ if (!tmp) -+ msg_pdbg("Empty write\n"); -+ writecnt -= tmp; -+ buf += tmp; -+ } -+ -+ return 0; -+} -+ -+int serialport_read(unsigned char *buf, unsigned int readcnt) -+{ -+ long tmp = 0; -+ -+ while (readcnt > 0) { -+#ifdef _WIN32 -+ ReadFile(sp_fd, buf, readcnt, &tmp, NULL); -+#else -+ tmp = read(sp_fd, buf, readcnt); -+#endif -+ if (tmp == -1) -+ return 1; -+ if (!tmp) -+ msg_pdbg("Empty read\n"); -+ readcnt -= tmp; -+ buf += tmp; -+ } -+ -+ return 0; -+} -diff --git a/serprog-protocol.txt b/serprog-protocol.txt -index 0d389e6..c5464a4 100644 ---- a/serprog-protocol.txt -+++ b/serprog-protocol.txt -@@ -46,14 +46,14 @@ Additional information of the above commands: - cmd 7 support: byte 0 bit 7 - cmd 8 support: byte 1 bit 0, and so on. - 0x04 (Q_SERBUF): -- If the programmer has guaranteedly working flow control, -+ If the programmer has a guaranteed working flow control, - it should return a big bogus value - eg 0xFFFF. - 0x05 (Q_BUSTYPE): - The bit's are defined as follows: - bit 0: PARALLEL, bit 1: LPC, bit 2: FWH, bit 3: SPI (if ever supported). - 0x06 (Q_CHIPSIZE): - Only applicable to parallel programmers. -- An LPC/FHW/SPI-programmer can report this as not supported in the command bitmap. -+ An LPC/FWH/SPI-programmer can report this as not supported in the command bitmap. - 0x08 (Q_WRNMAXLEN): - If a programmer reports a bigger maximum write-n length than the serial buffer size, - it is assumed that the programmer can process the data fast enough to take in the -diff --git a/serprog.c b/serprog.c -index 23e1a0c..efcf9d8 100644 ---- a/serprog.c -+++ b/serprog.c -@@ -61,14 +61,12 @@ - #define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */ - #define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */ - --static int sp_fd; -- - static uint16_t sp_device_serbuf_size = 16; - static uint16_t sp_device_opbuf_size = 300; - /* Bitmap of supported commands */ - static uint8_t sp_cmdmap[32]; - --/* sp_prev_was_write used to detect writes with continouous addresses -+/* sp_prev_was_write used to detect writes with contiguous addresses - and combine them to write-n's */ - static int sp_prev_was_write = 0; - /* sp_write_n_addr used as the starting addr of the currently -@@ -95,19 +93,13 @@ static int sp_opbuf_usage = 0; - whether the command is supported before doing it */ - static int sp_check_avail_automatic = 0; - --static void sp_die(char *msg) --{ -- perror(msg); -- exit(1); --} -- - static int sp_opensocket(char *ip, unsigned int port) - { - int flag = 1; - struct hostent *hostPtr = NULL; -- struct sockaddr_in sp; -+ union { struct sockaddr_in si; struct sockaddr s; } sp = {}; - int sock; -- printf_debug(MSGHEADER "IP %s port %d\n", ip, port); -+ msg_pdbg(MSGHEADER "IP %s port %d\n", ip, port); - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) - sp_die("Error: serprog cannot open socket"); -@@ -117,11 +109,10 @@ static int sp_opensocket(char *ip, unsigned int port) - if (NULL == hostPtr) - sp_die("Error: cannot resolve"); - } -- memset(&sp, 0, sizeof(sp)); -- sp.sin_family = AF_INET; -- sp.sin_port = htons(port); -- (void)memcpy(&sp.sin_addr, hostPtr->h_addr, hostPtr->h_length); -- if (connect(sock, (struct sockaddr *)&sp, sizeof(sp)) < 0) { -+ sp.si.sin_family = AF_INET; -+ sp.si.sin_port = htons(port); -+ (void)memcpy(&sp.si.sin_addr, hostPtr->h_addr, hostPtr->h_length); -+ if (connect(sock, &sp.s, sizeof(sp.si)) < 0) { - close(sock); - sp_die("Error: serprog cannot connect"); - } -@@ -131,112 +122,6 @@ static int sp_opensocket(char *ip, unsigned int port) - return sock; - } - --struct baudentry { -- int flag; -- unsigned int baud; --}; -- --/* I'd like if the C preprocessor could have directives in macros */ --#define BAUDENTRY(baud) { B##baud, baud }, --static const struct baudentry sp_baudtable[] = { -- BAUDENTRY(9600) -- BAUDENTRY(19200) -- BAUDENTRY(38400) -- BAUDENTRY(57600) -- BAUDENTRY(115200) --#ifdef B230400 -- BAUDENTRY(230400) --#endif --#ifdef B460800 -- BAUDENTRY(460800) --#endif --#ifdef B500000 -- BAUDENTRY(500000) --#endif --#ifdef B576000 -- BAUDENTRY(576000) --#endif --#ifdef B921600 -- BAUDENTRY(921600) --#endif --#ifdef B1000000 -- BAUDENTRY(1000000) --#endif --#ifdef B1152000 -- BAUDENTRY(1152000) --#endif --#ifdef B1500000 -- BAUDENTRY(1500000) --#endif --#ifdef B2000000 -- BAUDENTRY(2000000) --#endif --#ifdef B2500000 -- BAUDENTRY(2500000) --#endif --#ifdef B3000000 -- BAUDENTRY(3000000) --#endif --#ifdef B3500000 -- BAUDENTRY(3500000) --#endif --#ifdef B4000000 -- BAUDENTRY(4000000) --#endif -- {0, 0} /* Terminator */ --}; -- --static int sp_openserport(char *dev, unsigned int baud) --{ -- struct termios options; -- int fd, i; -- fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); -- if (fd < 0) -- sp_die("Error: cannot open serial port"); -- fcntl(fd, F_SETFL, 0); -- tcgetattr(fd, &options); -- for (i = 0;; i++) { -- if (sp_baudtable[i].baud == 0) { -- close(fd); -- fprintf(stderr, -- "Error: cannot configure for baudrate %d\n", -- baud); -- exit(1); -- } -- if (sp_baudtable[i].baud == baud) { -- cfsetispeed(&options, sp_baudtable[i].flag); -- cfsetospeed(&options, sp_baudtable[i].flag); -- break; -- } -- } -- options.c_cflag &= ~PARENB; -- options.c_cflag &= ~CSTOPB; -- options.c_cflag &= ~CSIZE; -- options.c_cflag |= CS8; -- options.c_cflag &= ~CRTSCTS; -- options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); -- options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR); -- options.c_oflag &= ~OPOST; -- options.c_cflag |= (CLOCAL | CREAD); -- tcsetattr(fd, TCSANOW, &options); -- return fd; --} -- --static void sp_flush_incoming(void) --{ -- int i; -- for (i=0;i<100;i++) { /* In case the device doesnt do EAGAIN, just read 0 */ -- unsigned char flush[16]; -- ssize_t rv; -- rv = read(sp_fd, flush, sizeof(flush)); -- if ((rv == -1) && (errno == EAGAIN)) -- break; -- if (rv == -1) -- sp_die("flush read"); -- } -- return; --} -- - static int sp_sync_read_timeout(int loops) - { - int i; -@@ -253,7 +138,7 @@ static int sp_sync_read_timeout(int loops) - return -1; - } - --/* Synchronize: a bit tricky algorhytm that tries to (and in my tests has * -+/* Synchronize: a bit tricky algorithm that tries to (and in my tests has * - * always succeeded in) bring the serial protocol to known waiting-for- * - * command state - uses nonblocking read - rest of the driver uses * - * blocking read - TODO: add an alarm() timer for the rest of the app on * -@@ -285,7 +170,7 @@ static void sp_synchronize(void) - unsigned char c = S_CMD_SYNCNOP; - if (write(sp_fd, &c, 1) != 1) - sp_die("sync write"); -- printf_debug("."); -+ msg_pdbg("."); - fflush(stdout); - for (n = 0; n < 10; n++) { - c = sp_sync_read_timeout(5); /* wait upto 50ms */ -@@ -306,12 +191,11 @@ static void sp_synchronize(void) - /* Ok, synchronized; back to blocking reads and return. */ - flags &= ~O_NONBLOCK; - fcntl(sp_fd, F_SETFL, flags); -- printf_debug("\n"); -+ msg_pdbg("\n"); - return; - } - } -- fprintf(stderr, -- "Error: cannot synchronize protocol\n" -+ msg_perr("Error: cannot synchronize protocol\n" - "- check communications and reset device?\n"); - exit(1); - } -@@ -327,7 +211,7 @@ static int sp_check_commandavail(uint8_t command) - static int sp_automatic_cmdcheck(uint8_t cmd) - { - if ((sp_check_avail_automatic) && (sp_check_commandavail(cmd) == 0)) { -- printf_debug ("Warning: Automatic command availability check" -+ msg_pdbg("Warning: Automatic command availability check" - " failed for cmd %d - wont execute cmd\n",cmd); - return 1; - } -@@ -354,8 +238,7 @@ static int sp_docommand(uint8_t command, uint32_t parmlen, - sp_die("Error: cannot read from device"); - if (c == S_NAK) return 1; - if (c != S_ACK) { -- fprintf(stderr, -- "Error: invalid response 0x%02X from device\n",c); -+ msg_perr("Error: invalid response 0x%02X from device\n",c); - exit(1); - } - if (retlen) { -@@ -378,18 +261,14 @@ static void sp_flush_stream(void) - do { - unsigned char c; - if (read(sp_fd, &c, 1) != 1) { -- sp_die -- ("Error: cannot read from device (flushing stream)"); -+ sp_die("Error: cannot read from device (flushing stream)"); - } - if (c == S_NAK) { -- fprintf(stderr, -- "Error: NAK to a stream buffer operation\n"); -+ msg_perr("Error: NAK to a stream buffer operation\n"); - exit(1); - } - if (c != S_ACK) { -- fprintf(stderr, -- "Error: Invalid reply 0x%02X from device\n", -- c); -+ msg_perr("Error: Invalid reply 0x%02X from device\n", c); - exit(1); - } - } while (--sp_streamed_transmit_ops); -@@ -425,12 +304,11 @@ int serprog_init(void) - unsigned char c; - char *num; - char *dev; -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - /* the parameter is either of format "/dev/device:baud" or "ip:port" */ - if ((!programmer_param) || (!strlen(programmer_param))) { - nodevice: -- fprintf(stderr, -- "Error: No device/host given for the serial programmer driver.\n" -+ msg_perr("Error: No device/host given for the serial programmer driver.\n" - "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); - exit(1); - } -@@ -438,8 +316,7 @@ int serprog_init(void) - len = num - programmer_param; - if (!len) goto nodevice; - if (!num) { -- fprintf(stderr, -- "Error: No port or baudrate specified to serial programmer driver.\n" -+ msg_perr("Error: No port or baudrate specified to serial programmer driver.\n" - "Use flashrom -p serprog=/dev/device:baud or flashrom -p serprog=ip:port\n"); - exit(1); - } -@@ -459,28 +336,28 @@ int serprog_init(void) - free(dev); dev = NULL; - free(num); num = NULL; - -- printf_debug(MSGHEADER "connected - attempting to synchronize\n"); -+ msg_pdbg(MSGHEADER "connected - attempting to synchronize\n"); - - sp_check_avail_automatic = 0; - - sp_synchronize(); - -- printf_debug(MSGHEADER "Synchronized\n"); -+ msg_pdbg(MSGHEADER "Synchronized\n"); - - if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) { -- fprintf(stderr, "Error: NAK to Query Interface version\n"); -+ msg_perr("Error: NAK to Query Interface version\n"); - exit(1); - } - - if (iface != 1) { -- fprintf(stderr, "Error: Unknown interface version %d\n", iface); -+ msg_perr("Error: Unknown interface version %d\n", iface); - exit(1); - } - -- printf_debug(MSGHEADER "Interface version ok.\n"); -+ msg_pdbg(MSGHEADER "Interface version ok.\n"); - - if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) { -- fprintf(stderr, "Error: query command map not supported\n"); -+ msg_perr("Error: query command map not supported\n"); - exit(1); - } - -@@ -488,81 +365,77 @@ int serprog_init(void) - - /* Check for the minimum operational set of commands */ - if (sp_check_commandavail(S_CMD_R_BYTE) == 0) { -- fprintf(stderr, "Error: Single byte read not supported\n"); -+ msg_perr("Error: Single byte read not supported\n"); - exit(1); - } - /* This could be translated to single byte reads (if missing), * - * but now we dont support that. */ - if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) { -- fprintf(stderr, "Error: Read n bytes not supported\n"); -+ msg_perr("Error: Read n bytes not supported\n"); - exit(1); - } - /* In the future one could switch to read-only mode if these * - * are not available. */ - if (sp_check_commandavail(S_CMD_O_INIT) == 0) { -- fprintf(stderr, -- "Error: Initialize operation buffer not supported\n"); -+ msg_perr("Error: Initialize operation buffer not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) { -- fprintf(stderr, -- "Error: Write to opbuf: write byte not supported\n"); -+ msg_perr("Error: Write to opbuf: write byte not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_DELAY) == 0) { -- fprintf(stderr, "Error: Write to opbuf: delay not supported\n"); -+ msg_perr("Error: Write to opbuf: delay not supported\n"); - exit(1); - } - if (sp_check_commandavail(S_CMD_O_EXEC) == 0) { -- fprintf(stderr, -+ msg_perr( - "Error: Execute operation buffer not supported\n"); - exit(1); - } - - if (sp_docommand(S_CMD_Q_PGMNAME, 0, NULL, 16, pgmname)) { -- fprintf(stderr, "Warning: NAK to query programmer name\n"); -+ msg_perr("Warning: NAK to query programmer name\n"); - strcpy((char *)pgmname, "(unknown)"); - } - pgmname[16] = 0; -- printf(MSGHEADER "Programmer name \"%s\"\n", pgmname); -+ msg_pinfo(MSGHEADER "Programmer name \"%s\"\n", pgmname); - - if (sp_docommand(S_CMD_Q_SERBUF, 0, NULL, 2, &sp_device_serbuf_size)) { -- fprintf(stderr, "Warning: NAK to query serial buffer size\n"); -+ msg_perr("Warning: NAK to query serial buffer size\n"); - } -- printf_debug(MSGHEADER "serial buffer size %d\n", -+ msg_pdbg(MSGHEADER "serial buffer size %d\n", - sp_device_serbuf_size); - - if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2, &sp_device_opbuf_size)) { -- fprintf(stderr, -- "Warning: NAK to query operation buffer size\n"); -+ msg_perr("Warning: NAK to query operation buffer size\n"); - } -- printf_debug(MSGHEADER "operation buffer size %d\n", -+ msg_pdbg(MSGHEADER "operation buffer size %d\n", - sp_device_opbuf_size); - - if (sp_docommand(S_CMD_Q_BUSTYPE, 0, NULL, 1, &c)) { -- fprintf(stderr, "Warning: NAK to query supported buses\n"); -+ msg_perr("Warning: NAK to query supported buses\n"); - c = CHIP_BUSTYPE_NONSPI; /* A reasonable default for now. */ - } - buses_supported = c; - - if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) { -- fprintf(stderr, "Error: NAK to initialize operation buffer\n"); -+ msg_perr("Error: NAK to initialize operation buffer\n"); - exit(1); - } - - if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) { -- printf_debug(MSGHEADER "Write-n not supported"); -+ msg_pdbg(MSGHEADER "Write-n not supported"); - sp_max_write_n = 0; - } else { - sp_max_write_n = ((unsigned int)(rbuf[0]) << 0); - sp_max_write_n |= ((unsigned int)(rbuf[1]) << 8); - sp_max_write_n |= ((unsigned int)(rbuf[2]) << 16); -- printf_debug(MSGHEADER "Maximum write-n length %d\n", -+ msg_pdbg(MSGHEADER "Maximum write-n length %d\n", - sp_max_write_n); - sp_write_n_buf = malloc(sp_max_write_n); - if (!sp_write_n_buf) { -- fprintf(stderr, -- "Error: cannot allocate memory for Write-n buffer\n"); -+ msg_perr("Error: cannot allocate memory for Write-n buffer\n"); - exit(1); - } - sp_write_n_bytes = 0; -@@ -573,10 +446,10 @@ int serprog_init(void) - sp_max_read_n = ((unsigned int)(rbuf[0]) << 0); - sp_max_read_n |= ((unsigned int)(rbuf[1]) << 8); - sp_max_read_n |= ((unsigned int)(rbuf[2]) << 16); -- printf_debug(MSGHEADER "Maximum read-n length %d\n", -+ msg_pdbg(MSGHEADER "Maximum read-n length %d\n", - sp_max_read_n ? sp_max_read_n : (1<<24)); - } else { -- printf_debug(MSGHEADER "Maximum read-n length not reported\n"); -+ msg_pdbg(MSGHEADER "Maximum read-n length not reported\n"); - sp_max_read_n = 0; - } - -@@ -592,7 +465,7 @@ int serprog_init(void) - static void sp_pass_writen(void) - { - unsigned char header[7]; -- printf_debug(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", -+ msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", - sp_write_n_bytes, sp_write_n_addr); - if (sp_streamed_transmit_bytes >= - (7 + sp_write_n_bytes + sp_device_serbuf_size)) -@@ -632,7 +505,7 @@ static void sp_execute_opbuf_noflush(void) - if ((sp_max_write_n) && (sp_write_n_bytes)) - sp_pass_writen(); - sp_stream_buffer_op(S_CMD_O_EXEC, 0, 0); -- printf_debug(MSGHEADER "Executed operation buffer of %d bytes\n", -+ msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", - sp_opbuf_usage); - sp_opbuf_usage = 0; - sp_prev_was_write = 0; -@@ -647,7 +520,7 @@ static void sp_execute_opbuf(void) - - int serprog_shutdown(void) - { -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) - sp_execute_opbuf(); - close(sp_fd); -@@ -661,15 +534,14 @@ static void sp_check_opbuf_usage(int bytes_to_be_added) - if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) { - sp_execute_opbuf(); - /* If this happens in the mid of an page load the page load * -- * will propably fail. */ -- printf_debug(MSGHEADER -- "Warning: executed operation buffer due to size reasons\n"); -+ * will probably fail. */ -+ msg_pdbg(MSGHEADER "Warning: executed operation buffer due to size reasons\n"); - } - } - - void serprog_chip_writeb(uint8_t val, chipaddr addr) - { -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - if (sp_max_write_n) { - if ((sp_prev_was_write) - && (addr == (sp_write_n_addr + sp_write_n_bytes))) { -@@ -713,16 +585,16 @@ uint8_t serprog_chip_readb(const chipaddr addr) - sp_flush_stream(); - if (read(sp_fd, &c, 1) != 1) - sp_die("readb byteread"); -- printf_debug("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c); -+ msg_pspew("%s addr=0x%lx returning 0x%02X\n", __func__, addr, c); - return c; - } - --/* Local version that really does the job, doesnt care of max_read_n. */ -+/* Local version that really does the job, doesn't care of max_read_n. */ - static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) - { - int rd_bytes = 0; - unsigned char sbuf[6]; -- printf_debug("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len); -+ msg_pspew("%s: addr=0x%lx len=%lu\n", __func__, addr, (unsigned long)len); - /* Stream the read-n -- as above. */ - if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) - sp_execute_opbuf_noflush(); -@@ -759,7 +631,7 @@ void serprog_chip_readn(uint8_t * buf, const chipaddr addr, size_t len) - void serprog_delay(int delay) - { - unsigned char buf[4]; -- printf_debug("%s\n", __func__); -+ msg_pspew("%s\n", __func__); - if ((sp_max_write_n) && (sp_write_n_bytes)) - sp_pass_writen(); - sp_check_opbuf_usage(5); -diff --git a/sharplhf00l04.c b/sharplhf00l04.c -index 53b9931..70b8135 100644 ---- a/sharplhf00l04.c -+++ b/sharplhf00l04.c -@@ -20,147 +20,45 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - --// I need that Berkeley bit-map printer --void print_lhf00l04_status(uint8_t status) --{ -- printf("%s", status & 0x80 ? "Ready:" : "Busy:"); -- printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); -- printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); -- printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); -- printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); -- printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); -- printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); --} -- --int probe_lhf00l04(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- --#if 0 -- /* Enter ID mode */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x90, bios + 0x5555); --#endif -- -- chip_writeb(0xff, bios); -- programmer_delay(10); -- chip_writeb(0x90, bios); -- programmer_delay(10); -- -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- /* Leave ID mode */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); -- -- programmer_delay(10); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- -- if (id1 != flash->manufacture_id || id2 != flash->model_id) -- return 0; -- -- map_flash_registers(flash); -- -- return 1; --} -- --uint8_t wait_lhf00l04(chipaddr bios) --{ -- uint8_t status; -- uint8_t id1, id2; -- -- chip_writeb(0x70, bios); -- if ((chip_readb(bios) & 0x80) == 0) { // it's busy -- while ((chip_readb(bios) & 0x80) == 0) ; -- } -- -- status = chip_readb(bios); -- -- // put another command to get out of status register mode -- -- chip_writeb(0x90, bios); -- programmer_delay(10); -- -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- // this is needed to jam it out of "read id" mode -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); -- -- return status; --} -+/* FIXME: The datasheet is unclear whether we should use toggle_ready_jedec -+ * or wait_82802ab. -+ */ - --int erase_lhf00l04_block(struct flashchip *flash, int offset) -+int erase_lhf00l04_block(struct flashchip *flash, unsigned int blockaddr, unsigned int blocklen) - { -- chipaddr bios = flash->virtual_memory + offset; -- chipaddr wrprotect = flash->virtual_registers + offset + 2; -+ chipaddr bios = flash->virtual_memory + blockaddr; -+ chipaddr wrprotect = flash->virtual_registers + blockaddr + 2; - uint8_t status; - - // clear status register - chip_writeb(0x50, bios); -- printf("Erase at 0x%lx\n", bios); -- status = wait_lhf00l04(flash->virtual_memory); -- print_lhf00l04_status(status); -+ msg_cdbg("Erase at 0x%lx\n", bios); -+ status = wait_82802ab(flash->virtual_memory); -+ print_status_82802ab(status); - // clear write protect -- printf("write protect is at 0x%lx\n", (wrprotect)); -- printf("write protect is 0x%x\n", chip_readb(wrprotect)); -+ msg_cspew("write protect is at 0x%lx\n", (wrprotect)); -+ msg_cspew("write protect is 0x%x\n", chip_readb(wrprotect)); - chip_writeb(0, wrprotect); -- printf("write protect is 0x%x\n", chip_readb(wrprotect)); -+ msg_cspew("write protect is 0x%x\n", chip_readb(wrprotect)); - - // now start it - chip_writeb(0x20, bios); - chip_writeb(0xd0, bios); - programmer_delay(10); - // now let's see what the register is -- status = wait_lhf00l04(flash->virtual_memory); -- print_lhf00l04_status(status); -- printf("DONE BLOCK 0x%x\n", offset); -+ status = wait_82802ab(flash->virtual_memory); -+ print_status_82802ab(status); -+ msg_cinfo("DONE BLOCK 0x%x\n", blockaddr); - -- if (check_erased_range(flash, offset, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ if (check_erased_range(flash, blockaddr, blocklen)) { -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --int erase_lhf00l04(struct flashchip *flash) --{ -- int i; -- unsigned int total_size = flash->total_size * 1024; -- -- printf("total_size is %d; flash->page_size is %d\n", -- total_size, flash->page_size); -- for (i = 0; i < total_size; i += flash->page_size) -- if (erase_lhf00l04_block(flash, i)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- printf("DONE ERASE\n"); -- -- return 0; --} -- --void write_page_lhf00l04(chipaddr bios, uint8_t *src, -- chipaddr dst, int page_size) --{ -- int i; -- -- for (i = 0; i < page_size; i++) { -- /* transfer data from source to destination */ -- chip_writeb(0x40, dst); -- chip_writeb(*src++, dst++); -- wait_lhf00l04(bios); -- } --} -- - int write_lhf00l04(struct flashchip *flash, uint8_t *buf) - { - int i; -@@ -168,19 +66,18 @@ int write_lhf00l04(struct flashchip *flash, uint8_t *buf) - int page_size = flash->page_size; - chipaddr bios = flash->virtual_memory; - -- if (erase_lhf00l04(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ if (erase_flash(flash)) { -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } -- printf("Programming page: "); -+ msg_cinfo("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { -- printf("%04d at address: 0x%08x", i, i * page_size); -- write_page_lhf00l04(bios, buf + i * page_size, -+ msg_cinfo("%04d at address: 0x%08x", i, i * page_size); -+ write_page_82802ab(bios, buf + i * page_size, - bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } -- printf("\n"); -- protect_jedec(bios); -+ msg_cinfo("\n"); - - return 0; - } -diff --git a/spi.c b/spi.c -index 7f678a1..8bbbe6e 100644 ---- a/spi.c -+++ b/spi.c -@@ -25,6 +25,7 @@ - #include - #include "flash.h" - #include "flashchips.h" -+#include "chipdrivers.h" - #include "spi.h" - - enum spi_controller spi_controller = SPI_CONTROLLER_NONE; -@@ -40,6 +41,7 @@ const struct spi_programmer spi_programmer[] = { - .write_256 = NULL, - }, - -+#if INTERNAL_SUPPORT == 1 - { /* SPI_CONTROLLER_ICH7 */ - .command = ich_spi_send_command, - .multicommand = ich_spi_send_multicommand, -@@ -81,6 +83,7 @@ const struct spi_programmer spi_programmer[] = { - .read = wbsio_spi_read, - .write_256 = wbsio_spi_write_1, - }, -+#endif - - #if FT2232_SPI_SUPPORT == 1 - { /* SPI_CONTROLLER_FT2232 */ -@@ -91,12 +94,32 @@ const struct spi_programmer spi_programmer[] = { - }, - #endif - -+#if DUMMY_SUPPORT == 1 - { /* SPI_CONTROLLER_DUMMY */ - .command = dummy_spi_send_command, - .multicommand = default_spi_send_multicommand, - .read = NULL, - .write_256 = NULL, - }, -+#endif -+ -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ { /* SPI_CONTROLLER_BUSPIRATE */ -+ .command = buspirate_spi_send_command, -+ .multicommand = default_spi_send_multicommand, -+ .read = buspirate_spi_read, -+ .write_256 = buspirate_spi_write_256, -+ }, -+#endif -+ -+#if DEDIPROG_SUPPORT == 1 -+ { /* SPI_CONTROLLER_DEDIPROG */ -+ .command = dediprog_spi_send_command, -+ .multicommand = default_spi_send_multicommand, -+ .read = dediprog_spi_read, -+ .write_256 = spi_chip_write_1, -+ }, -+#endif - - {}, /* This entry corresponds to SPI_CONTROLLER_INVALID. */ - }; -@@ -116,7 +139,7 @@ int spi_send_command(unsigned int writecnt, unsigned int readcnt, - writearr, readarr); - } - --int spi_send_multicommand(struct spi_command *spicommands) -+int spi_send_multicommand(struct spi_command *cmds) - { - if (!spi_programmer[spi_controller].multicommand) { - fprintf(stderr, "%s called, but SPI is unsupported on this " -@@ -124,7 +147,7 @@ int spi_send_multicommand(struct spi_command *spicommands) - return 1; - } - -- return spi_programmer[spi_controller].multicommand(spicommands); -+ return spi_programmer[spi_controller].multicommand(cmds); - } - - int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, -@@ -146,807 +169,16 @@ int default_spi_send_command(unsigned int writecnt, unsigned int readcnt, - return spi_send_multicommand(cmd); - } - --int default_spi_send_multicommand(struct spi_command *spicommands) -+int default_spi_send_multicommand(struct spi_command *cmds) - { - int result = 0; -- while ((spicommands->writecnt || spicommands->readcnt) && !result) { -- result = spi_send_command(spicommands->writecnt, spicommands->readcnt, -- spicommands->writearr, spicommands->readarr); -- spicommands++; -- } -- return result; --} -- --static int spi_rdid(unsigned char *readarr, int bytes) --{ -- const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID }; -- int ret; -- int i; -- -- ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr); -- if (ret) -- return ret; -- printf_debug("RDID returned"); -- for (i = 0; i < bytes; i++) -- printf_debug(" 0x%02x", readarr[i]); -- printf_debug(". "); -- return 0; --} -- --static int spi_rems(unsigned char *readarr) --{ -- unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 }; -- uint32_t readaddr; -- int ret; -- -- ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); -- if (ret == SPI_INVALID_ADDRESS) { -- /* Find the lowest even address allowed for reads. */ -- readaddr = (spi_get_valid_read_addr() + 1) & ~1; -- cmd[1] = (readaddr >> 16) & 0xff, -- cmd[2] = (readaddr >> 8) & 0xff, -- cmd[3] = (readaddr >> 0) & 0xff, -- ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); -- } -- if (ret) -- return ret; -- printf_debug("REMS returned %02x %02x. ", readarr[0], readarr[1]); -- return 0; --} -- --static int spi_res(unsigned char *readarr) --{ -- unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 }; -- uint32_t readaddr; -- int ret; -- -- ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); -- if (ret == SPI_INVALID_ADDRESS) { -- /* Find the lowest even address allowed for reads. */ -- readaddr = (spi_get_valid_read_addr() + 1) & ~1; -- cmd[1] = (readaddr >> 16) & 0xff, -- cmd[2] = (readaddr >> 8) & 0xff, -- cmd[3] = (readaddr >> 0) & 0xff, -- ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); -- } -- if (ret) -- return ret; -- printf_debug("RES returned %02x. ", readarr[0]); -- return 0; --} -- --int spi_write_enable(void) --{ -- const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN }; -- int result; -- -- /* Send WREN (Write Enable) */ -- result = spi_send_command(sizeof(cmd), 0, cmd, NULL); -- -- if (result) -- fprintf(stderr, "%s failed\n", __func__); -- -- return result; --} -- --int spi_write_disable(void) --{ -- const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI }; -- -- /* Send WRDI (Write Disable) */ -- return spi_send_command(sizeof(cmd), 0, cmd, NULL); --} -- --static int probe_spi_rdid_generic(struct flashchip *flash, int bytes) --{ -- unsigned char readarr[4]; -- uint32_t id1; -- uint32_t id2; -- -- if (spi_rdid(readarr, bytes)) -- return 0; -- -- if (!oddparity(readarr[0])) -- printf_debug("RDID byte 0 parity violation. "); -- -- /* Check if this is a continuation vendor ID */ -- if (readarr[0] == 0x7f) { -- if (!oddparity(readarr[1])) -- printf_debug("RDID byte 1 parity violation. "); -- id1 = (readarr[0] << 8) | readarr[1]; -- id2 = readarr[2]; -- if (bytes > 3) { -- id2 <<= 8; -- id2 |= readarr[3]; -- } -- } else { -- id1 = readarr[0]; -- id2 = (readarr[1] << 8) | readarr[2]; -- } -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- -- if (id1 == flash->manufacture_id && id2 == flash->model_id) { -- /* Print the status register to tell the -- * user about possible write protection. -- */ -- spi_prettyprint_status_register(flash); -- -- return 1; -- } -- -- /* Test if this is a pure vendor match. */ -- if (id1 == flash->manufacture_id && -- GENERIC_DEVICE_ID == flash->model_id) -- return 1; -- -- return 0; --} -- --int probe_spi_rdid(struct flashchip *flash) --{ -- return probe_spi_rdid_generic(flash, 3); --} -- --/* support 4 bytes flash ID */ --int probe_spi_rdid4(struct flashchip *flash) --{ -- /* only some SPI chipsets support 4 bytes commands */ -- switch (spi_controller) { -- case SPI_CONTROLLER_ICH7: -- case SPI_CONTROLLER_ICH9: -- case SPI_CONTROLLER_VIA: -- case SPI_CONTROLLER_SB600: -- case SPI_CONTROLLER_WBSIO: --#if FT2232_SPI_SUPPORT == 1 -- case SPI_CONTROLLER_FT2232: --#endif -- case SPI_CONTROLLER_DUMMY: -- return probe_spi_rdid_generic(flash, 4); -- default: -- printf_debug("4b ID not supported on this SPI controller\n"); -- } -- -- return 0; --} -- --int probe_spi_rems(struct flashchip *flash) --{ -- unsigned char readarr[JEDEC_REMS_INSIZE]; -- uint32_t id1, id2; -- -- if (spi_rems(readarr)) -- return 0; -- -- id1 = readarr[0]; -- id2 = readarr[1]; -- -- printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2); -- -- if (id1 == flash->manufacture_id && id2 == flash->model_id) { -- /* Print the status register to tell the -- * user about possible write protection. -- */ -- spi_prettyprint_status_register(flash); -- -- return 1; -- } -- -- /* Test if this is a pure vendor match. */ -- if (id1 == flash->manufacture_id && -- GENERIC_DEVICE_ID == flash->model_id) -- return 1; -- -- return 0; --} -- --int probe_spi_res(struct flashchip *flash) --{ -- unsigned char readarr[3]; -- uint32_t id2; -- -- /* Check if RDID was successful and did not return 0xff 0xff 0xff. -- * In that case, RES is pointless. -- */ -- if (!spi_rdid(readarr, 3) && ((readarr[0] != 0xff) || -- (readarr[1] != 0xff) || (readarr[2] != 0xff))) -- return 0; -- -- if (spi_res(readarr)) -- return 0; -- -- id2 = readarr[0]; -- printf_debug("%s: id 0x%x\n", __FUNCTION__, id2); -- if (id2 != flash->model_id) -- return 0; -- -- /* Print the status register to tell the -- * user about possible write protection. -- */ -- spi_prettyprint_status_register(flash); -- return 1; --} -- --uint8_t spi_read_status_register(void) --{ -- const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR }; -- /* FIXME: No workarounds for driver/hardware bugs in generic code. */ -- unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */ -- int ret; -- -- /* Read Status Register */ -- ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr); -- if (ret) -- fprintf(stderr, "RDSR failed!\n"); -- -- return readarr[0]; --} -- --/* Prettyprint the status register. Common definitions. */ --void spi_prettyprint_status_register_common(uint8_t status) --{ -- printf_debug("Chip status register: Bit 5 / Block Protect 3 (BP3) is " -- "%sset\n", (status & (1 << 5)) ? "" : "not "); -- printf_debug("Chip status register: Bit 4 / Block Protect 2 (BP2) is " -- "%sset\n", (status & (1 << 4)) ? "" : "not "); -- printf_debug("Chip status register: Bit 3 / Block Protect 1 (BP1) is " -- "%sset\n", (status & (1 << 3)) ? "" : "not "); -- printf_debug("Chip status register: Bit 2 / Block Protect 0 (BP0) is " -- "%sset\n", (status & (1 << 2)) ? "" : "not "); -- printf_debug("Chip status register: Write Enable Latch (WEL) is " -- "%sset\n", (status & (1 << 1)) ? "" : "not "); -- printf_debug("Chip status register: Write In Progress (WIP/BUSY) is " -- "%sset\n", (status & (1 << 0)) ? "" : "not "); --} -- --/* Prettyprint the status register. Works for -- * ST M25P series -- * MX MX25L series -- */ --void spi_prettyprint_status_register_st_m25p(uint8_t status) --{ -- printf_debug("Chip status register: Status Register Write Disable " -- "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not "); -- printf_debug("Chip status register: Bit 6 is " -- "%sset\n", (status & (1 << 6)) ? "" : "not "); -- spi_prettyprint_status_register_common(status); --} -- --void spi_prettyprint_status_register_sst25(uint8_t status) --{ -- printf_debug("Chip status register: Block Protect Write Disable " -- "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not "); -- printf_debug("Chip status register: Auto Address Increment Programming " -- "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not "); -- spi_prettyprint_status_register_common(status); --} -- --/* Prettyprint the status register. Works for -- * SST 25VF016 -- */ --void spi_prettyprint_status_register_sst25vf016(uint8_t status) --{ -- const char *bpt[] = { -- "none", -- "1F0000H-1FFFFFH", -- "1E0000H-1FFFFFH", -- "1C0000H-1FFFFFH", -- "180000H-1FFFFFH", -- "100000H-1FFFFFH", -- "all", "all" -- }; -- spi_prettyprint_status_register_sst25(status); -- printf_debug("Resulting block protection : %s\n", -- bpt[(status & 0x1c) >> 2]); --} -- --void spi_prettyprint_status_register_sst25vf040b(uint8_t status) --{ -- const char *bpt[] = { -- "none", -- "0x70000-0x7ffff", -- "0x60000-0x7ffff", -- "0x40000-0x7ffff", -- "all blocks", "all blocks", "all blocks", "all blocks" -- }; -- spi_prettyprint_status_register_sst25(status); -- printf_debug("Resulting block protection : %s\n", -- bpt[(status & 0x1c) >> 2]); --} -- --void spi_prettyprint_status_register(struct flashchip *flash) --{ -- uint8_t status; -- -- status = spi_read_status_register(); -- printf_debug("Chip status register is %02x\n", status); -- switch (flash->manufacture_id) { -- case ST_ID: -- if (((flash->model_id & 0xff00) == 0x2000) || -- ((flash->model_id & 0xff00) == 0x2500)) -- spi_prettyprint_status_register_st_m25p(status); -- break; -- case MX_ID: -- if ((flash->model_id & 0xff00) == 0x2000) -- spi_prettyprint_status_register_st_m25p(status); -- break; -- case SST_ID: -- switch (flash->model_id) { -- case 0x2541: -- spi_prettyprint_status_register_sst25vf016(status); -- break; -- case 0x8d: -- case 0x258d: -- spi_prettyprint_status_register_sst25vf040b(status); -- break; -- default: -- spi_prettyprint_status_register_sst25(status); -- break; -- } -- break; -- } --} -- --int spi_chip_erase_60(struct flashchip *flash) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_CE_60_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_CE_60 }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_disable_blockprotect(); -- if (result) { -- fprintf(stderr, "spi_disable_blockprotect failed\n"); -- return result; -- } -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- return result; -- } -- /* Wait until the Write-In-Progress bit is cleared. -- * This usually takes 1-85 s, so wait in 1 s steps. -- */ -- /* FIXME: We assume spi_read_status_register will never fail. */ -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(1000 * 1000); -- if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int spi_chip_erase_c7(struct flashchip *flash) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_CE_C7_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_CE_C7 }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_disable_blockprotect(); -- if (result) { -- fprintf(stderr, "spi_disable_blockprotect failed\n"); -- return result; -- } -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", __func__); -- return result; -- } -- /* Wait until the Write-In-Progress bit is cleared. -- * This usually takes 1-85 s, so wait in 1 s steps. -- */ -- /* FIXME: We assume spi_read_status_register will never fail. */ -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(1000 * 1000); -- if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int spi_chip_erase_60_c7(struct flashchip *flash) --{ -- int result; -- result = spi_chip_erase_60(flash); -- if (result) { -- printf_debug("spi_chip_erase_60 failed, trying c7\n"); -- result = spi_chip_erase_c7(flash); -+ for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) { -+ result = spi_send_command(cmds->writecnt, cmds->readcnt, -+ cmds->writearr, cmds->readarr); - } - return result; - } - --int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_BE_52_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_BE_52, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- return result; -- } -- /* Wait until the Write-In-Progress bit is cleared. -- * This usually takes 100-4000 ms, so wait in 100 ms steps. -- */ -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(100 * 1000); -- if (check_erased_range(flash, addr, blocklen)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --/* Block size is usually -- * 64k for Macronix -- * 32k for SST -- * 4-32k non-uniform for EON -- */ --int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_BE_D8_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_BE_D8, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", __func__); -- return result; -- } -- /* Wait until the Write-In-Progress bit is cleared. -- * This usually takes 100-4000 ms, so wait in 100 ms steps. -- */ -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(100 * 1000); -- if (check_erased_range(flash, addr, blocklen)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int spi_chip_erase_d8(struct flashchip *flash) --{ -- int i, rc = 0; -- int total_size = flash->total_size * 1024; -- int erase_size = 64 * 1024; -- -- spi_disable_blockprotect(); -- -- printf("Erasing chip: \n"); -- -- for (i = 0; i < total_size / erase_size; i++) { -- rc = spi_block_erase_d8(flash, i * erase_size, erase_size); -- if (rc) { -- fprintf(stderr, "Error erasing block at 0x%x\n", i); -- break; -- } -- } -- -- printf("\n"); -- -- return rc; --} -- --/* Sector size is usually 4k, though Macronix eliteflash has 64k */ --int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_SE_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_SE, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff) }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- return result; -- } -- /* Wait until the Write-In-Progress bit is cleared. -- * This usually takes 15-800 ms, so wait in 10 ms steps. -- */ -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(10 * 1000); -- if (check_erased_range(flash, addr, blocklen)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen) --{ -- if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -- fprintf(stderr, "%s called with incorrect arguments\n", -- __func__); -- return -1; -- } -- return spi_chip_erase_60(flash); --} -- --int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen) --{ -- if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -- fprintf(stderr, "%s called with incorrect arguments\n", -- __func__); -- return -1; -- } -- return spi_chip_erase_c7(flash); --} -- --int spi_write_status_enable(void) --{ -- const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR }; -- int result; -- -- /* Send EWSR (Enable Write Status Register). */ -- result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL); -- -- if (result) -- fprintf(stderr, "%s failed\n", __func__); -- -- return result; --} -- --/* -- * This is according the SST25VF016 datasheet, who knows it is more -- * generic that this... -- */ --int spi_write_status_register(int status) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_EWSR_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_EWSR }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_WRSR_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- } -- return result; --} -- --int spi_byte_program(int addr, uint8_t byte) --{ -- int result; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_BYTE_PROGRAM, (addr >> 16) & 0xff, (addr >> 8) & 0xff, (addr & 0xff), byte }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- } -- return result; --} -- --int spi_nbyte_program(int address, uint8_t *bytes, int len) --{ -- int result; -- /* FIXME: Switch to malloc based on len unless that kills speed. */ -- unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { -- JEDEC_BYTE_PROGRAM, -- (address >> 16) & 0xff, -- (address >> 8) & 0xff, -- (address >> 0) & 0xff, -- }; -- struct spi_command spicommands[] = { -- { -- .writecnt = JEDEC_WREN_OUTSIZE, -- .writearr = (const unsigned char[]){ JEDEC_WREN }, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len, -- .writearr = cmd, -- .readcnt = 0, -- .readarr = NULL, -- }, { -- .writecnt = 0, -- .writearr = NULL, -- .readcnt = 0, -- .readarr = NULL, -- }}; -- -- if (!len) { -- fprintf(stderr, "%s called for zero-length write\n", __func__); -- return 1; -- } -- if (len > 256) { -- fprintf(stderr, "%s called for too long a write\n", __func__); -- return 1; -- } -- -- memcpy(&cmd[4], bytes, len); -- -- result = spi_send_multicommand(spicommands); -- if (result) { -- fprintf(stderr, "%s failed during command execution\n", -- __func__); -- } -- return result; --} -- --int spi_disable_blockprotect(void) --{ -- uint8_t status; -- int result; -- -- status = spi_read_status_register(); -- /* If there is block protection in effect, unprotect it first. */ -- if ((status & 0x3c) != 0) { -- printf_debug("Some block protection in effect, disabling\n"); -- result = spi_write_status_register(status & ~0x3c); -- if (result) { -- fprintf(stderr, "spi_write_status_register failed\n"); -- return result; -- } -- } -- return 0; --} -- --int spi_nbyte_read(int address, uint8_t *bytes, int len) --{ -- const unsigned char cmd[JEDEC_READ_OUTSIZE] = { -- JEDEC_READ, -- (address >> 16) & 0xff, -- (address >> 8) & 0xff, -- (address >> 0) & 0xff, -- }; -- -- /* Send Read */ -- return spi_send_command(sizeof(cmd), len, cmd, bytes); --} -- --/* -- * Read a complete flash chip. -- * Each page is read separately in chunks with a maximum size of chunksize. -- */ --int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize) --{ -- int rc = 0; -- int i, j, starthere, lenhere; -- int page_size = flash->page_size; -- int toread; -- -- /* Warning: This loop has a very unusual condition and body. -- * The loop needs to go through each page with at least one affected -- * byte. The lowest page number is (start / page_size) since that -- * division rounds down. The highest page number we want is the page -- * where the last byte of the range lives. That last byte has the -- * address (start + len - 1), thus the highest page number is -- * (start + len - 1) / page_size. Since we want to include that last -- * page as well, the loop condition uses <=. -- */ -- for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { -- /* Byte position of the first byte in the range in this page. */ -- /* starthere is an offset to the base address of the chip. */ -- starthere = max(start, i * page_size); -- /* Length of bytes in the range in this page. */ -- lenhere = min(start + len, (i + 1) * page_size) - starthere; -- for (j = 0; j < lenhere; j += chunksize) { -- toread = min(chunksize, lenhere - j); -- rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread); -- if (rc) -- break; -- } -- if (rc) -- break; -- } -- -- return rc; --} -- - int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) - { - if (!spi_programmer[spi_controller].read) { -@@ -959,34 +191,6 @@ int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) - } - - /* -- * Program chip using byte programming. (SLOW!) -- * This is for chips which can only handle one byte writes -- * and for chips where memory mapped programming is impossible -- * (e.g. due to size constraints in IT87* for over 512 kB) -- */ --int spi_chip_write_1(struct flashchip *flash, uint8_t *buf) --{ -- int total_size = 1024 * flash->total_size; -- int i; -- -- spi_disable_blockprotect(); -- /* Erase first */ -- printf("Erasing flash before programming... "); -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- printf("done.\n"); -- for (i = 0; i < total_size; i++) { -- spi_byte_program(i, buf[i]); -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(10); -- } -- -- return 0; --} -- --/* - * Program chip using page (256 bytes) programming. - * Some SPI masters can't do this, they use single byte programming instead. - */ -@@ -1006,38 +210,3 @@ uint32_t spi_get_valid_read_addr(void) - /* Need to return BBAR for ICH chipsets. */ - return 0; - } -- --int spi_aai_write(struct flashchip *flash, uint8_t *buf) --{ -- uint32_t pos = 2, size = flash->total_size * 1024; -- unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]}; -- int result; -- -- switch (spi_controller) { -- case SPI_CONTROLLER_WBSIO: -- fprintf(stderr, "%s: impossible with Winbond SPI masters," -- " degrading to byte program\n", __func__); -- return spi_chip_write_1(flash, buf); -- default: -- break; -- } -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- result = spi_write_enable(); -- if (result) -- return result; -- spi_send_command(6, 0, w, NULL); -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(5); /* SST25VF040B Tbp is max 10us */ -- while (pos < size) { -- w[1] = buf[pos++]; -- w[2] = buf[pos++]; -- spi_send_command(3, 0, w, NULL); -- while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -- programmer_delay(5); /* SST25VF040B Tbp is max 10us */ -- } -- spi_write_disable(); -- return 0; --} -diff --git a/spi.h b/spi.h -index 3050ccf..1b49d59 100644 ---- a/spi.h -+++ b/spi.h -@@ -74,6 +74,11 @@ - #define JEDEC_BE_D8_OUTSIZE 0x04 - #define JEDEC_BE_D8_INSIZE 0x00 - -+/* Block Erase 0xd7 is supported by PMC chips. */ -+#define JEDEC_BE_D7 0xd7 -+#define JEDEC_BE_D7_OUTSIZE 0x04 -+#define JEDEC_BE_D7_INSIZE 0x00 -+ - /* Sector Erase 0x20 is supported by Macronix/SST chips. */ - #define JEDEC_SE 0x20 - #define JEDEC_SE_OUTSIZE 0x04 -@@ -106,6 +111,7 @@ - #define JEDEC_BYTE_PROGRAM_INSIZE 0x00 - - /* Error codes */ -+#define SPI_GENERIC_ERROR -1 - #define SPI_INVALID_OPCODE -2 - #define SPI_INVALID_ADDRESS -3 - #define SPI_INVALID_LENGTH -4 -diff --git a/spi25.c b/spi25.c -new file mode 100644 -index 0000000..c6d1b65 ---- /dev/null -+++ b/spi25.c -@@ -0,0 +1,981 @@ -+/* -+ * This file is part of the flashrom project. -+ * -+ * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger -+ * Copyright (C) 2008 coresystems GmbH -+ * -+ * 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; version 2 of the License. -+ * -+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+/* -+ * Contains the common SPI chip driver functions -+ */ -+ -+#include -+#include "flash.h" -+#include "flashchips.h" -+#include "chipdrivers.h" -+#include "spi.h" -+ -+void spi_prettyprint_status_register(struct flashchip *flash); -+ -+static int spi_rdid(unsigned char *readarr, int bytes) -+{ -+ const unsigned char cmd[JEDEC_RDID_OUTSIZE] = { JEDEC_RDID }; -+ int ret; -+ int i; -+ -+ ret = spi_send_command(sizeof(cmd), bytes, cmd, readarr); -+ if (ret) -+ return ret; -+ msg_cspew("RDID returned"); -+ for (i = 0; i < bytes; i++) -+ msg_cspew(" 0x%02x", readarr[i]); -+ msg_cspew(". "); -+ return 0; -+} -+ -+static int spi_rems(unsigned char *readarr) -+{ -+ unsigned char cmd[JEDEC_REMS_OUTSIZE] = { JEDEC_REMS, 0, 0, 0 }; -+ uint32_t readaddr; -+ int ret; -+ -+ ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); -+ if (ret == SPI_INVALID_ADDRESS) { -+ /* Find the lowest even address allowed for reads. */ -+ readaddr = (spi_get_valid_read_addr() + 1) & ~1; -+ cmd[1] = (readaddr >> 16) & 0xff, -+ cmd[2] = (readaddr >> 8) & 0xff, -+ cmd[3] = (readaddr >> 0) & 0xff, -+ ret = spi_send_command(sizeof(cmd), JEDEC_REMS_INSIZE, cmd, readarr); -+ } -+ if (ret) -+ return ret; -+ msg_cspew("REMS returned %02x %02x. ", readarr[0], readarr[1]); -+ return 0; -+} -+ -+static int spi_res(unsigned char *readarr) -+{ -+ unsigned char cmd[JEDEC_RES_OUTSIZE] = { JEDEC_RES, 0, 0, 0 }; -+ uint32_t readaddr; -+ int ret; -+ -+ ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); -+ if (ret == SPI_INVALID_ADDRESS) { -+ /* Find the lowest even address allowed for reads. */ -+ readaddr = (spi_get_valid_read_addr() + 1) & ~1; -+ cmd[1] = (readaddr >> 16) & 0xff, -+ cmd[2] = (readaddr >> 8) & 0xff, -+ cmd[3] = (readaddr >> 0) & 0xff, -+ ret = spi_send_command(sizeof(cmd), JEDEC_RES_INSIZE, cmd, readarr); -+ } -+ if (ret) -+ return ret; -+ msg_cspew("RES returned %02x. ", readarr[0]); -+ return 0; -+} -+ -+int spi_write_enable(void) -+{ -+ const unsigned char cmd[JEDEC_WREN_OUTSIZE] = { JEDEC_WREN }; -+ int result; -+ -+ /* Send WREN (Write Enable) */ -+ result = spi_send_command(sizeof(cmd), 0, cmd, NULL); -+ -+ if (result) -+ msg_cerr("%s failed\n", __func__); -+ -+ return result; -+} -+ -+int spi_write_disable(void) -+{ -+ const unsigned char cmd[JEDEC_WRDI_OUTSIZE] = { JEDEC_WRDI }; -+ -+ /* Send WRDI (Write Disable) */ -+ return spi_send_command(sizeof(cmd), 0, cmd, NULL); -+} -+ -+static int probe_spi_rdid_generic(struct flashchip *flash, int bytes) -+{ -+ unsigned char readarr[4]; -+ uint32_t id1; -+ uint32_t id2; -+ -+ if (spi_rdid(readarr, bytes)) -+ return 0; -+ -+ if (!oddparity(readarr[0])) -+ msg_cdbg("RDID byte 0 parity violation. "); -+ -+ /* Check if this is a continuation vendor ID */ -+ if (readarr[0] == 0x7f) { -+ if (!oddparity(readarr[1])) -+ msg_cdbg("RDID byte 1 parity violation. "); -+ id1 = (readarr[0] << 8) | readarr[1]; -+ id2 = readarr[2]; -+ if (bytes > 3) { -+ id2 <<= 8; -+ id2 |= readarr[3]; -+ } -+ } else { -+ id1 = readarr[0]; -+ id2 = (readarr[1] << 8) | readarr[2]; -+ } -+ -+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); -+ -+ if (id1 == flash->manufacture_id && id2 == flash->model_id) { -+ /* Print the status register to tell the -+ * user about possible write protection. -+ */ -+ spi_prettyprint_status_register(flash); -+ -+ return 1; -+ } -+ -+ /* Test if this is a pure vendor match. */ -+ if (id1 == flash->manufacture_id && -+ GENERIC_DEVICE_ID == flash->model_id) -+ return 1; -+ -+ /* Test if there is any vendor ID. */ -+ if (GENERIC_MANUF_ID == flash->manufacture_id && -+ id1 != 0xff) -+ return 1; -+ -+ return 0; -+} -+ -+int probe_spi_rdid(struct flashchip *flash) -+{ -+ return probe_spi_rdid_generic(flash, 3); -+} -+ -+/* support 4 bytes flash ID */ -+int probe_spi_rdid4(struct flashchip *flash) -+{ -+ /* only some SPI chipsets support 4 bytes commands */ -+ switch (spi_controller) { -+#if INTERNAL_SUPPORT == 1 -+ case SPI_CONTROLLER_ICH7: -+ case SPI_CONTROLLER_ICH9: -+ case SPI_CONTROLLER_VIA: -+ case SPI_CONTROLLER_SB600: -+ case SPI_CONTROLLER_WBSIO: -+#endif -+#if FT2232_SPI_SUPPORT == 1 -+ case SPI_CONTROLLER_FT2232: -+#endif -+#if DUMMY_SUPPORT == 1 -+ case SPI_CONTROLLER_DUMMY: -+#endif -+#if BUSPIRATE_SPI_SUPPORT == 1 -+ case SPI_CONTROLLER_BUSPIRATE: -+#endif -+#if DEDIPROG_SUPPORT == 1 -+ case SPI_CONTROLLER_DEDIPROG: -+#endif -+ return probe_spi_rdid_generic(flash, 4); -+ default: -+ msg_cinfo("4b ID not supported on this SPI controller\n"); -+ } -+ -+ return 0; -+} -+ -+int probe_spi_rems(struct flashchip *flash) -+{ -+ unsigned char readarr[JEDEC_REMS_INSIZE]; -+ uint32_t id1, id2; -+ -+ if (spi_rems(readarr)) -+ return 0; -+ -+ id1 = readarr[0]; -+ id2 = readarr[1]; -+ -+ msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2); -+ -+ if (id1 == flash->manufacture_id && id2 == flash->model_id) { -+ /* Print the status register to tell the -+ * user about possible write protection. -+ */ -+ spi_prettyprint_status_register(flash); -+ -+ return 1; -+ } -+ -+ /* Test if this is a pure vendor match. */ -+ if (id1 == flash->manufacture_id && -+ GENERIC_DEVICE_ID == flash->model_id) -+ return 1; -+ -+ /* Test if there is any vendor ID. */ -+ if (GENERIC_MANUF_ID == flash->manufacture_id && -+ id1 != 0xff) -+ return 1; -+ -+ return 0; -+} -+ -+int probe_spi_res(struct flashchip *flash) -+{ -+ unsigned char readarr[3]; -+ uint32_t id2; -+ const unsigned char allff[] = {0xff, 0xff, 0xff}; -+ const unsigned char all00[] = {0x00, 0x00, 0x00}; -+ -+ /* Check if RDID is usable and does not return 0xff 0xff 0xff or -+ * 0x00 0x00 0x00. In that case, RES is pointless. -+ */ -+ if (!spi_rdid(readarr, 3) && memcmp(readarr, allff, 3) && -+ memcmp(readarr, all00, 3)) { -+ msg_cdbg("Ignoring RES in favour of RDID.\n"); -+ return 0; -+ } -+ /* Check if REMS is usable and does not return 0xff 0xff or -+ * 0x00 0x00. In that case, RES is pointless. -+ */ -+ if (!spi_rems(readarr) && memcmp(readarr, allff, JEDEC_REMS_INSIZE) && -+ memcmp(readarr, all00, JEDEC_REMS_INSIZE)) { -+ msg_cdbg("Ignoring RES in favour of REMS.\n"); -+ return 0; -+ } -+ -+ if (spi_res(readarr)) -+ return 0; -+ -+ /* FIXME: Handle the case where RES gives a 2-byte response. */ -+ id2 = readarr[0]; -+ msg_cdbg("%s: id 0x%x\n", __func__, id2); -+ if (id2 != flash->model_id) -+ return 0; -+ -+ /* Print the status register to tell the -+ * user about possible write protection. -+ */ -+ spi_prettyprint_status_register(flash); -+ return 1; -+} -+ -+uint8_t spi_read_status_register(void) -+{ -+ const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR }; -+ /* FIXME: No workarounds for driver/hardware bugs in generic code. */ -+ unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */ -+ int ret; -+ -+ /* Read Status Register */ -+ ret = spi_send_command(sizeof(cmd), sizeof(readarr), cmd, readarr); -+ if (ret) -+ msg_cerr("RDSR failed!\n"); -+ -+ return readarr[0]; -+} -+ -+/* Prettyprint the status register. Common definitions. */ -+void spi_prettyprint_status_register_common(uint8_t status) -+{ -+ msg_cdbg("Chip status register: Bit 5 / Block Protect 3 (BP3) is " -+ "%sset\n", (status & (1 << 5)) ? "" : "not "); -+ msg_cdbg("Chip status register: Bit 4 / Block Protect 2 (BP2) is " -+ "%sset\n", (status & (1 << 4)) ? "" : "not "); -+ msg_cdbg("Chip status register: Bit 3 / Block Protect 1 (BP1) is " -+ "%sset\n", (status & (1 << 3)) ? "" : "not "); -+ msg_cdbg("Chip status register: Bit 2 / Block Protect 0 (BP0) is " -+ "%sset\n", (status & (1 << 2)) ? "" : "not "); -+ msg_cdbg("Chip status register: Write Enable Latch (WEL) is " -+ "%sset\n", (status & (1 << 1)) ? "" : "not "); -+ msg_cdbg("Chip status register: Write In Progress (WIP/BUSY) is " -+ "%sset\n", (status & (1 << 0)) ? "" : "not "); -+} -+ -+/* Prettyprint the status register. Works for -+ * ST M25P series -+ * MX MX25L series -+ */ -+void spi_prettyprint_status_register_st_m25p(uint8_t status) -+{ -+ msg_cdbg("Chip status register: Status Register Write Disable " -+ "(SRWD) is %sset\n", (status & (1 << 7)) ? "" : "not "); -+ msg_cdbg("Chip status register: Bit 6 is " -+ "%sset\n", (status & (1 << 6)) ? "" : "not "); -+ spi_prettyprint_status_register_common(status); -+} -+ -+void spi_prettyprint_status_register_sst25(uint8_t status) -+{ -+ msg_cdbg("Chip status register: Block Protect Write Disable " -+ "(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not "); -+ msg_cdbg("Chip status register: Auto Address Increment Programming " -+ "(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not "); -+ spi_prettyprint_status_register_common(status); -+} -+ -+/* Prettyprint the status register. Works for -+ * SST 25VF016 -+ */ -+void spi_prettyprint_status_register_sst25vf016(uint8_t status) -+{ -+ const char *bpt[] = { -+ "none", -+ "1F0000H-1FFFFFH", -+ "1E0000H-1FFFFFH", -+ "1C0000H-1FFFFFH", -+ "180000H-1FFFFFH", -+ "100000H-1FFFFFH", -+ "all", "all" -+ }; -+ spi_prettyprint_status_register_sst25(status); -+ msg_cdbg("Resulting block protection : %s\n", -+ bpt[(status & 0x1c) >> 2]); -+} -+ -+void spi_prettyprint_status_register_sst25vf040b(uint8_t status) -+{ -+ const char *bpt[] = { -+ "none", -+ "0x70000-0x7ffff", -+ "0x60000-0x7ffff", -+ "0x40000-0x7ffff", -+ "all blocks", "all blocks", "all blocks", "all blocks" -+ }; -+ spi_prettyprint_status_register_sst25(status); -+ msg_cdbg("Resulting block protection : %s\n", -+ bpt[(status & 0x1c) >> 2]); -+} -+ -+void spi_prettyprint_status_register(struct flashchip *flash) -+{ -+ uint8_t status; -+ -+ status = spi_read_status_register(); -+ msg_cdbg("Chip status register is %02x\n", status); -+ switch (flash->manufacture_id) { -+ case ST_ID: -+ if (((flash->model_id & 0xff00) == 0x2000) || -+ ((flash->model_id & 0xff00) == 0x2500)) -+ spi_prettyprint_status_register_st_m25p(status); -+ break; -+ case MX_ID: -+ if ((flash->model_id & 0xff00) == 0x2000) -+ spi_prettyprint_status_register_st_m25p(status); -+ break; -+ case SST_ID: -+ switch (flash->model_id) { -+ case 0x2541: -+ spi_prettyprint_status_register_sst25vf016(status); -+ break; -+ case 0x8d: -+ case 0x258d: -+ spi_prettyprint_status_register_sst25vf040b(status); -+ break; -+ default: -+ spi_prettyprint_status_register_sst25(status); -+ break; -+ } -+ break; -+ } -+} -+ -+int spi_chip_erase_60(struct flashchip *flash) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_CE_60_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_CE_60 }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_disable_blockprotect(); -+ if (result) { -+ msg_cerr("spi_disable_blockprotect failed\n"); -+ return result; -+ } -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution\n", -+ __func__); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 1-85 s, so wait in 1 s steps. -+ */ -+ /* FIXME: We assume spi_read_status_register will never fail. */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(1000 * 1000); -+ if (check_erased_range(flash, 0, flash->total_size * 1024)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+int spi_chip_erase_c7(struct flashchip *flash) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_CE_C7_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_CE_C7 }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_disable_blockprotect(); -+ if (result) { -+ msg_cerr("spi_disable_blockprotect failed\n"); -+ return result; -+ } -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution\n", __func__); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 1-85 s, so wait in 1 s steps. -+ */ -+ /* FIXME: We assume spi_read_status_register will never fail. */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(1000 * 1000); -+ if (check_erased_range(flash, 0, flash->total_size * 1024)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+int spi_block_erase_52(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_BE_52_OUTSIZE, -+ .writearr = (const unsigned char[]){ -+ JEDEC_BE_52, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr & 0xff) -+ }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 100-4000 ms, so wait in 100 ms steps. -+ */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(100 * 1000); -+ if (check_erased_range(flash, addr, blocklen)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+/* Block size is usually -+ * 64k for Macronix -+ * 32k for SST -+ * 4-32k non-uniform for EON -+ */ -+int spi_block_erase_d8(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_BE_D8_OUTSIZE, -+ .writearr = (const unsigned char[]){ -+ JEDEC_BE_D8, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr & 0xff) -+ }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 100-4000 ms, so wait in 100 ms steps. -+ */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(100 * 1000); -+ if (check_erased_range(flash, addr, blocklen)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+/* Block size is usually -+ * 4k for PMC -+ */ -+int spi_block_erase_d7(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_BE_D7_OUTSIZE, -+ .writearr = (const unsigned char[]){ -+ JEDEC_BE_D7, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr & 0xff) -+ }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 100-4000 ms, so wait in 100 ms steps. -+ */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(100 * 1000); -+ if (check_erased_range(flash, addr, blocklen)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+int spi_chip_erase_d8(struct flashchip *flash) -+{ -+ int i, rc = 0; -+ int total_size = flash->total_size * 1024; -+ int erase_size = 64 * 1024; -+ -+ spi_disable_blockprotect(); -+ -+ msg_cinfo("Erasing chip: \n"); -+ -+ for (i = 0; i < total_size / erase_size; i++) { -+ rc = spi_block_erase_d8(flash, i * erase_size, erase_size); -+ if (rc) { -+ msg_cerr("Error erasing block at 0x%x\n", i); -+ break; -+ } -+ } -+ -+ msg_cinfo("\n"); -+ -+ return rc; -+} -+ -+/* Sector size is usually 4k, though Macronix eliteflash has 64k */ -+int spi_block_erase_20(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_SE_OUTSIZE, -+ .writearr = (const unsigned char[]){ -+ JEDEC_SE, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr & 0xff) -+ }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ return result; -+ } -+ /* Wait until the Write-In-Progress bit is cleared. -+ * This usually takes 15-800 ms, so wait in 10 ms steps. -+ */ -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(10 * 1000); -+ if (check_erased_range(flash, addr, blocklen)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+int spi_block_erase_60(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); -+ return -1; -+ } -+ return spi_chip_erase_60(flash); -+} -+ -+int spi_block_erase_c7(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); -+ return -1; -+ } -+ return spi_chip_erase_c7(flash); -+} -+ -+int spi_write_status_enable(void) -+{ -+ const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR }; -+ int result; -+ -+ /* Send EWSR (Enable Write Status Register). */ -+ result = spi_send_command(sizeof(cmd), JEDEC_EWSR_INSIZE, cmd, NULL); -+ -+ if (result) -+ msg_cerr("%s failed\n", __func__); -+ -+ return result; -+} -+ -+/* -+ * This is according the SST25VF016 datasheet, who knows it is more -+ * generic that this... -+ */ -+int spi_write_status_register(int status) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ /* FIXME: WRSR requires either EWSR or WREN depending on chip type. */ -+ .writecnt = JEDEC_EWSR_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_EWSR }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_WRSR_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution\n", -+ __func__); -+ } -+ return result; -+} -+ -+int spi_byte_program(int addr, uint8_t databyte) -+{ -+ int result; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE, -+ .writearr = (const unsigned char[]){ -+ JEDEC_BYTE_PROGRAM, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr & 0xff), -+ databyte -+ }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ } -+ return result; -+} -+ -+int spi_nbyte_program(int addr, uint8_t *bytes, int len) -+{ -+ int result; -+ /* FIXME: Switch to malloc based on len unless that kills speed. */ -+ unsigned char cmd[JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + 256] = { -+ JEDEC_BYTE_PROGRAM, -+ (addr >> 16) & 0xff, -+ (addr >> 8) & 0xff, -+ (addr >> 0) & 0xff, -+ }; -+ struct spi_command cmds[] = { -+ { -+ .writecnt = JEDEC_WREN_OUTSIZE, -+ .writearr = (const unsigned char[]){ JEDEC_WREN }, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = JEDEC_BYTE_PROGRAM_OUTSIZE - 1 + len, -+ .writearr = cmd, -+ .readcnt = 0, -+ .readarr = NULL, -+ }, { -+ .writecnt = 0, -+ .writearr = NULL, -+ .readcnt = 0, -+ .readarr = NULL, -+ }}; -+ -+ if (!len) { -+ msg_cerr("%s called for zero-length write\n", __func__); -+ return 1; -+ } -+ if (len > 256) { -+ msg_cerr("%s called for too long a write\n", __func__); -+ return 1; -+ } -+ -+ memcpy(&cmd[4], bytes, len); -+ -+ result = spi_send_multicommand(cmds); -+ if (result) { -+ msg_cerr("%s failed during command execution at address 0x%x\n", -+ __func__, addr); -+ } -+ return result; -+} -+ -+int spi_disable_blockprotect(void) -+{ -+ uint8_t status; -+ int result; -+ -+ status = spi_read_status_register(); -+ /* If there is block protection in effect, unprotect it first. */ -+ if ((status & 0x3c) != 0) { -+ msg_cdbg("Some block protection in effect, disabling\n"); -+ result = spi_write_status_register(status & ~0x3c); -+ if (result) { -+ msg_cerr("spi_write_status_register failed\n"); -+ return result; -+ } -+ } -+ return 0; -+} -+ -+int spi_nbyte_read(int address, uint8_t *bytes, int len) -+{ -+ const unsigned char cmd[JEDEC_READ_OUTSIZE] = { -+ JEDEC_READ, -+ (address >> 16) & 0xff, -+ (address >> 8) & 0xff, -+ (address >> 0) & 0xff, -+ }; -+ -+ /* Send Read */ -+ return spi_send_command(sizeof(cmd), len, cmd, bytes); -+} -+ -+/* -+ * Read a complete flash chip. -+ * Each page is read separately in chunks with a maximum size of chunksize. -+ */ -+int spi_read_chunked(struct flashchip *flash, uint8_t *buf, int start, int len, int chunksize) -+{ -+ int rc = 0; -+ int i, j, starthere, lenhere; -+ int page_size = flash->page_size; -+ int toread; -+ -+ /* Warning: This loop has a very unusual condition and body. -+ * The loop needs to go through each page with at least one affected -+ * byte. The lowest page number is (start / page_size) since that -+ * division rounds down. The highest page number we want is the page -+ * where the last byte of the range lives. That last byte has the -+ * address (start + len - 1), thus the highest page number is -+ * (start + len - 1) / page_size. Since we want to include that last -+ * page as well, the loop condition uses <=. -+ */ -+ for (i = start / page_size; i <= (start + len - 1) / page_size; i++) { -+ /* Byte position of the first byte in the range in this page. */ -+ /* starthere is an offset to the base address of the chip. */ -+ starthere = max(start, i * page_size); -+ /* Length of bytes in the range in this page. */ -+ lenhere = min(start + len, (i + 1) * page_size) - starthere; -+ for (j = 0; j < lenhere; j += chunksize) { -+ toread = min(chunksize, lenhere - j); -+ rc = spi_nbyte_read(starthere + j, buf + starthere - start + j, toread); -+ if (rc) -+ break; -+ } -+ if (rc) -+ break; -+ } -+ -+ return rc; -+} -+ -+/* -+ * Program chip using byte programming. (SLOW!) -+ * This is for chips which can only handle one byte writes -+ * and for chips where memory mapped programming is impossible -+ * (e.g. due to size constraints in IT87* for over 512 kB) -+ */ -+int spi_chip_write_1(struct flashchip *flash, uint8_t *buf) -+{ -+ int total_size = 1024 * flash->total_size; -+ int i, result = 0; -+ -+ spi_disable_blockprotect(); -+ /* Erase first */ -+ msg_cinfo("Erasing flash before programming... "); -+ if (erase_flash(flash)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ msg_cinfo("done.\n"); -+ for (i = 0; i < total_size; i++) { -+ result = spi_byte_program(i, buf[i]); -+ if (result) -+ return 1; -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(10); -+ } -+ -+ return 0; -+} -+ -+int spi_aai_write(struct flashchip *flash, uint8_t *buf) -+{ -+ uint32_t pos = 2, size = flash->total_size * 1024; -+ unsigned char w[6] = {0xad, 0, 0, 0, buf[0], buf[1]}; -+ int result; -+ -+ switch (spi_controller) { -+#if INTERNAL_SUPPORT == 1 -+ case SPI_CONTROLLER_WBSIO: -+ msg_cerr("%s: impossible with Winbond SPI masters," -+ " degrading to byte program\n", __func__); -+ return spi_chip_write_1(flash, buf); -+#endif -+ default: -+ break; -+ } -+ if (erase_flash(flash)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } -+ /* FIXME: This will fail on ICH/VIA SPI. */ -+ result = spi_write_enable(); -+ if (result) -+ return result; -+ spi_send_command(6, 0, w, NULL); -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(5); /* SST25VF040B Tbp is max 10us */ -+ while (pos < size) { -+ w[1] = buf[pos++]; -+ w[2] = buf[pos++]; -+ spi_send_command(3, 0, w, NULL); -+ while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) -+ programmer_delay(5); /* SST25VF040B Tbp is max 10us */ -+ } -+ spi_write_disable(); -+ return 0; -+} -diff --git a/sst28sf040.c b/sst28sf040.c -index 35f8c27..b9e33ab 100644 ---- a/sst28sf040.c -+++ b/sst28sf040.c -@@ -3,6 +3,7 @@ - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005 coresystems GmbH -+ * Copyright (C) 2009 Sean Nelson - * - * 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 -@@ -20,6 +21,7 @@ - */ - - #include "flash.h" -+#include "chipdrivers.h" - - #define AUTO_PG_ERASE1 0x20 - #define AUTO_PG_ERASE2 0xD0 -@@ -30,31 +32,27 @@ - - static void protect_28sf040(chipaddr bios) - { -- uint8_t tmp; -- -- tmp = chip_readb(bios + 0x1823); -- tmp = chip_readb(bios + 0x1820); -- tmp = chip_readb(bios + 0x1822); -- tmp = chip_readb(bios + 0x0418); -- tmp = chip_readb(bios + 0x041B); -- tmp = chip_readb(bios + 0x0419); -- tmp = chip_readb(bios + 0x040A); -+ chip_readb(bios + 0x1823); -+ chip_readb(bios + 0x1820); -+ chip_readb(bios + 0x1822); -+ chip_readb(bios + 0x0418); -+ chip_readb(bios + 0x041B); -+ chip_readb(bios + 0x0419); -+ chip_readb(bios + 0x040A); - } - - static void unprotect_28sf040(chipaddr bios) - { -- uint8_t tmp; -- -- tmp = chip_readb(bios + 0x1823); -- tmp = chip_readb(bios + 0x1820); -- tmp = chip_readb(bios + 0x1822); -- tmp = chip_readb(bios + 0x0418); -- tmp = chip_readb(bios + 0x041B); -- tmp = chip_readb(bios + 0x0419); -- tmp = chip_readb(bios + 0x041A); -+ chip_readb(bios + 0x1823); -+ chip_readb(bios + 0x1820); -+ chip_readb(bios + 0x1822); -+ chip_readb(bios + 0x0418); -+ chip_readb(bios + 0x041B); -+ chip_readb(bios + 0x0419); -+ chip_readb(bios + 0x041A); - } - --static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, int sector_size) -+int erase_sector_28sf040(struct flashchip *flash, unsigned int address, unsigned int sector_size) - { - chipaddr bios = flash->virtual_memory; - -@@ -65,13 +63,13 @@ static int erase_sector_28sf040(struct flashchip *flash, unsigned long address, - toggle_ready_jedec(bios); - - if (check_erased_range(flash, address, sector_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; - } - --static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst, -+int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst, - unsigned int page_size) - { - int i; -@@ -94,30 +92,6 @@ static int write_sector_28sf040(chipaddr bios, uint8_t *src, chipaddr dst, - return 0; - } - --int probe_28sf040(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(RESET, bios); -- programmer_delay(10); -- -- chip_writeb(READ_ID, bios); -- programmer_delay(10); -- id1 = chip_readb(bios); -- programmer_delay(10); -- id2 = chip_readb(bios + 0x01); -- -- chip_writeb(RESET, bios); -- programmer_delay(10); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- if (id1 == flash->manufacture_id && id2 == flash->model_id) -- return 1; -- -- return 0; --} -- - int erase_28sf040(struct flashchip *flash) - { - chipaddr bios = flash->virtual_memory; -@@ -131,7 +105,7 @@ int erase_28sf040(struct flashchip *flash) - toggle_ready_jedec(bios); - - if (check_erased_range(flash, 0, flash->total_size * 1024)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - return 0; -@@ -146,23 +120,33 @@ int write_28sf040(struct flashchip *flash, uint8_t *buf) - - unprotect_28sf040(bios); - -- printf("Programming page: "); -+ msg_cinfo("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_sector_28sf040(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ -- printf("%04d at address: 0x%08x", i, i * page_size); -+ msg_cinfo("%04d at address: 0x%08x", i, i * page_size); - write_sector_28sf040(bios, buf + i * page_size, - bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } -- printf("\n"); -+ msg_cinfo("\n"); - - protect_28sf040(bios); - - return 0; - } -+ -+int erase_chip_28sf040(struct flashchip *flash, unsigned int addr, unsigned int blocklen) -+{ -+ if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); -+ return -1; -+ } -+ return erase_28sf040(flash); -+} -diff --git a/sst49lf040.c b/sst49lf040.c -deleted file mode 100644 -index ab1c918..0000000 ---- a/sst49lf040.c -+++ /dev/null -@@ -1,72 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2000 Silicon Integrated System Corporation -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --int erase_49lf040(struct flashchip *flash) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- -- for (i = 0; i < total_size / page_size; i++) { -- /* Chip erase only works in parallel programming mode -- * for the 49lf040. Use sector-erase instead */ -- if (erase_sector_jedec(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- } -- -- return 0; --} -- --int write_49lf040(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- /* erase the page before programming -- * Chip erase only works in parallel programming mode -- * for the 49lf040. Use sector-erase instead */ -- if (erase_sector_jedec(flash, i * page_size, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- /* write to the sector */ -- if (i % 10 == 0) -- printf("%04d at address: 0x%08x ", i, i * page_size); -- -- write_sector_jedec(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- -- if (i % 10 == 0) -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- fflush(stdout); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/sst49lfxxxc.c b/sst49lfxxxc.c -index 848ccde..1331cda 100644 ---- a/sst49lfxxxc.c -+++ b/sst49lfxxxc.c -@@ -3,6 +3,7 @@ - * - * Copyright (C) 2000 Silicon Integrated System Corporation - * Copyright (C) 2005-2007 coresystems GmbH -+ * Copyright (C) 2009 Sean Nelson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -21,19 +22,16 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - --#define SECTOR_ERASE 0x30 --#define BLOCK_ERASE 0x20 --#define ERASE 0xD0 --#define AUTO_PGRM 0x10 --#define RESET 0xFF --#define READ_ID 0x90 --#define READ_STATUS 0x70 --#define CLEAR_STATUS 0x50 -+int unlock_block_49lfxxxc(struct flashchip *flash, unsigned long address, unsigned char bits) -+{ -+ unsigned long lock = flash->virtual_registers + address + 2; -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", lock, chip_readb(lock)); -+ chip_writeb(bits, lock); - --#define STATUS_BPS (1 << 1) --#define STATUS_ESS (1 << 6) --#define STATUS_WSMS (1 << 7) -+ return 0; -+} - - static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) - { -@@ -41,30 +39,30 @@ static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) - int i, left = flash->total_size * 1024; - unsigned long address; - -- printf_debug("\nbios=0x%08lx\n", registers); -+ msg_cdbg("\nbios=0x%08lx\n", registers); - for (i = 0; left > 65536; i++, left -= 65536) { -- printf_debug("lockbits at address=0x%08lx is 0x%01x\n", -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", - registers + (i * 65536) + 2, - chip_readb(registers + (i * 65536) + 2)); - chip_writeb(bits, registers + (i * 65536) + 2); - } - address = i * 65536; -- printf_debug("lockbits at address=0x%08lx is 0x%01x\n", -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 32768; -- printf_debug("lockbits at address=0x%08lx is 0x%01x\n", -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 8192; -- printf_debug("lockbits at address=0x%08lx is 0x%01x\n", -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); - address += 8192; -- printf_debug("lockbits at address=0x%08lx is 0x%01x\n", -+ msg_cdbg("lockbits at address=0x%08lx is 0x%01x\n", - registers + address + 2, - chip_readb(registers + address + 2)); - chip_writeb(bits, registers + address + 2); -@@ -72,98 +70,25 @@ static int write_lockbits_49lfxxxc(struct flashchip *flash, unsigned char bits) - return 0; - } - --static int erase_sector_49lfxxxc(struct flashchip *flash, unsigned long address, int sector_size) --{ -- unsigned char status; -- chipaddr bios = flash->virtual_memory; -- -- chip_writeb(SECTOR_ERASE, bios); -- chip_writeb(ERASE, bios + address); -- -- do { -- status = chip_readb(bios); -- if (status & (STATUS_ESS | STATUS_BPS)) { -- printf("sector erase FAILED at address=0x%08lx status=0x%01x\n", bios + address, status); -- chip_writeb(CLEAR_STATUS, bios); -- return (-1); -- } -- } while (!(status & STATUS_WSMS)); -- chip_writeb(RESET, bios); -- -- if (check_erased_range(flash, address, sector_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --static int write_sector_49lfxxxc(chipaddr bios, uint8_t *src, chipaddr dst, -- unsigned int page_size) --{ -- int i; -- unsigned char status; -- -- chip_writeb(CLEAR_STATUS, bios); -- for (i = 0; i < page_size; i++) { -- /* transfer data from source to destination */ -- if (*src == 0xFF) { -- dst++, src++; -- /* If the data is 0xFF, don't program it */ -- continue; -- } -- /*issue AUTO PROGRAM command */ -- chip_writeb(AUTO_PGRM, bios); -- chip_writeb(*src++, dst++); -- -- do { -- status = chip_readb(bios); -- if (status & (STATUS_ESS | STATUS_BPS)) { -- printf("sector write FAILED at address=0x%08lx status=0x%01x\n", dst, status); -- chip_writeb(CLEAR_STATUS, bios); -- return (-1); -- } -- } while (!(status & STATUS_WSMS)); -- } -- -- return 0; --} -- --int probe_49lfxxxc(struct flashchip *flash) -+int unlock_49lfxxxc(struct flashchip *flash) - { -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- chip_writeb(RESET, bios); -- -- chip_writeb(READ_ID, bios); -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- chip_writeb(RESET, bios); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -- -- if (!(id1 == flash->manufacture_id && id2 == flash->model_id)) -- return 0; -- -- map_flash_registers(flash); -- -- return 1; -+ return write_lockbits_49lfxxxc(flash, 0); - } - --int erase_49lfxxxc(struct flashchip *flash) -+int erase_sector_49lfxxxc(struct flashchip *flash, unsigned int address, unsigned int sector_size) - { -+ uint8_t status; - chipaddr bios = flash->virtual_memory; -- int i; -- unsigned int total_size = flash->total_size * 1024; - -- write_lockbits_49lfxxxc(flash, 0); -- for (i = 0; i < total_size; i += flash->page_size) -- if (erase_sector_49lfxxxc(flash, i, flash->page_size)) -- return (-1); -+ chip_writeb(0x30, bios); -+ chip_writeb(0xD0, bios + address); - -- chip_writeb(RESET, bios); -+ status = wait_82802ab(bios); - -+ if (check_erased_range(flash, address, sector_size)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; -+ } - return 0; - } - -@@ -175,23 +100,23 @@ int write_49lfxxxc(struct flashchip *flash, uint8_t *buf) - chipaddr bios = flash->virtual_memory; - - write_lockbits_49lfxxxc(flash, 0); -- printf("Programming page: "); -+ msg_cinfo("Programming page: "); - for (i = 0; i < total_size / page_size; i++) { - /* erase the page before programming */ - if (erase_sector_49lfxxxc(flash, i * page_size, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - - /* write to the sector */ -- printf("%04d at address: 0x%08x", i, i * page_size); -- write_sector_49lfxxxc(bios, buf + i * page_size, -+ msg_cinfo("%04d at address: 0x%08x", i, i * page_size); -+ write_page_82802ab(bios, buf + i * page_size, - bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); - } -- printf("\n"); -+ msg_cinfo("\n"); - -- chip_writeb(RESET, bios); -+ chip_writeb(0xFF, bios); - - return 0; - } -diff --git a/sst_fwhub.c b/sst_fwhub.c -index e7ae9e9..2b867c8 100644 ---- a/sst_fwhub.c -+++ b/sst_fwhub.c -@@ -2,6 +2,8 @@ - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation -+ * Copyright (C) 2009 Kontron Modular Computers -+ * Copyright (C) 2009 Sean Nelson - * - * 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 -@@ -20,19 +22,10 @@ - - /* Adapted from the Intel FW hub stuff for 82802ax parts. */ - -+#include -+#include - #include "flash.h" -- --// I need that Berkeley bit-map printer --void print_sst_fwhub_status(uint8_t status) --{ -- printf("%s", status & 0x80 ? "Ready:" : "Busy:"); -- printf("%s", status & 0x40 ? "BE SUSPEND:" : "BE RUN/FINISH:"); -- printf("%s", status & 0x20 ? "BE ERROR:" : "BE OK:"); -- printf("%s", status & 0x10 ? "PROG ERR:" : "PROG OK:"); -- printf("%s", status & 0x8 ? "VP ERR:" : "VPP OK:"); -- printf("%s", status & 0x4 ? "PROG SUSPEND:" : "PROG RUN/FINISH:"); -- printf("%s", status & 0x2 ? "WP|TBL#|WP#,ABORT:" : "UNLOCK:"); --} -+#include "chipdrivers.h" - - int check_sst_fwhub_block_lock(struct flashchip *flash, int offset) - { -@@ -40,20 +33,20 @@ int check_sst_fwhub_block_lock(struct flashchip *flash, int offset) - uint8_t blockstatus; - - blockstatus = chip_readb(registers + offset + 2); -- printf_debug("Lock status for 0x%06x (size 0x%06x) is %02x, ", -+ msg_cdbg("Lock status for 0x%06x (size 0x%06x) is %02x, ", - offset, flash->page_size, blockstatus); - switch (blockstatus & 0x3) { - case 0x0: -- printf_debug("full access\n"); -+ msg_cdbg("full access\n"); - break; - case 0x1: -- printf_debug("write locked\n"); -+ msg_cdbg("write locked\n"); - break; - case 0x2: -- printf_debug("locked open\n"); -+ msg_cdbg("locked open\n"); - break; - case 0x3: -- printf_debug("write locked down\n"); -+ msg_cdbg("write locked down\n"); - break; - } - /* Return content of the write_locked bit */ -@@ -68,93 +61,38 @@ int clear_sst_fwhub_block_lock(struct flashchip *flash, int offset) - blockstatus = check_sst_fwhub_block_lock(flash, offset); - - if (blockstatus) { -- printf_debug("Trying to clear lock for 0x%06x... ", offset) -+ msg_cdbg("Trying to clear lock for 0x%06x... ", offset); - chip_writeb(0, registers + offset + 2); - - blockstatus = check_sst_fwhub_block_lock(flash, offset); -- printf_debug("%s\n", (blockstatus) ? "failed" : "OK"); -+ msg_cdbg("%s\n", (blockstatus) ? "failed" : "OK"); - } - - return blockstatus; - } - --/* probe_jedec works fine for probing */ --int probe_sst_fwhub(struct flashchip *flash) -+int printlock_sst_fwhub(struct flashchip *flash) - { - int i; - -- if (probe_jedec(flash) == 0) -- return 0; -- -- map_flash_registers(flash); -- - for (i = 0; i < flash->total_size * 1024; i += flash->page_size) - check_sst_fwhub_block_lock(flash, i); - -- return 1; --} -- --int erase_sst_fwhub_block(struct flashchip *flash, int offset, int page_size) --{ -- uint8_t blockstatus = clear_sst_fwhub_block_lock(flash, offset); -- -- if (blockstatus) { -- printf("Block lock clearing failed, not erasing block " -- "at 0x%06x\n", offset); -- return 1; -- } -- -- if (erase_block_jedec(flash, offset, page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- toggle_ready_jedec(flash->virtual_memory); -- - return 0; - } - --int erase_sst_fwhub(struct flashchip *flash) -+int unlock_sst_fwhub(struct flashchip *flash) - { -- int i; -- unsigned int total_size = flash->total_size * 1024; -+ int i, ret=0; - -- for (i = 0; i < total_size; i += flash->page_size) { -- if (erase_sst_fwhub_block(flash, i, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -+ for (i = 0; i < flash->total_size * 1024; i += flash->page_size) -+ { -+ if (clear_sst_fwhub_block_lock(flash, i)) -+ { -+ msg_cdbg("Warning: Unlock Failed for block 0x%06x\n", i); -+ ret++; - } - } -- -- return 0; -+ return ret; - } - --int write_sst_fwhub(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- uint8_t blockstatus; -- -- // FIXME: We want block wide erase instead of ironing the whole chip -- if (erase_sst_fwhub(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- printf("%04d at address: 0x%08x", i, i * page_size); -- blockstatus = clear_sst_fwhub_block_lock(flash, i * page_size); -- if (blockstatus) { -- printf(" is locked down permanently, aborting\n"); -- return 1; -- } -- write_sector_jedec(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/stm50flw0x0x.c b/stm50flw0x0x.c -index 30b7d50..3539395 100644 ---- a/stm50flw0x0x.c -+++ b/stm50flw0x0x.c -@@ -2,6 +2,7 @@ - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Claus Gindhart -+ * Copyright (C) 2009 Sean Nelson - * - * 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 -@@ -30,88 +31,7 @@ - #include - #include "flash.h" - #include "flashchips.h" -- --void protect_stm50flw0x0x(chipaddr bios) --{ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xA0, bios + 0x5555); -- -- programmer_delay(200); --} -- --int probe_stm50flw0x0x(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- uint32_t largeid1, largeid2; -- -- /* Issue JEDEC Product ID Entry command */ -- chip_writeb(0xAA, bios + 0x5555); -- programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -- programmer_delay(10); -- chip_writeb(0x90, bios + 0x5555); -- programmer_delay(40); -- -- /* Read product ID */ -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- largeid1 = id1; -- largeid2 = id2; -- -- /* Check if it is a continuation ID, this should be a while loop. */ -- if (id1 == 0x7F) { -- largeid1 <<= 8; -- id1 = chip_readb(bios + 0x100); -- largeid1 |= id1; -- } -- if (id2 == 0x7F) { -- largeid2 <<= 8; -- id2 = chip_readb(bios + 0x101); -- largeid2 |= id2; -- } -- -- /* Issue JEDEC Product ID Exit command */ -- chip_writeb(0xAA, bios + 0x5555); -- programmer_delay(10); -- chip_writeb(0x55, bios + 0x2AAA); -- programmer_delay(10); -- chip_writeb(0xF0, bios + 0x5555); -- programmer_delay(40); -- -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, largeid1, -- largeid2); -- -- if (largeid1 != flash->manufacture_id || largeid2 != flash->model_id) -- return 0; -- -- map_flash_registers(flash); -- -- return 1; --} -- --static void wait_stm50flw0x0x(chipaddr bios) --{ -- uint8_t id1; -- // id2; -- -- chip_writeb(0x70, bios); -- if ((chip_readb(bios) & 0x80) == 0) { // it's busy -- while ((chip_readb(bios) & 0x80) == 0) ; -- } -- // put another command to get out of status register mode -- -- chip_writeb(0x90, bios); -- programmer_delay(10); -- -- id1 = chip_readb(bios); -- -- // this is needed to jam it out of "read id" mode -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); --} -+#include "chipdrivers.h" - - /* - * claus.gindhart@kontron.com -@@ -129,7 +49,7 @@ int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) - * to them. The size of the locking sectors depends on the type - * of chip. - * -- * Sometimes, the BIOS does this for you; so you propably -+ * Sometimes, the BIOS does this for you; so you probably - * don't need to worry about that. - */ - -@@ -141,19 +61,19 @@ int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) - - // unlock each 4k-sector - for (j = 0; j < 0x10000; j += 0x1000) { -- printf_debug("unlocking at 0x%x\n", offset + j); -+ msg_cdbg("unlocking at 0x%x\n", offset + j); - chip_writeb(unlock_sector, wrprotect + offset + j); - if (chip_readb(wrprotect + offset + j) != unlock_sector) { -- printf("Cannot unlock sector @ 0x%x\n", -+ msg_cerr("Cannot unlock sector @ 0x%x\n", - offset + j); - return -1; - } - } - } else { -- printf_debug("unlocking at 0x%x\n", offset); -+ msg_cdbg("unlocking at 0x%x\n", offset); - chip_writeb(unlock_sector, wrprotect + offset); - if (chip_readb(wrprotect + offset) != unlock_sector) { -- printf("Cannot unlock sector @ 0x%x\n", offset); -+ msg_cerr("Cannot unlock sector @ 0x%x\n", offset); - return -1; - } - } -@@ -161,138 +81,69 @@ int unlock_block_stm50flw0x0x(struct flashchip *flash, int offset) - return 0; - } - --int erase_block_stm50flw0x0x(struct flashchip *flash, int offset) -+int unlock_stm50flw0x0x(struct flashchip *flash) - { -- chipaddr bios = flash->virtual_memory + offset; -- -- // clear status register -- chip_writeb(0x50, bios); -- printf_debug("Erase at 0x%lx\n", bios); -- // now start it -- chip_writeb(0x20, bios); -- chip_writeb(0xd0, bios); -- programmer_delay(10); -- -- wait_stm50flw0x0x(flash->virtual_memory); -+ int i; - -- if (check_erased_range(flash, offset, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -+ for (i = 0; i < flash->total_size * 1024; i+= flash->page_size) { -+ if(unlock_block_stm50flw0x0x(flash, i)) { -+ msg_cerr("UNLOCK FAILED!\n"); -+ return -1; -+ } - } -- printf("DONE BLOCK 0x%x\n", offset); - - return 0; - } - --int write_page_stm50flw0x0x(chipaddr bios, uint8_t *src, -- chipaddr dst, int page_size) -+int erase_sector_stm50flw0x0x(struct flashchip *flash, unsigned int sector, unsigned int sectorsize) - { -- int i, rc = 0; -- chipaddr d = dst; -- uint8_t *s = src; -+ chipaddr bios = flash->virtual_memory + sector; - -- /* transfer data from source to destination */ -- for (i = 0; i < page_size; i++) { -- chip_writeb(0x40, dst); -- chip_writeb(*src++, dst++); -- wait_stm50flw0x0x(bios); -- } -+ // clear status register -+ chip_writeb(0x50, bios); -+ msg_cdbg("Erase at 0x%lx\n", bios); -+ // now start it -+ chip_writeb(0x32, bios); -+ chip_writeb(0xd0, bios); -+ programmer_delay(10); - --/* claus.gindhart@kontron.com -- * TODO -- * I think, that verification is not required, but -- * i leave it in anyway -- */ -- dst = d; -- src = s; -- for (i = 0; i < page_size; i++) { -- if (chip_readb(dst) != *src) { -- rc = -1; -- break; -- } -- dst++; -- src++; -- } -+ wait_82802ab(flash->virtual_memory); - -- if (rc) { -- fprintf(stderr, " page 0x%lx failed!\n", -- (d - bios) / page_size); -+ if (check_erased_range(flash, sector, sectorsize)) { -+ msg_cerr("ERASE FAILED!\n"); -+ return -1; - } -+ msg_cinfo("DONE BLOCK 0x%x\n", sector); - -- return rc; -+ return 0; - } - --/* I simply erase block by block -- * I Chip This is not the fastest way, but it works -- */ --int erase_stm50flw0x0x(struct flashchip *flash) -+int erase_chip_stm50flw0x0x(struct flashchip *flash, unsigned int addr, unsigned int blocklen) - { - int i; - int total_size = flash->total_size * 1024; - int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; - -- printf("Erasing page:\n"); -+ if ((addr != 0) || (blocklen != flash->total_size * 1024)) { -+ msg_cerr("%s called with incorrect arguments\n", -+ __func__); -+ return -1; -+ } -+ -+ msg_cinfo("Erasing page:\n"); - for (i = 0; i < total_size / page_size; i++) { -- printf -- ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- printf("%04d at address: 0x%08x ", i, i * page_size); -- if (unlock_block_stm50flw0x0x(flash, i * page_size)) { -- fprintf(stderr, "UNLOCK FAILED!\n"); -- return -1; -- } -- if (erase_block_stm50flw0x0x(flash, i * page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -+ msg_cinfo("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -+ msg_cinfo("%04d at address: 0x%08x ", i, i * page_size); -+ //if (unlock_block_stm50flw0x0x(flash, i * page_size)) { -+ // msg_cerr("UNLOCK FAILED!\n"); -+ // return -1; -+ //} -+ if (erase_block_82802ab(flash, i * page_size, page_size)) { -+ msg_cerr("ERASE FAILED!\n"); - return -1; - } - } -- printf("\n"); -- protect_stm50flw0x0x(bios); -+ msg_cinfo("\n"); - - return 0; - } -- --int write_stm50flw0x0x(struct flashchip *flash, uint8_t * buf) --{ -- int i, rc = 0; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- uint8_t *tmpbuf = malloc(page_size); -- -- if (!tmpbuf) { -- printf("Could not allocate memory!\n"); -- exit(1); -- } -- printf("Programming page: \n"); -- for (i = 0; (i < total_size / page_size) && (rc == 0); i++) { -- printf -- ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- printf("%04d at address: 0x%08x ", i, i * page_size); -- -- /* Auto Skip Blocks, which already contain the desired data -- * Faster, because we only write, what has changed -- * More secure, because blocks, which are excluded -- * (with the exclude or layout feature) -- * are not erased and rewritten; data is retained also -- * in sudden power off situations -- */ -- chip_readn(tmpbuf, bios + i * page_size, page_size); -- if (!memcmp((void *)(buf + i * page_size), tmpbuf, page_size)) { -- printf("SKIPPED\n"); -- continue; -- } -- -- rc = unlock_block_stm50flw0x0x(flash, i * page_size); -- if (!rc) -- rc = erase_block_stm50flw0x0x(flash, i * page_size); -- if (!rc) -- write_page_stm50flw0x0x(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- } -- printf("\n"); -- protect_stm50flw0x0x(bios); -- free(tmpbuf); -- -- return rc; --} -diff --git a/udelay.c b/udelay.c -index 9a0ab36..bae6467 100644 ---- a/udelay.c -+++ b/udelay.c -@@ -2,6 +2,7 @@ - * This file is part of the flashrom project. - * - * Copyright (C) 2000 Silicon Integrated System Corporation -+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger - * - * 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 -@@ -19,47 +20,111 @@ - */ - - #include -+#include -+#include - #include "flash.h" - --// count to a billion. Time it. If it's < 1 sec, count to 10B, etc. -+/* loops per microsecond */ - unsigned long micro = 1; - --void myusec_delay(int usecs) -+__attribute__ ((noinline)) void myusec_delay(int usecs) - { -- volatile unsigned long i; -- for (i = 0; i < usecs * micro; i++) ; -+ unsigned long i; -+ for (i = 0; i < usecs * micro; i++) { -+ /* Make sure the compiler doesn't optimize the loop away. */ -+ asm volatile ("" : : "rm" (i) ); -+ } - } - --void myusec_calibrate_delay(void) -+unsigned long measure_delay(int usecs) - { -- int count = 1000; - unsigned long timeusec; - struct timeval start, end; -- int ok = 0; -+ -+ gettimeofday(&start, 0); -+ myusec_delay(usecs); -+ gettimeofday(&end, 0); -+ timeusec = 1000000 * (end.tv_sec - start.tv_sec) + -+ (end.tv_usec - start.tv_usec); -+ /* Protect against time going forward too much. */ -+ if ((end.tv_sec > start.tv_sec) && -+ ((end.tv_sec - start.tv_sec) >= LONG_MAX / 1000000 - 1)) -+ timeusec = LONG_MAX; -+ /* Protect against time going backwards during leap seconds. */ -+ if ((end.tv_sec < start.tv_sec) || (timeusec > LONG_MAX)) -+ timeusec = 1; -+ -+ return timeusec; -+} -+ -+void myusec_calibrate_delay(void) -+{ -+ unsigned long count = 1000; -+ unsigned long timeusec; -+ int i, tries = 0; - - printf("Calibrating delay loop... "); - -- while (!ok) { -- gettimeofday(&start, 0); -- myusec_delay(count); -- gettimeofday(&end, 0); -- timeusec = 1000000 * (end.tv_sec - start.tv_sec) + -- (end.tv_usec - start.tv_usec); -+recalibrate: -+ count = 1000; -+ while (1) { -+ timeusec = measure_delay(count); -+ if (timeusec > 1000000 / 4) -+ break; -+ if (count >= ULONG_MAX / 2) { -+ msg_pinfo("timer loop overflow, reduced precision. "); -+ break; -+ } - count *= 2; -- if (timeusec < 1000000 / 4) -- continue; -- ok = 1; - } -+ tries ++; - -- // compute one microsecond. That will be count / time -- micro = count / timeusec; -+ /* Avoid division by zero, but in that case the loop is shot anyway. */ -+ if (!timeusec) -+ timeusec = 1; -+ -+ /* Compute rounded up number of loops per microsecond. */ -+ micro = (count * micro) / timeusec + 1; -+ msg_pdbg("%luM loops per second, ", micro); -+ -+ /* Did we try to recalibrate less than 5 times? */ -+ if (tries < 5) { -+ /* Recheck our timing to make sure we weren't just hitting -+ * a scheduler delay or something similar. -+ */ -+ for (i = 0; i < 4; i++) { -+ if (measure_delay(100) < 90) { -+ msg_pdbg("delay more than 10%% too short, " -+ "recalculating... "); -+ goto recalibrate; -+ } -+ } -+ } else { -+ msg_perr("delay loop is unreliable, trying to continue "); -+ } -+ -+ /* We're interested in the actual precision. */ -+ timeusec = measure_delay(10); -+ msg_pdbg("10 myus = %ld us, ", timeusec); -+ timeusec = measure_delay(100); -+ msg_pdbg("100 myus = %ld us, ", timeusec); -+ timeusec = measure_delay(1000); -+ msg_pdbg("1000 myus = %ld us, ", timeusec); -+ timeusec = measure_delay(10000); -+ msg_pdbg("10000 myus = %ld us, ", timeusec); - -- gettimeofday(&start, 0); -- myusec_delay(100); -- gettimeofday(&end, 0); -- timeusec = 1000000 * (end.tv_sec - start.tv_sec) + -- (end.tv_usec - start.tv_usec); -- printf_debug("%ldM loops per second, 100 myus = %ld us. ", -- (unsigned long)micro, timeusec); - printf("OK.\n"); - } -+ -+void internal_delay(int usecs) -+{ -+ /* If the delay is >1 s, use usleep because timing does not need to -+ * be so precise. -+ */ -+ if (usecs > 1000000) { -+ usleep(usecs); -+ } else { -+ myusec_delay(usecs); -+ } -+} -+ -diff --git a/w29ee011.c b/w29ee011.c -index a26cd80..6b88a1c 100644 ---- a/w29ee011.c -+++ b/w29ee011.c -@@ -20,6 +20,7 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - - int probe_w29ee011(struct flashchip *flash) - { -@@ -28,7 +29,7 @@ int probe_w29ee011(struct flashchip *flash) - extern char *chip_to_probe; - - if (!chip_to_probe || strcmp(chip_to_probe, "W29EE011")) { -- printf_debug("Probing disabled for Winbond W29EE011 because " -+ msg_cdbg("Probing disabled for Winbond W29EE011 because " - "the probing sequence puts the AMIC A49LF040A in " - "a funky state. Use 'flashrom -c W29EE011' if you " - "have a board with this chip.\n"); -@@ -61,7 +62,7 @@ int probe_w29ee011(struct flashchip *flash) - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(10); - -- printf_debug("%s: id1 0x%02x, id2 0x%02x\n", __FUNCTION__, id1, id2); -+ msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2); - - if (id1 == flash->manufacture_id && id2 == flash->model_id) - return 1; -diff --git a/w39v040c.c b/w39v040c.c -index 7fccd53..dc4de1c 100644 ---- a/w39v040c.c -+++ b/w39v040c.c -@@ -19,11 +19,12 @@ - */ - - #include "flash.h" -+#include "chipdrivers.h" - --int probe_w39v040c(struct flashchip *flash) -+int printlock_w39v040c(struct flashchip *flash) - { - chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2, lock; -+ uint8_t lock; - - chip_writeb(0xAA, bios + 0x5555); - programmer_delay(10); -@@ -32,8 +33,6 @@ int probe_w39v040c(struct flashchip *flash) - chip_writeb(0x90, bios + 0x5555); - programmer_delay(10); - -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 1); - lock = chip_readb(bios + 0xfff2); - - chip_writeb(0xAA, bios + 0x5555); -@@ -43,54 +42,7 @@ int probe_w39v040c(struct flashchip *flash) - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(40); - -- printf_debug("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2); -- if (!oddparity(id1)) -- printf_debug(", id1 parity violation"); -- printf_debug("\n"); -- if (flash->manufacture_id == id1 && flash->model_id == id2) { -- printf("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n", -- __func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un"); -- return 1; -- } -- -- return 0; --} -- --int erase_w39v040c(struct flashchip *flash) --{ -- int i; -- unsigned int total_size = flash->total_size * 1024; -- -- for (i = 0; i < total_size; i += flash->page_size) { -- if (erase_sector_jedec(flash, i, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- } -- -- return 0; --} -- --int write_w39v040c(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- if (flash->erase(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- printf("%04d at address: 0x%08x", i, i * page_size); -- write_sector_jedec(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- } -- printf("\n"); -- -+ msg_cdbg("%s: Boot block #TBL is %slocked, rest of chip #WP is %slocked.\n", -+ __func__, lock & 0x4 ? "" : "un", lock & 0x8 ? "" : "un"); - return 0; - } -diff --git a/w39v080fa.c b/w39v080fa.c -index 31ef15f..62c55f4 100644 ---- a/w39v080fa.c -+++ b/w39v080fa.c -@@ -19,74 +19,44 @@ - */ - - #include "flash.h" -- --int probe_winbond_fwhub(struct flashchip *flash) --{ -- chipaddr bios = flash->virtual_memory; -- uint8_t id1, id2; -- -- /* Product Identification Entry */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x90, bios + 0x5555); -- programmer_delay(10); -- -- /* Read product ID */ -- id1 = chip_readb(bios); -- id2 = chip_readb(bios + 0x01); -- -- /* Product Identifixation Exit */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0xF0, bios + 0x5555); -- programmer_delay(10); -- -- printf_debug("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2); -- -- if (id1 != flash->manufacture_id || id2 != flash->model_id) -- return 0; -- -- map_flash_registers(flash); -- -- return 1; --} -+#include "chipdrivers.h" - - static int unlock_block_winbond_fwhub(struct flashchip *flash, int offset) - { - chipaddr wrprotect = flash->virtual_registers + offset + 2; - uint8_t locking; - -- printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset, -+ msg_cdbg("Trying to unlock block @0x%08x = 0x%02x\n", offset, - chip_readb(wrprotect)); - - locking = chip_readb(wrprotect); - switch (locking & 0x7) { - case 0: -- printf_debug("Full Access.\n"); -+ msg_cdbg("Full Access.\n"); - return 0; - case 1: -- printf_debug("Write Lock (Default State).\n"); -+ msg_cdbg("Write Lock (Default State).\n"); - chip_writeb(0, wrprotect); - return 0; - case 2: -- printf_debug("Locked Open (Full Access, Lock Down).\n"); -+ msg_cdbg("Locked Open (Full Access, Lock Down).\n"); - return 0; - case 3: -- fprintf(stderr, "Error: Write Lock, Locked Down.\n"); -+ msg_cerr("Error: Write Lock, Locked Down.\n"); - return -1; - case 4: -- printf_debug("Read Lock.\n"); -+ msg_cdbg("Read Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 5: -- printf_debug("Read/Write Lock.\n"); -+ msg_cdbg("Read/Write Lock.\n"); - chip_writeb(0, wrprotect); - return 0; - case 6: -- fprintf(stderr, "Error: Read Lock, Locked Down.\n"); -+ msg_cerr("Error: Read Lock, Locked Down.\n"); - return -1; - case 7: -- fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n"); -+ msg_cerr("Error: Read/Write Lock, Locked Down.\n"); - return -1; - } - -@@ -119,17 +89,17 @@ int unlock_winbond_fwhub(struct flashchip *flash) - chip_writeb(0xF0, bios + 0x5555); - programmer_delay(10); - -- printf_debug("Lockout bits:\n"); -+ msg_cdbg("Lockout bits:\n"); - - if (locking & (1 << 2)) -- fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n"); -+ msg_cerr("Error: hardware bootblock locking (#TBL).\n"); - else -- printf_debug("No hardware bootblock locking (good!)\n"); -+ msg_cdbg("No hardware bootblock locking (good!)\n"); - - if (locking & (1 << 3)) -- fprintf(stderr, "Error: hardware block locking (#WP).\n"); -+ msg_cerr("Error: hardware block locking (#WP).\n"); - else -- printf_debug("No hardware block locking (good!)\n"); -+ msg_cdbg("No hardware block locking (good!)\n"); - - if (locking & ((1 << 2) | (1 << 3))) - return -1; -@@ -141,69 +111,3 @@ int unlock_winbond_fwhub(struct flashchip *flash) - - return 0; - } -- --static int erase_sector_winbond_fwhub(struct flashchip *flash, -- unsigned int sector) --{ -- chipaddr bios = flash->virtual_memory; -- /* Remember: too much sleep can waste your day. */ -- -- printf("0x%08x\b\b\b\b\b\b\b\b\b\b", sector); -- -- /* Sector Erase */ -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x80, bios + 0x5555); -- -- chip_writeb(0xAA, bios + 0x5555); -- chip_writeb(0x55, bios + 0x2AAA); -- chip_writeb(0x30, bios + sector); -- -- /* wait for Toggle bit ready */ -- toggle_ready_jedec(bios); -- -- if (check_erased_range(flash, sector, flash->page_size)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- return 0; --} -- --int erase_winbond_fwhub(struct flashchip *flash) --{ -- int i, total_size = flash->total_size * 1024; -- -- unlock_winbond_fwhub(flash); -- -- printf("Erasing: "); -- -- for (i = 0; i < total_size; i += flash->page_size) { -- if (erase_sector_winbond_fwhub(flash, i)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- } -- -- printf("\n"); -- -- return 0; --} -- --int write_winbond_fwhub(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- chipaddr bios = flash->virtual_memory; -- -- if (erase_winbond_fwhub(flash)) -- return -1; -- -- printf("Programming: "); -- for (i = 0; i < total_size; i += flash->page_size) { -- printf("0x%08x\b\b\b\b\b\b\b\b\b\b", i); -- write_sector_jedec(bios, buf + i, bios + i, flash->page_size); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/w49f002u.c b/w49f002u.c -deleted file mode 100644 -index d12bc72..0000000 ---- a/w49f002u.c -+++ /dev/null -@@ -1,47 +0,0 @@ --/* -- * This file is part of the flashrom project. -- * -- * Copyright (C) 2000 Silicon Integrated System Corporation -- * -- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -- */ -- --#include "flash.h" -- --int write_49f002(struct flashchip *flash, uint8_t *buf) --{ -- int i; -- int total_size = flash->total_size * 1024; -- int page_size = flash->page_size; -- chipaddr bios = flash->virtual_memory; -- -- if (erase_chip_jedec(flash)) { -- fprintf(stderr, "ERASE FAILED!\n"); -- return -1; -- } -- -- printf("Programming page: "); -- for (i = 0; i < total_size / page_size; i++) { -- printf("%04d at address: 0x%08x ", i, i * page_size); -- /* Byte-wise writing of 'page_size' bytes. */ -- write_sector_jedec(bios, buf + i * page_size, -- bios + i * page_size, page_size); -- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); -- fflush(stdout); -- } -- printf("\n"); -- -- return 0; --} -diff --git a/wbsio_spi.c b/wbsio_spi.c -index 6b9425f..ca39322 100644 ---- a/wbsio_spi.c -+++ b/wbsio_spi.c -@@ -2,6 +2,7 @@ - * This file is part of the flashrom project. - * - * Copyright (C) 2008 Peter Stuge -+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger - * - * 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 -@@ -19,6 +20,7 @@ - - #include - #include "flash.h" -+#include "chipdrivers.h" - #include "spi.h" - - #define WBSIO_PORT1 0x2e -@@ -34,18 +36,18 @@ static uint16_t wbsio_get_spibase(uint16_t port) - w836xx_ext_enter(port); - id = sio_read(port, 0x20); - if (id != 0xa0) { -- fprintf(stderr, "\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id); -+ msg_perr("\nW83627 not found at 0x%x, id=0x%02x want=0xa0.\n", port, id); - goto done; - } - - if (0 == (sio_read(port, 0x24) & 2)) { -- fprintf(stderr, "\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port); -+ msg_perr("\nW83627 found at 0x%x, but SPI pins are not enabled. (CR[0x24] bit 1=0)\n", port); - goto done; - } - - sio_write(port, 0x07, 0x06); - if (0 == (sio_read(port, 0x30) & 1)) { -- fprintf(stderr, "\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port); -+ msg_perr("\nW83627 found at 0x%x, but SPI is not enabled. (LDN6[0x30] bit 0=0)\n", port); - goto done; - } - -@@ -62,7 +64,7 @@ int wbsio_check_for_spi(const char *name) - if (0 == (wbsio_spibase = wbsio_get_spibase(WBSIO_PORT2))) - return 1; - -- printf_debug("\nwbsio_spibase = 0x%x\n", wbsio_spibase); -+ msg_pspew("\nwbsio_spibase = 0x%x\n", wbsio_spibase); - - buses_supported |= CHIP_BUSTYPE_SPI; - spi_controller = SPI_CONTROLLER_WBSIO; -@@ -96,42 +98,42 @@ int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - int i; - uint8_t mode = 0; - -- printf_debug("%s:", __func__); -+ msg_pspew("%s:", __func__); - - if (1 == writecnt && 0 == readcnt) { - mode = 0x10; - } else if (2 == writecnt && 0 == readcnt) { - OUTB(writearr[1], wbsio_spibase + 4); -- printf_debug(" data=0x%02x", writearr[1]); -+ msg_pspew(" data=0x%02x", writearr[1]); - mode = 0x20; - } else if (1 == writecnt && 2 == readcnt) { - mode = 0x30; - } else if (4 == writecnt && 0 == readcnt) { -- printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); -+ msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug("%02x", writearr[i]); -+ msg_pspew("%02x", writearr[i]); - } - mode = 0x40 | (writearr[1] & 0x0f); - } else if (5 == writecnt && 0 == readcnt) { -- printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); -+ msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < 4; i++) { - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug("%02x", writearr[i]); -+ msg_pspew("%02x", writearr[i]); - } - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug(" data=0x%02x", writearr[i]); -+ msg_pspew(" data=0x%02x", writearr[i]); - mode = 0x50 | (writearr[1] & 0x0f); - } else if (8 == writecnt && 0 == readcnt) { -- printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); -+ msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < 4; i++) { - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug("%02x", writearr[i]); -+ msg_pspew("%02x", writearr[i]); - } -- printf_debug(" data=0x"); -+ msg_pspew(" data=0x"); - for (; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug("%02x", writearr[i]); -+ msg_pspew("%02x", writearr[i]); - } - mode = 0x60 | (writearr[1] & 0x0f); - } else if (5 == writecnt && 4 == readcnt) { -@@ -142,17 +144,17 @@ int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - */ - ; - } else if (4 == writecnt && readcnt >= 1 && readcnt <= 4) { -- printf_debug(" addr=0x%02x", (writearr[1] & 0x0f)); -+ msg_pspew(" addr=0x%02x", (writearr[1] & 0x0f)); - for (i = 2; i < writecnt; i++) { - OUTB(writearr[i], wbsio_spibase + i); -- printf_debug("%02x", writearr[i]); -+ msg_pspew("%02x", writearr[i]); - } - mode = ((7 + readcnt) << 4) | (writearr[1] & 0x0f); - } -- printf_debug(" cmd=%02x mode=%02x\n", writearr[0], mode); -+ msg_pspew(" cmd=%02x mode=%02x\n", writearr[0], mode); - - if (!mode) { -- fprintf(stderr, "%s: unsupported command type wr=%d rd=%d\n", -+ msg_perr("%s: unsupported command type wr=%d rd=%d\n", - __func__, writecnt, readcnt); - /* Command type refers to the number of bytes read/written. */ - return SPI_INVALID_LENGTH; -@@ -165,12 +167,12 @@ int wbsio_spi_send_command(unsigned int writecnt, unsigned int readcnt, - if (!readcnt) - return 0; - -- printf_debug("%s: returning data =", __func__); -+ msg_pspew("%s: returning data =", __func__); - for (i = 0; i < readcnt; i++) { - readarr[i] = INB(wbsio_spibase + 4 + i); -- printf_debug(" 0x%02x", readarr[i]); -+ msg_pspew(" 0x%02x", readarr[i]); - } -- printf_debug("\n"); -+ msg_pspew("\n"); - return 0; - } - -@@ -179,7 +181,7 @@ int wbsio_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len) - int size = flash->total_size * 1024; - - if (size > 1024 * 1024) { -- fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); -+ msg_perr("%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); - return 1; - } - -@@ -191,7 +193,7 @@ int wbsio_spi_write_1(struct flashchip *flash, uint8_t *buf) - int size = flash->total_size * 1024; - - if (size > 1024 * 1024) { -- fprintf(stderr, "%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); -+ msg_perr("%s: Winbond saved on 4 register bits so max chip size is 1024 KB!\n", __func__); - return 1; - } - diff --git a/flashrom.spec b/flashrom.spec index e43692b..0c42db9 100644 --- a/flashrom.spec +++ b/flashrom.spec @@ -1,15 +1,15 @@ -%global svnrev 995 +%global svnrev 1001 Summary: Simple program for reading/writing BIOS chips content Name: flashrom -Version: 0.9.1 -Release: 4.svn%{svnrev}%{?dist} +Version: 0.9.2 +Release: 1%{?dist} License: GPLv2 Group: Applications/System URL: http://flashrom.org Source0: http://qa.coreboot.org/releases/%{name}-%{version}.tar.bz2 Source1: http://qa.coreboot.org/releases/%{name}-%{version}.tar.bz2.asc -Patch0: flashrom-r710-r%{svnrev}.diff +#Patch0: flashrom-r710-r%{svnrev}.diff BuildRequires: pciutils-devel BuildRequires: zlib-devel BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -23,7 +23,7 @@ and write new contents on the chips ("flash the chip"). %prep %setup -q -%patch0 -p1 +#%patch0 -p1 %build CFLAGS="%{optflags}" %{__make} %{?_smp_mflags} @@ -42,6 +42,15 @@ CFLAGS="%{optflags}" %{__make} %{?_smp_mflags} %{_mandir}/man8/%{name}.* %changelog +* Thu Jun 3 2010 Peter Lemenkov 0.9.2-1 +- Support for new external flashers +- Dozens of added flash chips, chipsets, mainboards +- Selective blockwise erase +- Improved user interface +- Reliability fixes +- Mainboard matching via DMI strings +- Laptop detection which triggers safety measures + * Wed Apr 28 2010 Peter Lemenkov 0.9.1-4.svn995 - Updated to latest svn ver. 995 - Lots of new chips and m/b diff --git a/import.log b/import.log index 4beeb1c..50f1b2c 100644 --- a/import.log +++ b/import.log @@ -9,3 +9,4 @@ flashrom-0_9_1-1_fc11:HEAD:flashrom-0.9.1-1.fc11.src.rpm:1252055642 flashrom-0_9_1-2_svn893_fc12:HEAD:flashrom-0.9.1-2.svn893.fc12.src.rpm:1265623249 flashrom-0_9_1-3_svn931_fc12:F-13:flashrom-0.9.1-3.svn931.fc12.src.rpm:1268395355 flashrom-0_9_1-4_svn995_fc12:F-13:flashrom-0.9.1-4.svn995.fc12.src.rpm:1272467989 +flashrom-0_9_2-1_fc12:F-13:flashrom-0.9.2-1.fc12.src.rpm:1275551255 diff --git a/sources b/sources index dd23769..8ad156e 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -2b7cc0e45a0ac4c6d43c0f7cd05b041a flashrom-0.9.1.tar.bz2 +21751b4ea93c5a82c725adae7b63014a flashrom-0.9.2.tar.bz2